radeon_dri2.c revision 0d16fef4
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 32de2362d3Smrg#include "radeon.h" 33de2362d3Smrg#include "radeon_dri2.h" 34de2362d3Smrg#include "radeon_video.h" 35de2362d3Smrg 36de2362d3Smrg#ifdef DRI2 37de2362d3Smrg 38de2362d3Smrg#include <sys/types.h> 39de2362d3Smrg#include <sys/stat.h> 40de2362d3Smrg#include <fcntl.h> 41de2362d3Smrg#include <errno.h> 42de2362d3Smrg 430d16fef4Smrg#include "radeon_bo_helper.h" 44de2362d3Smrg#include "radeon_version.h" 450d16fef4Smrg#include "radeon_list.h" 46de2362d3Smrg 47de2362d3Smrg#include "radeon_bo_gem.h" 48de2362d3Smrg 490d16fef4Smrg#include <xf86Priv.h> 50de2362d3Smrg 51de2362d3Smrg#if DRI2INFOREC_VERSION >= 9 52de2362d3Smrg#define USE_DRI2_PRIME 53de2362d3Smrg#endif 54de2362d3Smrg 55de2362d3Smrg#define FALLBACK_SWAP_DELAY 16 56de2362d3Smrg 570d16fef4Smrg#include "radeon_glamor.h" 58de2362d3Smrg 59de2362d3Smrgtypedef DRI2BufferPtr BufferPtr; 60de2362d3Smrg 61de2362d3Smrgstruct dri2_buffer_priv { 62de2362d3Smrg PixmapPtr pixmap; 63de2362d3Smrg unsigned int attachment; 64de2362d3Smrg unsigned int refcnt; 65de2362d3Smrg}; 66de2362d3Smrg 67de2362d3Smrg 680d16fef4Smrgstruct dri2_window_priv { 690d16fef4Smrg xf86CrtcPtr crtc; 700d16fef4Smrg int vblank_delta; 710d16fef4Smrg}; 720d16fef4Smrg 730d16fef4Smrgstatic DevPrivateKeyRec dri2_window_private_key_rec; 740d16fef4Smrg#define dri2_window_private_key (&dri2_window_private_key_rec) 750d16fef4Smrg 760d16fef4Smrg#define get_dri2_window_priv(window) \ 770d16fef4Smrg ((struct dri2_window_priv*) \ 780d16fef4Smrg dixLookupPrivate(&(window)->devPrivates, dri2_window_private_key)) 790d16fef4Smrg 800d16fef4Smrg 81de2362d3Smrgstatic PixmapPtr get_drawable_pixmap(DrawablePtr drawable) 82de2362d3Smrg{ 83de2362d3Smrg if (drawable->type == DRAWABLE_PIXMAP) 84de2362d3Smrg return (PixmapPtr)drawable; 85de2362d3Smrg else 86de2362d3Smrg return (*drawable->pScreen->GetWindowPixmap)((WindowPtr)drawable); 87de2362d3Smrg} 88de2362d3Smrg 89de2362d3Smrg 90de2362d3Smrgstatic PixmapPtr fixup_glamor(DrawablePtr drawable, PixmapPtr pixmap) 91de2362d3Smrg{ 92de2362d3Smrg PixmapPtr old = get_drawable_pixmap(drawable); 93de2362d3Smrg#ifdef USE_GLAMOR 94de2362d3Smrg ScreenPtr screen = drawable->pScreen; 95de2362d3Smrg struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); 96de2362d3Smrg GCPtr gc; 97de2362d3Smrg 98de2362d3Smrg /* With a glamor pixmap, 2D pixmaps are created in texture 99de2362d3Smrg * and without a static BO attached to it. To support DRI, 100de2362d3Smrg * we need to create a new textured-drm pixmap and 101de2362d3Smrg * need to copy the original content to this new textured-drm 102de2362d3Smrg * pixmap, and then convert the old pixmap to a coherent 103de2362d3Smrg * textured-drm pixmap which has a valid BO attached to it 104de2362d3Smrg * and also has a valid texture, thus both glamor and DRI2 105de2362d3Smrg * can access it. 106de2362d3Smrg * 107de2362d3Smrg */ 108de2362d3Smrg 109de2362d3Smrg /* Copy the current contents of the pixmap to the bo. */ 110de2362d3Smrg gc = GetScratchGC(drawable->depth, screen); 111de2362d3Smrg if (gc) { 112de2362d3Smrg ValidateGC(&pixmap->drawable, gc); 113de2362d3Smrg gc->ops->CopyArea(&old->drawable, &pixmap->drawable, 114de2362d3Smrg gc, 115de2362d3Smrg 0, 0, 116de2362d3Smrg old->drawable.width, 117de2362d3Smrg old->drawable.height, 118de2362d3Smrg 0, 0); 119de2362d3Smrg FreeScratchGC(gc); 120de2362d3Smrg } 121de2362d3Smrg 122de2362d3Smrg radeon_set_pixmap_private(pixmap, NULL); 123de2362d3Smrg 124de2362d3Smrg /* And redirect the pixmap to the new bo (for 3D). */ 125de2362d3Smrg glamor_egl_exchange_buffers(old, pixmap); 126de2362d3Smrg radeon_set_pixmap_private(old, priv); 127de2362d3Smrg old->refcnt++; 128de2362d3Smrg 129de2362d3Smrg screen->ModifyPixmapHeader(old, 130de2362d3Smrg old->drawable.width, 131de2362d3Smrg old->drawable.height, 132de2362d3Smrg 0, 0, 1330d16fef4Smrg pixmap->devKind, 134de2362d3Smrg NULL); 1350d16fef4Smrg old->devPrivate.ptr = NULL; 1360d16fef4Smrg 1370d16fef4Smrg screen->DestroyPixmap(pixmap); 138de2362d3Smrg 139de2362d3Smrg#endif /* USE_GLAMOR*/ 140de2362d3Smrg 141de2362d3Smrg return old; 142de2362d3Smrg} 143de2362d3Smrg 1440d16fef4Smrg/* Get GEM flink name for a pixmap */ 1450d16fef4Smrgstatic Bool 1460d16fef4Smrgradeon_get_flink_name(RADEONInfoPtr info, PixmapPtr pixmap, uint32_t *name) 1470d16fef4Smrg{ 1480d16fef4Smrg struct radeon_bo *bo = radeon_get_pixmap_bo(pixmap); 1490d16fef4Smrg struct drm_gem_flink flink; 1500d16fef4Smrg 1510d16fef4Smrg if (bo) 1520d16fef4Smrg return radeon_gem_get_kernel_name(bo, name) == 0; 1530d16fef4Smrg 1540d16fef4Smrg if (radeon_get_pixmap_handle(pixmap, &flink.handle)) { 1550d16fef4Smrg if (drmIoctl(info->dri2.drm_fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) 1560d16fef4Smrg return FALSE; 1570d16fef4Smrg 1580d16fef4Smrg *name = flink.name; 1590d16fef4Smrg return TRUE; 1600d16fef4Smrg } 1610d16fef4Smrg 1620d16fef4Smrg return FALSE; 1630d16fef4Smrg} 164de2362d3Smrg 165de2362d3Smrgstatic BufferPtr 166de2362d3Smrgradeon_dri2_create_buffer2(ScreenPtr pScreen, 167de2362d3Smrg DrawablePtr drawable, 168de2362d3Smrg unsigned int attachment, 169de2362d3Smrg unsigned int format) 170de2362d3Smrg{ 171de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 172de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 173de2362d3Smrg BufferPtr buffers; 174de2362d3Smrg struct dri2_buffer_priv *privates; 1750d16fef4Smrg PixmapPtr pixmap; 176de2362d3Smrg int flags; 177de2362d3Smrg unsigned front_width; 178de2362d3Smrg uint32_t tiling = 0; 179de2362d3Smrg unsigned aligned_width = drawable->width; 180de2362d3Smrg unsigned height = drawable->height; 181de2362d3Smrg Bool is_glamor_pixmap = FALSE; 182de2362d3Smrg int depth; 183de2362d3Smrg int cpp; 184de2362d3Smrg 185de2362d3Smrg if (format) { 186de2362d3Smrg depth = format; 187de2362d3Smrg 188de2362d3Smrg switch (depth) { 189de2362d3Smrg case 15: 190de2362d3Smrg cpp = 2; 191de2362d3Smrg break; 192de2362d3Smrg case 24: 193de2362d3Smrg cpp = 4; 194de2362d3Smrg break; 195de2362d3Smrg default: 196de2362d3Smrg cpp = depth / 8; 197de2362d3Smrg } 198de2362d3Smrg } else { 199de2362d3Smrg depth = drawable->depth; 200de2362d3Smrg cpp = drawable->bitsPerPixel / 8; 201de2362d3Smrg } 202de2362d3Smrg 2030d16fef4Smrg front_width = pScreen->GetScreenPixmap(pScreen)->drawable.width; 204de2362d3Smrg 2050d16fef4Smrg pixmap = NULL; 206de2362d3Smrg 207de2362d3Smrg if (attachment == DRI2BufferFrontLeft) { 2080d16fef4Smrg uint32_t handle; 2090d16fef4Smrg 210de2362d3Smrg pixmap = get_drawable_pixmap(drawable); 211de2362d3Smrg if (pScreen != pixmap->drawable.pScreen) 212de2362d3Smrg pixmap = NULL; 2130d16fef4Smrg else if (info->use_glamor && !radeon_get_pixmap_handle(pixmap, &handle)) { 214de2362d3Smrg is_glamor_pixmap = TRUE; 215de2362d3Smrg aligned_width = pixmap->drawable.width; 216de2362d3Smrg height = pixmap->drawable.height; 217de2362d3Smrg pixmap = NULL; 218de2362d3Smrg } else 219de2362d3Smrg pixmap->refcnt++; 220de2362d3Smrg } 221de2362d3Smrg 222de2362d3Smrg if (!pixmap && (is_glamor_pixmap || attachment != DRI2BufferFrontLeft)) { 223de2362d3Smrg /* tile the back buffer */ 224de2362d3Smrg switch(attachment) { 225de2362d3Smrg case DRI2BufferDepth: 226de2362d3Smrg /* macro is the preferred setting, but the 2D detiling for software 227de2362d3Smrg * fallbacks in mesa still has issues on some configurations 228de2362d3Smrg */ 229de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 230de2362d3Smrg if (info->allowColorTiling2D) { 231de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 232de2362d3Smrg } else { 233de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 234de2362d3Smrg } 235de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_CEDAR) 236de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_SZBUFFER; 237de2362d3Smrg } else if (cpp == 2 && info->ChipFamily >= CHIP_FAMILY_R300) 238de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE; 239de2362d3Smrg else 240de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 241de2362d3Smrg if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON) 242de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_DEPTH; 243de2362d3Smrg break; 244de2362d3Smrg case DRI2BufferDepthStencil: 245de2362d3Smrg /* macro is the preferred setting, but the 2D detiling for software 246de2362d3Smrg * fallbacks in mesa still has issues on some configurations 247de2362d3Smrg */ 248de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 249de2362d3Smrg if (info->allowColorTiling2D) { 250de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 251de2362d3Smrg } else { 252de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 253de2362d3Smrg } 254de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_CEDAR) 255de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_SZBUFFER; 256de2362d3Smrg } else if (cpp == 2 && info->ChipFamily >= CHIP_FAMILY_R300) 257de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE; 258de2362d3Smrg else 259de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 260de2362d3Smrg if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON) 261de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_DEPTH; 262de2362d3Smrg 263de2362d3Smrg break; 264de2362d3Smrg case DRI2BufferBackLeft: 265de2362d3Smrg case DRI2BufferBackRight: 266de2362d3Smrg case DRI2BufferFrontLeft: 267de2362d3Smrg case DRI2BufferFrontRight: 268de2362d3Smrg case DRI2BufferFakeFrontLeft: 269de2362d3Smrg case DRI2BufferFakeFrontRight: 270de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 271de2362d3Smrg if (info->allowColorTiling2D) { 272de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 273de2362d3Smrg } else { 274de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 275de2362d3Smrg } 276de2362d3Smrg } else 277de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 278de2362d3Smrg break; 279de2362d3Smrg default: 280de2362d3Smrg flags = 0; 281de2362d3Smrg } 282de2362d3Smrg 283de2362d3Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO) 284de2362d3Smrg tiling |= RADEON_TILING_MICRO; 285de2362d3Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE) 286de2362d3Smrg tiling |= RADEON_TILING_MICRO_SQUARE; 287de2362d3Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MACRO) 288de2362d3Smrg tiling |= RADEON_TILING_MACRO; 289de2362d3Smrg 290de2362d3Smrg if (aligned_width == front_width) 291de2362d3Smrg aligned_width = pScrn->virtualX; 292de2362d3Smrg 293de2362d3Smrg pixmap = (*pScreen->CreatePixmap)(pScreen, 294de2362d3Smrg aligned_width, 295de2362d3Smrg height, 296de2362d3Smrg depth, 297de2362d3Smrg flags | RADEON_CREATE_PIXMAP_DRI2); 298de2362d3Smrg } 299de2362d3Smrg 300de2362d3Smrg buffers = calloc(1, sizeof *buffers); 301de2362d3Smrg if (buffers == NULL) 302de2362d3Smrg goto error; 303de2362d3Smrg 304de2362d3Smrg if (pixmap) { 305de2362d3Smrg if (!info->use_glamor) { 306de2362d3Smrg info->exa_force_create = TRUE; 307de2362d3Smrg exaMoveInPixmap(pixmap); 308de2362d3Smrg info->exa_force_create = FALSE; 309de2362d3Smrg if (exaGetPixmapDriverPrivate(pixmap) == NULL) { 310de2362d3Smrg /* this happen if pixmap is non accelerable */ 311de2362d3Smrg goto error; 312de2362d3Smrg } 313de2362d3Smrg } 314de2362d3Smrg 315de2362d3Smrg if (is_glamor_pixmap) 316de2362d3Smrg pixmap = fixup_glamor(drawable, pixmap); 3170d16fef4Smrg if (!radeon_get_flink_name(info, pixmap, &buffers->name)) 318de2362d3Smrg goto error; 319de2362d3Smrg } 320de2362d3Smrg 321de2362d3Smrg privates = calloc(1, sizeof(struct dri2_buffer_priv)); 322de2362d3Smrg if (privates == NULL) 323de2362d3Smrg goto error; 324de2362d3Smrg 325de2362d3Smrg buffers->attachment = attachment; 326de2362d3Smrg if (pixmap) { 327de2362d3Smrg buffers->pitch = pixmap->devKind; 328de2362d3Smrg buffers->cpp = cpp; 329de2362d3Smrg } 330de2362d3Smrg buffers->driverPrivate = privates; 331de2362d3Smrg buffers->format = format; 332de2362d3Smrg buffers->flags = 0; /* not tiled */ 333de2362d3Smrg privates->pixmap = pixmap; 334de2362d3Smrg privates->attachment = attachment; 335de2362d3Smrg privates->refcnt = 1; 336de2362d3Smrg 337de2362d3Smrg return buffers; 338de2362d3Smrg 339de2362d3Smrgerror: 340de2362d3Smrg free(buffers); 341de2362d3Smrg if (pixmap) 342de2362d3Smrg (*pScreen->DestroyPixmap)(pixmap); 343de2362d3Smrg return NULL; 344de2362d3Smrg} 345de2362d3Smrg 346de2362d3SmrgDRI2BufferPtr 347de2362d3Smrgradeon_dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, 348de2362d3Smrg unsigned int format) 349de2362d3Smrg{ 350de2362d3Smrg return radeon_dri2_create_buffer2(pDraw->pScreen, pDraw, 351de2362d3Smrg attachment, format); 352de2362d3Smrg} 353de2362d3Smrg 354de2362d3Smrgstatic void 355de2362d3Smrgradeon_dri2_destroy_buffer2(ScreenPtr pScreen, 356de2362d3Smrg DrawablePtr drawable, BufferPtr buffers) 357de2362d3Smrg{ 358de2362d3Smrg if(buffers) 359de2362d3Smrg { 360de2362d3Smrg struct dri2_buffer_priv *private = buffers->driverPrivate; 361de2362d3Smrg 362de2362d3Smrg /* Trying to free an already freed buffer is unlikely to end well */ 363de2362d3Smrg if (private->refcnt == 0) { 364de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 365de2362d3Smrg 366de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 367de2362d3Smrg "Attempted to destroy previously destroyed buffer.\ 368de2362d3Smrg This is a programming error\n"); 369de2362d3Smrg return; 370de2362d3Smrg } 371de2362d3Smrg 372de2362d3Smrg private->refcnt--; 373de2362d3Smrg if (private->refcnt == 0) 374de2362d3Smrg { 375de2362d3Smrg if (private->pixmap) 376de2362d3Smrg (*pScreen->DestroyPixmap)(private->pixmap); 377de2362d3Smrg 378de2362d3Smrg free(buffers->driverPrivate); 379de2362d3Smrg free(buffers); 380de2362d3Smrg } 381de2362d3Smrg } 382de2362d3Smrg} 383de2362d3Smrg 384de2362d3Smrgvoid 385de2362d3Smrgradeon_dri2_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buf) 386de2362d3Smrg{ 387de2362d3Smrg radeon_dri2_destroy_buffer2(pDraw->pScreen, pDraw, buf); 388de2362d3Smrg} 389de2362d3Smrg 390de2362d3Smrg 391de2362d3Smrgstatic inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable) 392de2362d3Smrg{ 393de2362d3Smrg if (drawable->type == DRAWABLE_PIXMAP) 394de2362d3Smrg return (PixmapPtr)drawable; 395de2362d3Smrg else { 396de2362d3Smrg struct _Window *pWin = (struct _Window *)drawable; 397de2362d3Smrg return drawable->pScreen->GetWindowPixmap(pWin); 398de2362d3Smrg } 399de2362d3Smrg} 400de2362d3Smrgstatic void 401de2362d3Smrgradeon_dri2_copy_region2(ScreenPtr pScreen, 402de2362d3Smrg DrawablePtr drawable, 403de2362d3Smrg RegionPtr region, 404de2362d3Smrg BufferPtr dest_buffer, 405de2362d3Smrg BufferPtr src_buffer) 406de2362d3Smrg{ 407de2362d3Smrg struct dri2_buffer_priv *src_private = src_buffer->driverPrivate; 408de2362d3Smrg struct dri2_buffer_priv *dst_private = dest_buffer->driverPrivate; 409de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 410de2362d3Smrg DrawablePtr src_drawable; 411de2362d3Smrg DrawablePtr dst_drawable; 412de2362d3Smrg RegionPtr copy_clip; 413de2362d3Smrg GCPtr gc; 414de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 415de2362d3Smrg Bool vsync; 416de2362d3Smrg Bool translate = FALSE; 417de2362d3Smrg int off_x = 0, off_y = 0; 418de2362d3Smrg PixmapPtr dst_ppix; 419de2362d3Smrg 420de2362d3Smrg dst_ppix = dst_private->pixmap; 421de2362d3Smrg src_drawable = &src_private->pixmap->drawable; 422de2362d3Smrg dst_drawable = &dst_private->pixmap->drawable; 423de2362d3Smrg 424de2362d3Smrg if (src_private->attachment == DRI2BufferFrontLeft) { 425de2362d3Smrg#ifdef USE_DRI2_PRIME 426de2362d3Smrg if (drawable->pScreen != pScreen) { 427de2362d3Smrg src_drawable = DRI2UpdatePrime(drawable, src_buffer); 428de2362d3Smrg if (!src_drawable) 429de2362d3Smrg return; 430de2362d3Smrg } else 431de2362d3Smrg#endif 432de2362d3Smrg src_drawable = drawable; 433de2362d3Smrg } 434de2362d3Smrg if (dst_private->attachment == DRI2BufferFrontLeft) { 435de2362d3Smrg#ifdef USE_DRI2_PRIME 436de2362d3Smrg if (drawable->pScreen != pScreen) { 437de2362d3Smrg dst_drawable = DRI2UpdatePrime(drawable, dest_buffer); 438de2362d3Smrg if (!dst_drawable) 439de2362d3Smrg return; 440de2362d3Smrg dst_ppix = (PixmapPtr)dst_drawable; 441de2362d3Smrg if (dst_drawable != drawable) 442de2362d3Smrg translate = TRUE; 443de2362d3Smrg } else 444de2362d3Smrg#endif 445de2362d3Smrg dst_drawable = drawable; 446de2362d3Smrg } 447de2362d3Smrg 448de2362d3Smrg if (translate && drawable->type == DRAWABLE_WINDOW) { 449de2362d3Smrg PixmapPtr pPix = GetDrawablePixmap(drawable); 450de2362d3Smrg 451de2362d3Smrg off_x = drawable->x - pPix->screen_x; 452de2362d3Smrg off_y = drawable->y - pPix->screen_y; 453de2362d3Smrg } 454de2362d3Smrg gc = GetScratchGC(dst_drawable->depth, pScreen); 455de2362d3Smrg copy_clip = REGION_CREATE(pScreen, NULL, 0); 456de2362d3Smrg REGION_COPY(pScreen, copy_clip, region); 457de2362d3Smrg 458de2362d3Smrg if (translate) { 459de2362d3Smrg REGION_TRANSLATE(pScreen, copy_clip, off_x, off_y); 460de2362d3Smrg } 461de2362d3Smrg 462de2362d3Smrg (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0); 463de2362d3Smrg ValidateGC(dst_drawable, gc); 464de2362d3Smrg 465de2362d3Smrg /* If this is a full buffer swap or frontbuffer flush, throttle on the 466de2362d3Smrg * previous one 467de2362d3Smrg */ 468de2362d3Smrg if (dst_private->attachment == DRI2BufferFrontLeft) { 469de2362d3Smrg if (REGION_NUM_RECTS(region) == 1) { 470de2362d3Smrg BoxPtr extents = REGION_EXTENTS(pScreen, region); 471de2362d3Smrg 472de2362d3Smrg if (extents->x1 == 0 && extents->y1 == 0 && 473de2362d3Smrg extents->x2 == drawable->width && 474de2362d3Smrg extents->y2 == drawable->height) { 475de2362d3Smrg struct radeon_bo *bo = radeon_get_pixmap_bo(dst_ppix); 476de2362d3Smrg 477de2362d3Smrg if (bo) 478de2362d3Smrg radeon_bo_wait(bo); 479de2362d3Smrg } 480de2362d3Smrg } 481de2362d3Smrg } 482de2362d3Smrg 483de2362d3Smrg vsync = info->accel_state->vsync; 484de2362d3Smrg 485de2362d3Smrg /* Driver option "SwapbuffersWait" defines if we vsync DRI2 copy-swaps. */ 486de2362d3Smrg info->accel_state->vsync = info->swapBuffersWait; 487de2362d3Smrg info->accel_state->force = TRUE; 488de2362d3Smrg 489de2362d3Smrg (*gc->ops->CopyArea)(src_drawable, dst_drawable, gc, 490de2362d3Smrg 0, 0, drawable->width, drawable->height, off_x, off_y); 491de2362d3Smrg 492de2362d3Smrg info->accel_state->force = FALSE; 493de2362d3Smrg info->accel_state->vsync = vsync; 494de2362d3Smrg 495de2362d3Smrg FreeScratchGC(gc); 496de2362d3Smrg} 497de2362d3Smrg 498de2362d3Smrgvoid 499de2362d3Smrgradeon_dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion, 500de2362d3Smrg DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer) 501de2362d3Smrg{ 502de2362d3Smrg return radeon_dri2_copy_region2(pDraw->pScreen, pDraw, pRegion, 503de2362d3Smrg pDstBuffer, pSrcBuffer); 504de2362d3Smrg} 505de2362d3Smrg 506de2362d3Smrgenum DRI2FrameEventType { 507de2362d3Smrg DRI2_SWAP, 508de2362d3Smrg DRI2_FLIP, 509de2362d3Smrg DRI2_WAITMSC, 510de2362d3Smrg}; 511de2362d3Smrg 512de2362d3Smrgtypedef struct _DRI2FrameEvent { 513de2362d3Smrg XID drawable_id; 514de2362d3Smrg ClientPtr client; 515de2362d3Smrg enum DRI2FrameEventType type; 5160d16fef4Smrg unsigned frame; 517de2362d3Smrg xf86CrtcPtr crtc; 5180d16fef4Smrg OsTimerPtr timer; 5190d16fef4Smrg uintptr_t drm_queue_seq; 520de2362d3Smrg 521de2362d3Smrg /* for swaps & flips only */ 522de2362d3Smrg DRI2SwapEventPtr event_complete; 523de2362d3Smrg void *event_data; 524de2362d3Smrg DRI2BufferPtr front; 525de2362d3Smrg DRI2BufferPtr back; 526de2362d3Smrg} DRI2FrameEventRec, *DRI2FrameEventPtr; 527de2362d3Smrg 528de2362d3Smrgstatic int DRI2InfoCnt; 529de2362d3Smrg 530de2362d3Smrgstatic void 531de2362d3Smrgradeon_dri2_ref_buffer(BufferPtr buffer) 532de2362d3Smrg{ 533de2362d3Smrg struct dri2_buffer_priv *private = buffer->driverPrivate; 534de2362d3Smrg private->refcnt++; 535de2362d3Smrg} 536de2362d3Smrg 537de2362d3Smrgstatic void 538de2362d3Smrgradeon_dri2_unref_buffer(BufferPtr buffer) 539de2362d3Smrg{ 540de2362d3Smrg if (buffer) { 541de2362d3Smrg struct dri2_buffer_priv *private = buffer->driverPrivate; 542de2362d3Smrg radeon_dri2_destroy_buffer(&(private->pixmap->drawable), buffer); 543de2362d3Smrg } 544de2362d3Smrg} 545de2362d3Smrg 546de2362d3Smrgstatic void 547de2362d3Smrgradeon_dri2_client_state_changed(CallbackListPtr *ClientStateCallback, pointer data, pointer calldata) 548de2362d3Smrg{ 549de2362d3Smrg NewClientInfoRec *clientinfo = calldata; 550de2362d3Smrg ClientPtr pClient = clientinfo->client; 551de2362d3Smrg 552de2362d3Smrg switch (pClient->clientState) { 553de2362d3Smrg case ClientStateRetained: 554de2362d3Smrg case ClientStateGone: 5550d16fef4Smrg radeon_drm_abort_client(pClient); 556de2362d3Smrg break; 557de2362d3Smrg default: 558de2362d3Smrg break; 559de2362d3Smrg } 560de2362d3Smrg} 561de2362d3Smrg 5620d16fef4Smrg/* 5630d16fef4Smrg * Get current frame count delta for the specified drawable and CRTC 5640d16fef4Smrg */ 5650d16fef4Smrgstatic uint32_t radeon_get_msc_delta(DrawablePtr pDraw, xf86CrtcPtr crtc) 5660d16fef4Smrg{ 5670d16fef4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 5680d16fef4Smrg 5690d16fef4Smrg if (pDraw && pDraw->type == DRAWABLE_WINDOW) 5700d16fef4Smrg return drmmode_crtc->interpolated_vblanks + 5710d16fef4Smrg get_dri2_window_priv((WindowPtr)pDraw)->vblank_delta; 5720d16fef4Smrg 5730d16fef4Smrg return drmmode_crtc->interpolated_vblanks; 5740d16fef4Smrg} 5750d16fef4Smrg 5760d16fef4Smrg/* 5770d16fef4Smrg * Get current frame count and timestamp of the specified CRTC 5780d16fef4Smrg */ 5790d16fef4Smrgstatic Bool radeon_dri2_get_crtc_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 5800d16fef4Smrg{ 5810d16fef4Smrg if (!radeon_crtc_is_enabled(crtc) || 5820d16fef4Smrg drmmode_crtc_get_ust_msc(crtc, ust, msc) != Success) { 5830d16fef4Smrg /* CRTC is not running, extrapolate MSC and timestamp */ 5840d16fef4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 5850d16fef4Smrg ScrnInfoPtr scrn = crtc->scrn; 5860d16fef4Smrg RADEONInfoPtr info = RADEONPTR(scrn); 5870d16fef4Smrg CARD64 now, delta_t, delta_seq; 5880d16fef4Smrg 5890d16fef4Smrg if (!drmmode_crtc->dpms_last_ust) 5900d16fef4Smrg return FALSE; 5910d16fef4Smrg 5920d16fef4Smrg if (drmmode_get_current_ust(info->dri2.drm_fd, &now) != 0) { 5930d16fef4Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 5940d16fef4Smrg "%s cannot get current time\n", __func__); 5950d16fef4Smrg return FALSE; 5960d16fef4Smrg } 5970d16fef4Smrg 5980d16fef4Smrg delta_t = now - drmmode_crtc->dpms_last_ust; 5990d16fef4Smrg delta_seq = delta_t * drmmode_crtc->dpms_last_fps; 6000d16fef4Smrg delta_seq /= 1000000; 6010d16fef4Smrg *ust = drmmode_crtc->dpms_last_ust; 6020d16fef4Smrg delta_t = delta_seq * 1000000; 6030d16fef4Smrg delta_t /= drmmode_crtc->dpms_last_fps; 6040d16fef4Smrg *ust += delta_t; 6050d16fef4Smrg *msc = drmmode_crtc->dpms_last_seq; 6060d16fef4Smrg *msc += delta_seq; 6070d16fef4Smrg } 6080d16fef4Smrg 6090d16fef4Smrg return TRUE; 6100d16fef4Smrg} 6110d16fef4Smrg 612de2362d3Smrgstatic 613de2362d3Smrgxf86CrtcPtr radeon_dri2_drawable_crtc(DrawablePtr pDraw, Bool consider_disabled) 614de2362d3Smrg{ 615de2362d3Smrg ScreenPtr pScreen = pDraw->pScreen; 616de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 6170d16fef4Smrg xf86CrtcPtr crtc = radeon_pick_best_crtc(pScrn, consider_disabled, 6180d16fef4Smrg pDraw->x, pDraw->x + pDraw->width, 6190d16fef4Smrg pDraw->y, pDraw->y + pDraw->height); 620de2362d3Smrg 6210d16fef4Smrg if (crtc && pDraw->type == DRAWABLE_WINDOW) { 6220d16fef4Smrg struct dri2_window_priv *priv = get_dri2_window_priv((WindowPtr)pDraw); 623de2362d3Smrg 6240d16fef4Smrg if (priv->crtc && priv->crtc != crtc) { 6250d16fef4Smrg CARD64 ust, mscold, mscnew; 6260d16fef4Smrg 6270d16fef4Smrg if (radeon_dri2_get_crtc_msc(priv->crtc, &ust, &mscold) && 6280d16fef4Smrg radeon_dri2_get_crtc_msc(crtc, &ust, &mscnew)) 6290d16fef4Smrg priv->vblank_delta += mscold - mscnew; 6300d16fef4Smrg } 6310d16fef4Smrg 6320d16fef4Smrg priv->crtc = crtc; 6330d16fef4Smrg } 6340d16fef4Smrg 6350d16fef4Smrg return crtc; 6360d16fef4Smrg} 6370d16fef4Smrg 6380d16fef4Smrgstatic void 6390d16fef4Smrgradeon_dri2_flip_event_abort(xf86CrtcPtr crtc, void *event_data) 6400d16fef4Smrg{ 6410d16fef4Smrg RADEONInfoPtr info = RADEONPTR(crtc->scrn); 6420d16fef4Smrg 6430d16fef4Smrg info->drmmode.dri2_flipping = FALSE; 6440d16fef4Smrg free(event_data); 6450d16fef4Smrg} 6460d16fef4Smrg 6470d16fef4Smrgstatic void 6480d16fef4Smrgradeon_dri2_flip_event_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, 6490d16fef4Smrg void *event_data) 6500d16fef4Smrg{ 6510d16fef4Smrg DRI2FrameEventPtr flip = event_data; 6520d16fef4Smrg ScrnInfoPtr scrn = crtc->scrn; 6530d16fef4Smrg unsigned tv_sec, tv_usec; 6540d16fef4Smrg DrawablePtr drawable; 6550d16fef4Smrg ScreenPtr screen; 6560d16fef4Smrg int status; 6570d16fef4Smrg PixmapPtr pixmap; 6580d16fef4Smrg 6590d16fef4Smrg status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient, 6600d16fef4Smrg M_ANY, DixWriteAccess); 6610d16fef4Smrg if (status != Success) 6620d16fef4Smrg goto abort; 6630d16fef4Smrg 6640d16fef4Smrg frame += radeon_get_msc_delta(drawable, crtc); 6650d16fef4Smrg 6660d16fef4Smrg screen = scrn->pScreen; 6670d16fef4Smrg pixmap = screen->GetScreenPixmap(screen); 6680d16fef4Smrg xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 6690d16fef4Smrg "%s:%d fevent[%p] width %d pitch %d (/4 %d)\n", 6700d16fef4Smrg __func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4); 6710d16fef4Smrg 6720d16fef4Smrg tv_sec = usec / 1000000; 6730d16fef4Smrg tv_usec = usec % 1000000; 6740d16fef4Smrg 6750d16fef4Smrg /* We assume our flips arrive in order, so we don't check the frame */ 6760d16fef4Smrg switch (flip->type) { 6770d16fef4Smrg case DRI2_SWAP: 6780d16fef4Smrg /* Check for too small vblank count of pageflip completion, taking wraparound 6790d16fef4Smrg * into account. This usually means some defective kms pageflip completion, 6800d16fef4Smrg * causing wrong (msc, ust) return values and possible visual corruption. 6810d16fef4Smrg */ 6820d16fef4Smrg if ((frame < flip->frame) && (flip->frame - frame < 5)) { 6830d16fef4Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 6840d16fef4Smrg "%s: Pageflip completion event has impossible msc %u < target_msc %u\n", 6850d16fef4Smrg __func__, frame, flip->frame); 6860d16fef4Smrg /* All-Zero values signal failure of (msc, ust) timestamping to client. */ 6870d16fef4Smrg frame = tv_sec = tv_usec = 0; 6880d16fef4Smrg } 6890d16fef4Smrg 6900d16fef4Smrg DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec, 6910d16fef4Smrg DRI2_FLIP_COMPLETE, flip->event_complete, 6920d16fef4Smrg flip->event_data); 6930d16fef4Smrg break; 6940d16fef4Smrg default: 6950d16fef4Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__); 6960d16fef4Smrg /* Unknown type */ 6970d16fef4Smrg break; 6980d16fef4Smrg } 6990d16fef4Smrg 7000d16fef4Smrgabort: 7010d16fef4Smrg radeon_dri2_flip_event_abort(crtc, event_data); 702de2362d3Smrg} 703de2362d3Smrg 704de2362d3Smrgstatic Bool 7050d16fef4Smrgradeon_dri2_schedule_flip(xf86CrtcPtr crtc, ClientPtr client, 706de2362d3Smrg DrawablePtr draw, DRI2BufferPtr front, 707de2362d3Smrg DRI2BufferPtr back, DRI2SwapEventPtr func, 708de2362d3Smrg void *data, unsigned int target_msc) 709de2362d3Smrg{ 7100d16fef4Smrg ScrnInfoPtr scrn = crtc->scrn; 7110d16fef4Smrg RADEONInfoPtr info = RADEONPTR(scrn); 712de2362d3Smrg struct dri2_buffer_priv *back_priv; 713de2362d3Smrg struct radeon_bo *bo; 714de2362d3Smrg DRI2FrameEventPtr flip_info; 7150d16fef4Smrg int ref_crtc_hw_id = drmmode_get_crtc_id(crtc); 716de2362d3Smrg 717de2362d3Smrg flip_info = calloc(1, sizeof(DRI2FrameEventRec)); 718de2362d3Smrg if (!flip_info) 719de2362d3Smrg return FALSE; 720de2362d3Smrg 721de2362d3Smrg flip_info->drawable_id = draw->id; 722de2362d3Smrg flip_info->client = client; 723de2362d3Smrg flip_info->type = DRI2_SWAP; 724de2362d3Smrg flip_info->event_complete = func; 725de2362d3Smrg flip_info->event_data = data; 726de2362d3Smrg flip_info->frame = target_msc; 727de2362d3Smrg flip_info->crtc = crtc; 728de2362d3Smrg 729de2362d3Smrg xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 730de2362d3Smrg "%s:%d fevent[%p]\n", __func__, __LINE__, flip_info); 731de2362d3Smrg 732de2362d3Smrg /* Page flip the full screen buffer */ 733de2362d3Smrg back_priv = back->driverPrivate; 734de2362d3Smrg bo = radeon_get_pixmap_bo(back_priv->pixmap); 735de2362d3Smrg 7360d16fef4Smrg if (radeon_do_pageflip(scrn, client, bo->handle, 7370d16fef4Smrg RADEON_DRM_QUEUE_ID_DEFAULT, flip_info, 7380d16fef4Smrg ref_crtc_hw_id, 7390d16fef4Smrg radeon_dri2_flip_event_handler, 7400d16fef4Smrg radeon_dri2_flip_event_abort)) { 7410d16fef4Smrg info->drmmode.dri2_flipping = TRUE; 7420d16fef4Smrg return TRUE; 7430d16fef4Smrg } 7440d16fef4Smrg 7450d16fef4Smrg return FALSE; 746de2362d3Smrg} 747de2362d3Smrg 748de2362d3Smrgstatic Bool 749de2362d3Smrgupdate_front(DrawablePtr draw, DRI2BufferPtr front) 750de2362d3Smrg{ 751de2362d3Smrg PixmapPtr pixmap; 752de2362d3Smrg RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(draw->pScreen)); 753de2362d3Smrg struct dri2_buffer_priv *priv = front->driverPrivate; 754de2362d3Smrg 755de2362d3Smrg pixmap = get_drawable_pixmap(draw); 756de2362d3Smrg pixmap->refcnt++; 757de2362d3Smrg 758de2362d3Smrg if (!info->use_glamor) 759de2362d3Smrg exaMoveInPixmap(pixmap); 7600d16fef4Smrg if (!radeon_get_flink_name(info, pixmap, &front->name)) { 761de2362d3Smrg (*draw->pScreen->DestroyPixmap)(pixmap); 762de2362d3Smrg return FALSE; 763de2362d3Smrg } 764de2362d3Smrg (*draw->pScreen->DestroyPixmap)(priv->pixmap); 765de2362d3Smrg front->pitch = pixmap->devKind; 766de2362d3Smrg front->cpp = pixmap->drawable.bitsPerPixel / 8; 767de2362d3Smrg priv->pixmap = pixmap; 768de2362d3Smrg 769de2362d3Smrg return TRUE; 770de2362d3Smrg} 771de2362d3Smrg 772de2362d3Smrgstatic Bool 773de2362d3Smrgcan_exchange(ScrnInfoPtr pScrn, DrawablePtr draw, 774de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back) 775de2362d3Smrg{ 776de2362d3Smrg struct dri2_buffer_priv *front_priv = front->driverPrivate; 777de2362d3Smrg struct dri2_buffer_priv *back_priv = back->driverPrivate; 778de2362d3Smrg PixmapPtr front_pixmap; 779de2362d3Smrg PixmapPtr back_pixmap = back_priv->pixmap; 780de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 781de2362d3Smrg int i; 782de2362d3Smrg 783de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 784de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 785de2362d3Smrg if (crtc->enabled && crtc->rotatedData) 786de2362d3Smrg return FALSE; 787de2362d3Smrg } 788de2362d3Smrg 789de2362d3Smrg if (!update_front(draw, front)) 790de2362d3Smrg return FALSE; 791de2362d3Smrg 792de2362d3Smrg front_pixmap = front_priv->pixmap; 793de2362d3Smrg 794de2362d3Smrg if (front_pixmap->drawable.width != back_pixmap->drawable.width) 795de2362d3Smrg return FALSE; 796de2362d3Smrg 797de2362d3Smrg if (front_pixmap->drawable.height != back_pixmap->drawable.height) 798de2362d3Smrg return FALSE; 799de2362d3Smrg 800de2362d3Smrg if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) 801de2362d3Smrg return FALSE; 802de2362d3Smrg 803de2362d3Smrg if (front_pixmap->devKind != back_pixmap->devKind) 804de2362d3Smrg return FALSE; 805de2362d3Smrg 806de2362d3Smrg return TRUE; 807de2362d3Smrg} 808de2362d3Smrg 809de2362d3Smrgstatic Bool 810de2362d3Smrgcan_flip(ScrnInfoPtr pScrn, DrawablePtr draw, 811de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back) 812de2362d3Smrg{ 8130d16fef4Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 8140d16fef4Smrg 815de2362d3Smrg return draw->type == DRAWABLE_WINDOW && 8160d16fef4Smrg info->allowPageFlip && 8170d16fef4Smrg !info->hwcursor_disabled && 8180d16fef4Smrg !info->drmmode.present_flipping && 819de2362d3Smrg pScrn->vtSema && 820de2362d3Smrg DRI2CanFlip(draw) && 821de2362d3Smrg can_exchange(pScrn, draw, front, back); 822de2362d3Smrg} 823de2362d3Smrg 824de2362d3Smrgstatic void 825de2362d3Smrgradeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back) 826de2362d3Smrg{ 827de2362d3Smrg struct dri2_buffer_priv *front_priv = front->driverPrivate; 828de2362d3Smrg struct dri2_buffer_priv *back_priv = back->driverPrivate; 829de2362d3Smrg struct radeon_bo *front_bo, *back_bo; 830de2362d3Smrg ScreenPtr screen; 831de2362d3Smrg RADEONInfoPtr info; 832de2362d3Smrg RegionRec region; 833de2362d3Smrg int tmp; 834de2362d3Smrg 835de2362d3Smrg region.extents.x1 = region.extents.y1 = 0; 836de2362d3Smrg region.extents.x2 = front_priv->pixmap->drawable.width; 837de2362d3Smrg region.extents.y2 = front_priv->pixmap->drawable.width; 838de2362d3Smrg region.data = NULL; 839de2362d3Smrg DamageRegionAppend(&front_priv->pixmap->drawable, ®ion); 840de2362d3Smrg 841de2362d3Smrg /* Swap BO names so DRI works */ 842de2362d3Smrg tmp = front->name; 843de2362d3Smrg front->name = back->name; 844de2362d3Smrg back->name = tmp; 845de2362d3Smrg 846de2362d3Smrg /* Swap pixmap bos */ 847de2362d3Smrg front_bo = radeon_get_pixmap_bo(front_priv->pixmap); 848de2362d3Smrg back_bo = radeon_get_pixmap_bo(back_priv->pixmap); 849de2362d3Smrg radeon_set_pixmap_bo(front_priv->pixmap, back_bo); 850de2362d3Smrg radeon_set_pixmap_bo(back_priv->pixmap, front_bo); 851de2362d3Smrg 852de2362d3Smrg /* Do we need to update the Screen? */ 853de2362d3Smrg screen = draw->pScreen; 854de2362d3Smrg info = RADEONPTR(xf86ScreenToScrn(screen)); 855de2362d3Smrg if (front_bo == info->front_bo) { 856de2362d3Smrg radeon_bo_ref(back_bo); 857de2362d3Smrg radeon_bo_unref(info->front_bo); 858de2362d3Smrg info->front_bo = back_bo; 859de2362d3Smrg radeon_set_pixmap_bo(screen->GetScreenPixmap(screen), back_bo); 860de2362d3Smrg } 861de2362d3Smrg 862de2362d3Smrg radeon_glamor_exchange_buffers(front_priv->pixmap, back_priv->pixmap); 863de2362d3Smrg 864de2362d3Smrg DamageRegionProcessPending(&front_priv->pixmap->drawable); 865de2362d3Smrg} 866de2362d3Smrg 8670d16fef4Smrgstatic void radeon_dri2_frame_event_abort(xf86CrtcPtr crtc, void *event_data) 868de2362d3Smrg{ 869de2362d3Smrg DRI2FrameEventPtr event = event_data; 8700d16fef4Smrg 8710d16fef4Smrg TimerCancel(event->timer); 8720d16fef4Smrg TimerFree(event->timer); 8730d16fef4Smrg radeon_dri2_unref_buffer(event->front); 8740d16fef4Smrg radeon_dri2_unref_buffer(event->back); 8750d16fef4Smrg free(event); 8760d16fef4Smrg} 8770d16fef4Smrg 8780d16fef4Smrgstatic void radeon_dri2_frame_event_handler(xf86CrtcPtr crtc, uint32_t seq, 8790d16fef4Smrg uint64_t usec, void *event_data) 8800d16fef4Smrg{ 8810d16fef4Smrg DRI2FrameEventPtr event = event_data; 8820d16fef4Smrg ScrnInfoPtr scrn = crtc->scrn; 883de2362d3Smrg DrawablePtr drawable; 884de2362d3Smrg int status; 885de2362d3Smrg int swap_type; 886de2362d3Smrg BoxRec box; 887de2362d3Smrg RegionRec region; 888de2362d3Smrg 889de2362d3Smrg status = dixLookupDrawable(&drawable, event->drawable_id, serverClient, 890de2362d3Smrg M_ANY, DixWriteAccess); 891de2362d3Smrg if (status != Success) 892de2362d3Smrg goto cleanup; 893de2362d3Smrg 8940d16fef4Smrg seq += radeon_get_msc_delta(drawable, crtc); 895de2362d3Smrg 896de2362d3Smrg switch (event->type) { 897de2362d3Smrg case DRI2_FLIP: 898de2362d3Smrg if (can_flip(scrn, drawable, event->front, event->back) && 8990d16fef4Smrg radeon_dri2_schedule_flip(crtc, 900de2362d3Smrg event->client, 901de2362d3Smrg drawable, 902de2362d3Smrg event->front, 903de2362d3Smrg event->back, 904de2362d3Smrg event->event_complete, 905de2362d3Smrg event->event_data, 906de2362d3Smrg event->frame)) { 907de2362d3Smrg radeon_dri2_exchange_buffers(drawable, event->front, event->back); 908de2362d3Smrg break; 909de2362d3Smrg } 910de2362d3Smrg /* else fall through to exchange/blit */ 911de2362d3Smrg case DRI2_SWAP: 912de2362d3Smrg if (DRI2CanExchange(drawable) && 913de2362d3Smrg can_exchange(scrn, drawable, event->front, event->back)) { 914de2362d3Smrg radeon_dri2_exchange_buffers(drawable, event->front, event->back); 915de2362d3Smrg swap_type = DRI2_EXCHANGE_COMPLETE; 916de2362d3Smrg } else { 917de2362d3Smrg box.x1 = 0; 918de2362d3Smrg box.y1 = 0; 919de2362d3Smrg box.x2 = drawable->width; 920de2362d3Smrg box.y2 = drawable->height; 921de2362d3Smrg REGION_INIT(pScreen, ®ion, &box, 0); 922de2362d3Smrg radeon_dri2_copy_region(drawable, ®ion, event->front, event->back); 923de2362d3Smrg swap_type = DRI2_BLIT_COMPLETE; 924de2362d3Smrg } 925de2362d3Smrg 9260d16fef4Smrg DRI2SwapComplete(event->client, drawable, seq, usec / 1000000, 9270d16fef4Smrg usec % 1000000, swap_type, event->event_complete, 9280d16fef4Smrg event->event_data); 929de2362d3Smrg 930de2362d3Smrg break; 931de2362d3Smrg case DRI2_WAITMSC: 9320d16fef4Smrg DRI2WaitMSCComplete(event->client, drawable, seq, usec / 1000000, 9330d16fef4Smrg usec % 1000000); 934de2362d3Smrg break; 935de2362d3Smrg default: 936de2362d3Smrg /* Unknown type */ 937de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 938de2362d3Smrg "%s: unknown vblank event received\n", __func__); 939de2362d3Smrg break; 940de2362d3Smrg } 941de2362d3Smrg 942de2362d3Smrgcleanup: 9430d16fef4Smrg radeon_dri2_frame_event_abort(crtc, event_data); 944de2362d3Smrg} 945de2362d3Smrg 946de2362d3SmrgdrmVBlankSeqType radeon_populate_vbl_request_type(xf86CrtcPtr crtc) 947de2362d3Smrg{ 948de2362d3Smrg drmVBlankSeqType type = 0; 949de2362d3Smrg int crtc_id = drmmode_get_crtc_id(crtc); 950de2362d3Smrg 951de2362d3Smrg if (crtc_id == 1) 952de2362d3Smrg type |= DRM_VBLANK_SECONDARY; 953de2362d3Smrg else if (crtc_id > 1) 954de2362d3Smrg#ifdef DRM_VBLANK_HIGH_CRTC_SHIFT 955de2362d3Smrg type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) & 956de2362d3Smrg DRM_VBLANK_HIGH_CRTC_MASK; 957de2362d3Smrg#else 958de2362d3Smrg ErrorF("radeon driver bug: %s called for CRTC %d > 1, but " 959de2362d3Smrg "DRM_VBLANK_HIGH_CRTC_MASK not defined at build time\n", 960de2362d3Smrg __func__, crtc_id); 961de2362d3Smrg#endif 962de2362d3Smrg 963de2362d3Smrg return type; 964de2362d3Smrg} 965de2362d3Smrg 966de2362d3Smrg/* 967de2362d3Smrg * This function should be called on a disabled CRTC only (i.e., CRTC 968de2362d3Smrg * in DPMS-off state). It will calculate the delay necessary to reach 969de2362d3Smrg * target_msc from present time if the CRTC were running. 970de2362d3Smrg */ 971de2362d3Smrgstatic 972de2362d3SmrgCARD32 radeon_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 *target_msc, 973de2362d3Smrg CARD64 divisor, CARD64 remainder) 974de2362d3Smrg{ 975de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 976de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 977de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 978de2362d3Smrg int nominal_frame_rate = drmmode_crtc->dpms_last_fps; 979de2362d3Smrg CARD64 last_vblank_ust = drmmode_crtc->dpms_last_ust; 980de2362d3Smrg uint32_t last_vblank_seq = drmmode_crtc->dpms_last_seq; 981de2362d3Smrg CARD64 now, target_time, delta_t; 982de2362d3Smrg int64_t d, delta_seq; 983de2362d3Smrg int ret; 984de2362d3Smrg CARD32 d_ms; 985de2362d3Smrg 986de2362d3Smrg if (!last_vblank_ust) { 987de2362d3Smrg *target_msc = 0; 988de2362d3Smrg return FALLBACK_SWAP_DELAY; 989de2362d3Smrg } 990de2362d3Smrg ret = drmmode_get_current_ust(info->dri2.drm_fd, &now); 991de2362d3Smrg if (ret) { 992de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 993de2362d3Smrg "%s cannot get current time\n", __func__); 994de2362d3Smrg *target_msc = 0; 995de2362d3Smrg return FALLBACK_SWAP_DELAY; 996de2362d3Smrg } 9970d16fef4Smrg delta_seq = *target_msc - last_vblank_seq; 998de2362d3Smrg delta_seq *= 1000000; 999de2362d3Smrg target_time = last_vblank_ust; 1000de2362d3Smrg target_time += delta_seq / nominal_frame_rate; 1001de2362d3Smrg d = target_time - now; 1002de2362d3Smrg if (d < 0) { 1003de2362d3Smrg /* we missed the event, adjust target_msc, do the divisor magic */ 10040d16fef4Smrg CARD64 current_msc = last_vblank_seq; 10050d16fef4Smrg 1006de2362d3Smrg delta_t = now - last_vblank_ust; 1007de2362d3Smrg delta_seq = delta_t * nominal_frame_rate; 1008de2362d3Smrg current_msc += delta_seq / 1000000; 1009de2362d3Smrg current_msc &= 0xffffffff; 1010de2362d3Smrg if (divisor == 0) { 1011de2362d3Smrg *target_msc = current_msc; 1012de2362d3Smrg d = 0; 1013de2362d3Smrg } else { 1014de2362d3Smrg *target_msc = current_msc - (current_msc % divisor) + remainder; 1015de2362d3Smrg if ((current_msc % divisor) >= remainder) 1016de2362d3Smrg *target_msc += divisor; 1017de2362d3Smrg *target_msc &= 0xffffffff; 10180d16fef4Smrg delta_seq = *target_msc - last_vblank_seq; 1019de2362d3Smrg delta_seq *= 1000000; 1020de2362d3Smrg target_time = last_vblank_ust; 1021de2362d3Smrg target_time += delta_seq / nominal_frame_rate; 1022de2362d3Smrg d = target_time - now; 1023de2362d3Smrg } 1024de2362d3Smrg } 1025de2362d3Smrg /* 1026de2362d3Smrg * convert delay to milliseconds and add margin to prevent the client 1027de2362d3Smrg * from coming back early (due to timer granularity and rounding 1028de2362d3Smrg * errors) and getting the same MSC it just got 1029de2362d3Smrg */ 1030de2362d3Smrg d_ms = (CARD32)d / 1000; 1031de2362d3Smrg if ((CARD32)d - d_ms * 1000 > 0) 1032de2362d3Smrg d_ms += 2; 1033de2362d3Smrg else 1034de2362d3Smrg d_ms++; 1035de2362d3Smrg return d_ms; 1036de2362d3Smrg} 1037de2362d3Smrg 1038de2362d3Smrg/* 10390d16fef4Smrg * Get current interpolated frame count and frame count timestamp, based on 10400d16fef4Smrg * drawable's crtc. 1041de2362d3Smrg */ 1042de2362d3Smrgstatic int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 1043de2362d3Smrg{ 1044de2362d3Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); 1045de2362d3Smrg 1046de2362d3Smrg /* Drawable not displayed, make up a value */ 1047de2362d3Smrg if (crtc == NULL) { 1048de2362d3Smrg *ust = 0; 1049de2362d3Smrg *msc = 0; 1050de2362d3Smrg return TRUE; 1051de2362d3Smrg } 1052de2362d3Smrg 10530d16fef4Smrg if (!radeon_dri2_get_crtc_msc(crtc, ust, msc)) 10540d16fef4Smrg return FALSE; 1055de2362d3Smrg 10560d16fef4Smrg *msc += radeon_get_msc_delta(draw, crtc); 10570d16fef4Smrg *msc &= 0xffffffff; 1058de2362d3Smrg return TRUE; 1059de2362d3Smrg} 1060de2362d3Smrg 1061de2362d3Smrgstatic 1062de2362d3SmrgCARD32 radeon_dri2_deferred_event(OsTimerPtr timer, CARD32 now, pointer data) 1063de2362d3Smrg{ 1064de2362d3Smrg DRI2FrameEventPtr event_info = (DRI2FrameEventPtr)data; 10650d16fef4Smrg xf86CrtcPtr crtc = event_info->crtc; 1066de2362d3Smrg ScrnInfoPtr scrn; 1067de2362d3Smrg RADEONInfoPtr info; 1068de2362d3Smrg CARD64 drm_now; 1069de2362d3Smrg int ret; 1070de2362d3Smrg CARD64 delta_t, delta_seq, frame; 1071de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc; 1072de2362d3Smrg 1073de2362d3Smrg /* 1074de2362d3Smrg * This is emulated event, so its time is current time, which we 1075de2362d3Smrg * have to get in DRM-compatible form (which is a bit messy given 1076de2362d3Smrg * the information that we have at this point). Can't use now argument 1077de2362d3Smrg * because DRM event time may come from monotonic clock, while 1078de2362d3Smrg * DIX timer facility uses real-time clock. 1079de2362d3Smrg */ 1080de2362d3Smrg if (!event_info->crtc) { 1081de2362d3Smrg ErrorF("%s no crtc\n", __func__); 10820d16fef4Smrg if (event_info->drm_queue_seq) 10830d16fef4Smrg radeon_drm_abort_entry(event_info->drm_queue_seq); 10840d16fef4Smrg else 10850d16fef4Smrg radeon_dri2_frame_event_abort(NULL, data); 1086de2362d3Smrg return 0; 1087de2362d3Smrg } 10880d16fef4Smrg 10890d16fef4Smrg scrn = crtc->scrn; 1090de2362d3Smrg info = RADEONPTR(scrn); 1091de2362d3Smrg ret = drmmode_get_current_ust(info->dri2.drm_fd, &drm_now); 1092de2362d3Smrg if (ret) { 1093de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1094de2362d3Smrg "%s cannot get current time\n", __func__); 10950d16fef4Smrg if (event_info->drm_queue_seq) 10960d16fef4Smrg radeon_drm_queue_handler(info->dri2.drm_fd, 0, 0, 0, 10970d16fef4Smrg (void*)event_info->drm_queue_seq); 10980d16fef4Smrg else 10990d16fef4Smrg radeon_dri2_frame_event_handler(crtc, 0, 0, data); 1100de2362d3Smrg return 0; 1101de2362d3Smrg } 1102de2362d3Smrg /* 1103de2362d3Smrg * calculate the frame number from current time 1104de2362d3Smrg * that would come from CRTC if it were running 1105de2362d3Smrg */ 1106de2362d3Smrg drmmode_crtc = event_info->crtc->driver_private; 1107de2362d3Smrg delta_t = drm_now - (CARD64)drmmode_crtc->dpms_last_ust; 1108de2362d3Smrg delta_seq = delta_t * drmmode_crtc->dpms_last_fps; 1109de2362d3Smrg delta_seq /= 1000000; 1110de2362d3Smrg frame = (CARD64)drmmode_crtc->dpms_last_seq + delta_seq; 11110d16fef4Smrg if (event_info->drm_queue_seq) 11120d16fef4Smrg radeon_drm_queue_handler(info->dri2.drm_fd, frame, drm_now / 1000000, 11130d16fef4Smrg drm_now % 1000000, 11140d16fef4Smrg (void*)event_info->drm_queue_seq); 11150d16fef4Smrg else 11160d16fef4Smrg radeon_dri2_frame_event_handler(crtc, frame, drm_now, data); 1117de2362d3Smrg return 0; 1118de2362d3Smrg} 1119de2362d3Smrg 1120de2362d3Smrgstatic 11210d16fef4Smrgvoid radeon_dri2_schedule_event(CARD32 delay, DRI2FrameEventPtr event_info) 1122de2362d3Smrg{ 11230d16fef4Smrg event_info->timer = TimerSet(NULL, 0, delay, radeon_dri2_deferred_event, 11240d16fef4Smrg event_info); 1125de2362d3Smrg if (delay == 0) { 1126de2362d3Smrg CARD32 now = GetTimeInMillis(); 11270d16fef4Smrg radeon_dri2_deferred_event(event_info->timer, now, event_info); 1128de2362d3Smrg } 1129de2362d3Smrg} 1130de2362d3Smrg 1131de2362d3Smrg/* 1132de2362d3Smrg * Request a DRM event when the requested conditions will be satisfied. 1133de2362d3Smrg * 1134de2362d3Smrg * We need to handle the event and ask the server to wake up the client when 1135de2362d3Smrg * we receive it. 1136de2362d3Smrg */ 1137de2362d3Smrgstatic int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, 1138de2362d3Smrg CARD64 target_msc, CARD64 divisor, 1139de2362d3Smrg CARD64 remainder) 1140de2362d3Smrg{ 1141de2362d3Smrg ScreenPtr screen = draw->pScreen; 1142de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1143de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1144de2362d3Smrg DRI2FrameEventPtr wait_info = NULL; 11450d16fef4Smrg uintptr_t drm_queue_seq = 0; 1146de2362d3Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); 11470d16fef4Smrg uint32_t msc_delta; 1148de2362d3Smrg drmVBlank vbl; 1149de2362d3Smrg int ret; 1150de2362d3Smrg CARD64 current_msc; 1151de2362d3Smrg 1152de2362d3Smrg /* Truncate to match kernel interfaces; means occasional overflow 1153de2362d3Smrg * misses, but that's generally not a big deal */ 1154de2362d3Smrg target_msc &= 0xffffffff; 1155de2362d3Smrg divisor &= 0xffffffff; 1156de2362d3Smrg remainder &= 0xffffffff; 1157de2362d3Smrg 1158de2362d3Smrg /* Drawable not visible, return immediately */ 1159de2362d3Smrg if (crtc == NULL) 1160de2362d3Smrg goto out_complete; 1161de2362d3Smrg 11620d16fef4Smrg msc_delta = radeon_get_msc_delta(draw, crtc); 11630d16fef4Smrg 1164de2362d3Smrg wait_info = calloc(1, sizeof(DRI2FrameEventRec)); 1165de2362d3Smrg if (!wait_info) 1166de2362d3Smrg goto out_complete; 1167de2362d3Smrg 1168de2362d3Smrg wait_info->drawable_id = draw->id; 1169de2362d3Smrg wait_info->client = client; 1170de2362d3Smrg wait_info->type = DRI2_WAITMSC; 1171de2362d3Smrg wait_info->crtc = crtc; 1172de2362d3Smrg 1173de2362d3Smrg /* 1174de2362d3Smrg * CRTC is in DPMS off state, calculate wait time from current time, 1175de2362d3Smrg * target_msc and last vblank time/sequence when CRTC was turned off 1176de2362d3Smrg */ 1177de2362d3Smrg if (!radeon_crtc_is_enabled(crtc)) { 1178de2362d3Smrg CARD32 delay; 11790d16fef4Smrg target_msc -= msc_delta; 1180de2362d3Smrg delay = radeon_dri2_extrapolate_msc_delay(crtc, &target_msc, 1181de2362d3Smrg divisor, remainder); 1182de2362d3Smrg radeon_dri2_schedule_event(delay, wait_info); 1183de2362d3Smrg DRI2BlockClient(client, draw); 1184de2362d3Smrg return TRUE; 1185de2362d3Smrg } 1186de2362d3Smrg 1187de2362d3Smrg /* Get current count */ 1188de2362d3Smrg vbl.request.type = DRM_VBLANK_RELATIVE; 1189de2362d3Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 1190de2362d3Smrg vbl.request.sequence = 0; 1191de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1192de2362d3Smrg if (ret) { 1193de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1194de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1195de2362d3Smrg goto out_complete; 1196de2362d3Smrg } 1197de2362d3Smrg 11980d16fef4Smrg current_msc = vbl.reply.sequence + msc_delta; 1199de2362d3Smrg current_msc &= 0xffffffff; 1200de2362d3Smrg 12010d16fef4Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT, 12020d16fef4Smrg wait_info, radeon_dri2_frame_event_handler, 12030d16fef4Smrg radeon_dri2_frame_event_abort); 12040d16fef4Smrg if (!drm_queue_seq) { 12050d16fef4Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 12060d16fef4Smrg "Allocating DRM queue event entry failed.\n"); 12070d16fef4Smrg goto out_complete; 12080d16fef4Smrg } 12090d16fef4Smrg wait_info->drm_queue_seq = drm_queue_seq; 12100d16fef4Smrg 1211de2362d3Smrg /* 1212de2362d3Smrg * If divisor is zero, or current_msc is smaller than target_msc, 1213de2362d3Smrg * we just need to make sure target_msc passes before waking up the 1214de2362d3Smrg * client. 1215de2362d3Smrg */ 1216de2362d3Smrg if (divisor == 0 || current_msc < target_msc) { 1217de2362d3Smrg /* If target_msc already reached or passed, set it to 1218de2362d3Smrg * current_msc to ensure we return a reasonable value back 1219de2362d3Smrg * to the caller. This keeps the client from continually 1220de2362d3Smrg * sending us MSC targets from the past by forcibly updating 1221de2362d3Smrg * their count on this call. 1222de2362d3Smrg */ 1223de2362d3Smrg if (current_msc >= target_msc) 1224de2362d3Smrg target_msc = current_msc; 1225de2362d3Smrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1226de2362d3Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 12270d16fef4Smrg vbl.request.sequence = target_msc - msc_delta; 12280d16fef4Smrg vbl.request.signal = drm_queue_seq; 1229de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1230de2362d3Smrg if (ret) { 1231de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1232de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1233de2362d3Smrg goto out_complete; 1234de2362d3Smrg } 1235de2362d3Smrg 1236de2362d3Smrg DRI2BlockClient(client, draw); 1237de2362d3Smrg return TRUE; 1238de2362d3Smrg } 1239de2362d3Smrg 1240de2362d3Smrg /* 1241de2362d3Smrg * If we get here, target_msc has already passed or we don't have one, 1242de2362d3Smrg * so we queue an event that will satisfy the divisor/remainder equation. 1243de2362d3Smrg */ 1244de2362d3Smrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1245de2362d3Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 1246de2362d3Smrg 1247de2362d3Smrg vbl.request.sequence = current_msc - (current_msc % divisor) + 12480d16fef4Smrg remainder - msc_delta; 1249de2362d3Smrg 1250de2362d3Smrg /* 1251de2362d3Smrg * If calculated remainder is larger than requested remainder, 1252de2362d3Smrg * it means we've passed the last point where 1253de2362d3Smrg * seq % divisor == remainder, so we need to wait for the next time 1254de2362d3Smrg * that will happen. 1255de2362d3Smrg */ 1256de2362d3Smrg if ((current_msc % divisor) >= remainder) 1257de2362d3Smrg vbl.request.sequence += divisor; 1258de2362d3Smrg 12590d16fef4Smrg vbl.request.signal = drm_queue_seq; 1260de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1261de2362d3Smrg if (ret) { 1262de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1263de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1264de2362d3Smrg goto out_complete; 1265de2362d3Smrg } 1266de2362d3Smrg 1267de2362d3Smrg DRI2BlockClient(client, draw); 1268de2362d3Smrg 1269de2362d3Smrg return TRUE; 1270de2362d3Smrg 1271de2362d3Smrgout_complete: 12720d16fef4Smrg if (wait_info) 12730d16fef4Smrg radeon_dri2_deferred_event(NULL, 0, wait_info); 1274de2362d3Smrg return TRUE; 1275de2362d3Smrg} 1276de2362d3Smrg 1277de2362d3Smrg/* 1278de2362d3Smrg * ScheduleSwap is responsible for requesting a DRM vblank event for the 1279de2362d3Smrg * appropriate frame. 1280de2362d3Smrg * 1281de2362d3Smrg * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 1282de2362d3Smrg * the vblank requested can simply be the last queued swap frame + the swap 1283de2362d3Smrg * interval for the drawable. 1284de2362d3Smrg * 1285de2362d3Smrg * In the case of a page flip, we request an event for the last queued swap 1286de2362d3Smrg * frame + swap interval - 1, since we'll need to queue the flip for the frame 1287de2362d3Smrg * immediately following the received event. 1288de2362d3Smrg * 1289de2362d3Smrg * The client will be blocked if it tries to perform further GL commands 1290de2362d3Smrg * after queueing a swap, though in the Intel case after queueing a flip, the 1291de2362d3Smrg * client is free to queue more commands; they'll block in the kernel if 1292de2362d3Smrg * they access buffers busy with the flip. 1293de2362d3Smrg * 1294de2362d3Smrg * When the swap is complete, the driver should call into the server so it 1295de2362d3Smrg * can send any swap complete events that have been requested. 1296de2362d3Smrg */ 1297de2362d3Smrgstatic int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, 1298de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back, 1299de2362d3Smrg CARD64 *target_msc, CARD64 divisor, 1300de2362d3Smrg CARD64 remainder, DRI2SwapEventPtr func, 1301de2362d3Smrg void *data) 1302de2362d3Smrg{ 1303de2362d3Smrg ScreenPtr screen = draw->pScreen; 1304de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1305de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1306de2362d3Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); 13070d16fef4Smrg uint32_t msc_delta; 1308de2362d3Smrg drmVBlank vbl; 1309de2362d3Smrg int ret, flip = 0; 1310de2362d3Smrg DRI2FrameEventPtr swap_info = NULL; 13110d16fef4Smrg uintptr_t drm_queue_seq; 1312de2362d3Smrg CARD64 current_msc; 1313de2362d3Smrg BoxRec box; 1314de2362d3Smrg RegionRec region; 1315de2362d3Smrg 1316de2362d3Smrg /* Truncate to match kernel interfaces; means occasional overflow 1317de2362d3Smrg * misses, but that's generally not a big deal */ 1318de2362d3Smrg *target_msc &= 0xffffffff; 1319de2362d3Smrg divisor &= 0xffffffff; 1320de2362d3Smrg remainder &= 0xffffffff; 1321de2362d3Smrg 1322de2362d3Smrg /* radeon_dri2_frame_event_handler will get called some unknown time in the 1323de2362d3Smrg * future with these buffers. Take a reference to ensure that they won't 1324de2362d3Smrg * get destroyed before then. 1325de2362d3Smrg */ 1326de2362d3Smrg radeon_dri2_ref_buffer(front); 1327de2362d3Smrg radeon_dri2_ref_buffer(back); 1328de2362d3Smrg 1329de2362d3Smrg /* either off-screen or CRTC not usable... just complete the swap */ 1330de2362d3Smrg if (crtc == NULL) 1331de2362d3Smrg goto blit_fallback; 1332de2362d3Smrg 13330d16fef4Smrg msc_delta = radeon_get_msc_delta(draw, crtc); 13340d16fef4Smrg 1335de2362d3Smrg swap_info = calloc(1, sizeof(DRI2FrameEventRec)); 1336de2362d3Smrg if (!swap_info) 1337de2362d3Smrg goto blit_fallback; 1338de2362d3Smrg 13390d16fef4Smrg swap_info->type = DRI2_SWAP; 1340de2362d3Smrg swap_info->drawable_id = draw->id; 1341de2362d3Smrg swap_info->client = client; 1342de2362d3Smrg swap_info->event_complete = func; 1343de2362d3Smrg swap_info->event_data = data; 1344de2362d3Smrg swap_info->front = front; 1345de2362d3Smrg swap_info->back = back; 1346de2362d3Smrg swap_info->crtc = crtc; 13470d16fef4Smrg 13480d16fef4Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT, 13490d16fef4Smrg swap_info, radeon_dri2_frame_event_handler, 13500d16fef4Smrg radeon_dri2_frame_event_abort); 13510d16fef4Smrg if (!drm_queue_seq) { 1352de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 13530d16fef4Smrg "Allocating DRM queue entry failed.\n"); 1354de2362d3Smrg goto blit_fallback; 1355de2362d3Smrg } 13560d16fef4Smrg swap_info->drm_queue_seq = drm_queue_seq; 1357de2362d3Smrg 1358de2362d3Smrg /* 1359de2362d3Smrg * CRTC is in DPMS off state, fallback to blit, but calculate 1360de2362d3Smrg * wait time from current time, target_msc and last vblank 1361de2362d3Smrg * time/sequence when CRTC was turned off 1362de2362d3Smrg */ 1363de2362d3Smrg if (!radeon_crtc_is_enabled(crtc)) { 1364de2362d3Smrg CARD32 delay; 13650d16fef4Smrg *target_msc -= msc_delta; 1366de2362d3Smrg delay = radeon_dri2_extrapolate_msc_delay(crtc, target_msc, 1367de2362d3Smrg divisor, remainder); 13680d16fef4Smrg *target_msc += msc_delta; 13690d16fef4Smrg *target_msc &= 0xffffffff; 1370de2362d3Smrg radeon_dri2_schedule_event(delay, swap_info); 1371de2362d3Smrg return TRUE; 1372de2362d3Smrg } 1373de2362d3Smrg 1374de2362d3Smrg /* Get current count */ 1375de2362d3Smrg vbl.request.type = DRM_VBLANK_RELATIVE; 1376de2362d3Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 1377de2362d3Smrg vbl.request.sequence = 0; 1378de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1379de2362d3Smrg if (ret) { 1380de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1381de2362d3Smrg "first get vblank counter failed: %s\n", 1382de2362d3Smrg strerror(errno)); 13830d16fef4Smrg goto blit_fallback; 1384de2362d3Smrg } 1385de2362d3Smrg 13860d16fef4Smrg current_msc = vbl.reply.sequence + msc_delta; 1387de2362d3Smrg current_msc &= 0xffffffff; 1388de2362d3Smrg 1389de2362d3Smrg /* Flips need to be submitted one frame before */ 1390de2362d3Smrg if (can_flip(scrn, draw, front, back)) { 13910d16fef4Smrg swap_info->type = DRI2_FLIP; 1392de2362d3Smrg flip = 1; 1393de2362d3Smrg } 1394de2362d3Smrg 13950d16fef4Smrg /* Correct target_msc by 'flip' if swap_info->type == DRI2_FLIP. 1396de2362d3Smrg * Do it early, so handling of different timing constraints 1397de2362d3Smrg * for divisor, remainder and msc vs. target_msc works. 1398de2362d3Smrg */ 1399de2362d3Smrg if (*target_msc > 0) 1400de2362d3Smrg *target_msc -= flip; 1401de2362d3Smrg 1402de2362d3Smrg /* 1403de2362d3Smrg * If divisor is zero, or current_msc is smaller than target_msc 1404de2362d3Smrg * we just need to make sure target_msc passes before initiating 1405de2362d3Smrg * the swap. 1406de2362d3Smrg */ 1407de2362d3Smrg if (divisor == 0 || current_msc < *target_msc) { 1408de2362d3Smrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1409de2362d3Smrg /* If non-pageflipping, but blitting/exchanging, we need to use 1410de2362d3Smrg * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later 1411de2362d3Smrg * on. 1412de2362d3Smrg */ 1413de2362d3Smrg if (flip == 0) 1414de2362d3Smrg vbl.request.type |= DRM_VBLANK_NEXTONMISS; 1415de2362d3Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 1416de2362d3Smrg 1417de2362d3Smrg /* If target_msc already reached or passed, set it to 1418de2362d3Smrg * current_msc to ensure we return a reasonable value back 1419de2362d3Smrg * to the caller. This makes swap_interval logic more robust. 1420de2362d3Smrg */ 1421de2362d3Smrg if (current_msc >= *target_msc) 1422de2362d3Smrg *target_msc = current_msc; 1423de2362d3Smrg 14240d16fef4Smrg vbl.request.sequence = *target_msc - msc_delta; 14250d16fef4Smrg vbl.request.signal = drm_queue_seq; 1426de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1427de2362d3Smrg if (ret) { 1428de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1429de2362d3Smrg "divisor 0 get vblank counter failed: %s\n", 1430de2362d3Smrg strerror(errno)); 14310d16fef4Smrg goto blit_fallback; 1432de2362d3Smrg } 1433de2362d3Smrg 14340d16fef4Smrg *target_msc = vbl.reply.sequence + flip + msc_delta; 1435de2362d3Smrg swap_info->frame = *target_msc; 1436de2362d3Smrg 1437de2362d3Smrg return TRUE; 1438de2362d3Smrg } 1439de2362d3Smrg 1440de2362d3Smrg /* 1441de2362d3Smrg * If we get here, target_msc has already passed or we don't have one, 1442de2362d3Smrg * and we need to queue an event that will satisfy the divisor/remainder 1443de2362d3Smrg * equation. 1444de2362d3Smrg */ 1445de2362d3Smrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1446de2362d3Smrg if (flip == 0) 1447de2362d3Smrg vbl.request.type |= DRM_VBLANK_NEXTONMISS; 1448de2362d3Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 1449de2362d3Smrg 1450de2362d3Smrg vbl.request.sequence = current_msc - (current_msc % divisor) + 14510d16fef4Smrg remainder - msc_delta; 1452de2362d3Smrg 1453de2362d3Smrg /* 1454de2362d3Smrg * If the calculated deadline vbl.request.sequence is smaller than 1455de2362d3Smrg * or equal to current_msc, it means we've passed the last point 1456de2362d3Smrg * when effective onset frame seq could satisfy 1457de2362d3Smrg * seq % divisor == remainder, so we need to wait for the next time 1458de2362d3Smrg * this will happen. 1459de2362d3Smrg 1460de2362d3Smrg * This comparison takes the 1 frame swap delay in pageflipping mode 1461de2362d3Smrg * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay 1462de2362d3Smrg * if we are blitting/exchanging instead of flipping. 1463de2362d3Smrg */ 1464de2362d3Smrg if (vbl.request.sequence <= current_msc) 1465de2362d3Smrg vbl.request.sequence += divisor; 1466de2362d3Smrg 1467de2362d3Smrg /* Account for 1 frame extra pageflip delay if flip > 0 */ 1468de2362d3Smrg vbl.request.sequence -= flip; 1469de2362d3Smrg 14700d16fef4Smrg vbl.request.signal = drm_queue_seq; 1471de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1472de2362d3Smrg if (ret) { 1473de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1474de2362d3Smrg "final get vblank counter failed: %s\n", 1475de2362d3Smrg strerror(errno)); 14760d16fef4Smrg goto blit_fallback; 1477de2362d3Smrg } 1478de2362d3Smrg 1479de2362d3Smrg /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ 14800d16fef4Smrg *target_msc = vbl.reply.sequence + flip + msc_delta; 14810d16fef4Smrg *target_msc &= 0xffffffff; 1482de2362d3Smrg swap_info->frame = *target_msc; 1483de2362d3Smrg 1484de2362d3Smrg return TRUE; 1485de2362d3Smrg 1486de2362d3Smrgblit_fallback: 14870d16fef4Smrg if (swap_info) { 14880d16fef4Smrg swap_info->type = DRI2_SWAP; 14890d16fef4Smrg radeon_dri2_schedule_event(FALLBACK_SWAP_DELAY, swap_info); 14900d16fef4Smrg } else { 14910d16fef4Smrg box.x1 = 0; 14920d16fef4Smrg box.y1 = 0; 14930d16fef4Smrg box.x2 = draw->width; 14940d16fef4Smrg box.y2 = draw->height; 14950d16fef4Smrg REGION_INIT(pScreen, ®ion, &box, 0); 1496de2362d3Smrg 14970d16fef4Smrg radeon_dri2_copy_region(draw, ®ion, front, back); 1498de2362d3Smrg 14990d16fef4Smrg DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); 1500de2362d3Smrg 15010d16fef4Smrg radeon_dri2_unref_buffer(front); 15020d16fef4Smrg radeon_dri2_unref_buffer(back); 15030d16fef4Smrg } 1504de2362d3Smrg 1505de2362d3Smrg *target_msc = 0; /* offscreen, so zero out target vblank count */ 1506de2362d3Smrg return TRUE; 1507de2362d3Smrg} 1508de2362d3Smrg 1509de2362d3Smrg 1510de2362d3SmrgBool 1511de2362d3Smrgradeon_dri2_screen_init(ScreenPtr pScreen) 1512de2362d3Smrg{ 1513de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1514de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1515de2362d3Smrg DRI2InfoRec dri2_info = { 0 }; 1516de2362d3Smrg const char *driverNames[2]; 1517de2362d3Smrg Bool scheduling_works = TRUE; 1518de2362d3Smrg 1519de2362d3Smrg if (!info->dri2.available) 1520de2362d3Smrg return FALSE; 1521de2362d3Smrg 1522de2362d3Smrg info->dri2.device_name = drmGetDeviceNameFromFd(info->dri2.drm_fd); 1523de2362d3Smrg 1524de2362d3Smrg if ( (info->ChipFamily >= CHIP_FAMILY_TAHITI) ) { 1525de2362d3Smrg dri2_info.driverName = SI_DRIVER_NAME; 1526de2362d3Smrg } else if ( (info->ChipFamily >= CHIP_FAMILY_R600) ) { 1527de2362d3Smrg dri2_info.driverName = R600_DRIVER_NAME; 1528de2362d3Smrg } else if ( (info->ChipFamily >= CHIP_FAMILY_R300) ) { 1529de2362d3Smrg dri2_info.driverName = R300_DRIVER_NAME; 1530de2362d3Smrg } else if ( info->ChipFamily >= CHIP_FAMILY_R200 ) { 1531de2362d3Smrg dri2_info.driverName = R200_DRIVER_NAME; 1532de2362d3Smrg } else { 1533de2362d3Smrg dri2_info.driverName = RADEON_DRIVER_NAME; 1534de2362d3Smrg } 1535de2362d3Smrg dri2_info.fd = info->dri2.drm_fd; 1536de2362d3Smrg dri2_info.deviceName = info->dri2.device_name; 1537de2362d3Smrg dri2_info.version = DRI2INFOREC_VERSION; 1538de2362d3Smrg dri2_info.CreateBuffer = radeon_dri2_create_buffer; 1539de2362d3Smrg dri2_info.DestroyBuffer = radeon_dri2_destroy_buffer; 1540de2362d3Smrg dri2_info.CopyRegion = radeon_dri2_copy_region; 1541de2362d3Smrg 1542de2362d3Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4) { 1543de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for " 1544de2362d3Smrg "sync extension\n"); 1545de2362d3Smrg scheduling_works = FALSE; 1546de2362d3Smrg } 1547de2362d3Smrg 15480d16fef4Smrg if (scheduling_works && info->drmmode.count_crtcs > 2) { 1549de2362d3Smrg#ifdef DRM_CAP_VBLANK_HIGH_CRTC 1550de2362d3Smrg uint64_t cap_value; 1551de2362d3Smrg 1552de2362d3Smrg if (drmGetCap(info->dri2.drm_fd, DRM_CAP_VBLANK_HIGH_CRTC, &cap_value)) { 1553de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel " 1554de2362d3Smrg "for VBLANKs on CRTC > 1\n"); 1555de2362d3Smrg scheduling_works = FALSE; 1556de2362d3Smrg } else if (!cap_value) { 1557de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Your kernel does not " 1558de2362d3Smrg "handle VBLANKs on CRTC > 1\n"); 1559de2362d3Smrg scheduling_works = FALSE; 1560de2362d3Smrg } 1561de2362d3Smrg#else 1562de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need to rebuild against a " 1563de2362d3Smrg "newer libdrm to handle VBLANKs on CRTC > 1\n"); 1564de2362d3Smrg scheduling_works = FALSE; 1565de2362d3Smrg#endif 1566de2362d3Smrg } 1567de2362d3Smrg 1568de2362d3Smrg if (scheduling_works) { 1569de2362d3Smrg dri2_info.version = 4; 1570de2362d3Smrg dri2_info.ScheduleSwap = radeon_dri2_schedule_swap; 1571de2362d3Smrg dri2_info.GetMSC = radeon_dri2_get_msc; 1572de2362d3Smrg dri2_info.ScheduleWaitMSC = radeon_dri2_schedule_wait_msc; 1573de2362d3Smrg dri2_info.numDrivers = RADEON_ARRAY_SIZE(driverNames); 1574de2362d3Smrg dri2_info.driverNames = driverNames; 15750d16fef4Smrg driverNames[0] = dri2_info.driverName; 15760d16fef4Smrg 15770d16fef4Smrg if (info->ChipFamily >= CHIP_FAMILY_R300) 15780d16fef4Smrg driverNames[1] = driverNames[0]; 15790d16fef4Smrg else 15800d16fef4Smrg driverNames[1] = NULL; /* no VDPAU support */ 1581de2362d3Smrg 1582de2362d3Smrg if (DRI2InfoCnt == 0) { 15830d16fef4Smrg if (!dixRegisterPrivateKey(dri2_window_private_key, 15840d16fef4Smrg PRIVATE_WINDOW, 15850d16fef4Smrg sizeof(struct dri2_window_priv))) { 15860d16fef4Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 15870d16fef4Smrg "Failed to get DRI2 window private\n"); 1588de2362d3Smrg return FALSE; 1589de2362d3Smrg } 1590de2362d3Smrg 1591de2362d3Smrg AddCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); 1592de2362d3Smrg } 1593de2362d3Smrg 1594de2362d3Smrg DRI2InfoCnt++; 1595de2362d3Smrg } 1596de2362d3Smrg 1597de2362d3Smrg#if DRI2INFOREC_VERSION >= 9 1598de2362d3Smrg dri2_info.version = 9; 1599de2362d3Smrg dri2_info.CreateBuffer2 = radeon_dri2_create_buffer2; 1600de2362d3Smrg dri2_info.DestroyBuffer2 = radeon_dri2_destroy_buffer2; 1601de2362d3Smrg dri2_info.CopyRegion2 = radeon_dri2_copy_region2; 1602de2362d3Smrg#endif 1603de2362d3Smrg 1604de2362d3Smrg info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info); 1605de2362d3Smrg return info->dri2.enabled; 1606de2362d3Smrg} 1607de2362d3Smrg 1608de2362d3Smrgvoid radeon_dri2_close_screen(ScreenPtr pScreen) 1609de2362d3Smrg{ 1610de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1611de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1612de2362d3Smrg 1613de2362d3Smrg if (--DRI2InfoCnt == 0) 1614de2362d3Smrg DeleteCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); 1615de2362d3Smrg 1616de2362d3Smrg DRI2CloseScreen(pScreen); 1617de2362d3Smrg drmFree(info->dri2.device_name); 1618de2362d3Smrg} 1619de2362d3Smrg 1620de2362d3Smrg#endif /* DRI2 */ 1621de2362d3Smrg 1622