radeon_dri2.c revision 7821949a
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 <sys/types.h> 33de2362d3Smrg#include <sys/stat.h> 34de2362d3Smrg#include <fcntl.h> 35de2362d3Smrg#include <errno.h> 36de2362d3Smrg 377821949aSmrg#include "radeon.h" 387821949aSmrg#include "radeon_dri2.h" 39de2362d3Smrg#include "radeon_version.h" 40de2362d3Smrg 417821949aSmrg#if HAVE_LIST_H 427821949aSmrg#include "list.h" 437821949aSmrg#if !HAVE_XORG_LIST 447821949aSmrg#define xorg_list list 457821949aSmrg#define xorg_list_init list_init 467821949aSmrg#define xorg_list_add list_add 477821949aSmrg#define xorg_list_del list_del 487821949aSmrg#define xorg_list_for_each_entry list_for_each_entry 497821949aSmrg#endif 507821949aSmrg#endif 51de2362d3Smrg 527821949aSmrg#ifdef RADEON_DRI2 53de2362d3Smrg 547821949aSmrg#include "radeon_bo_gem.h" 55de2362d3Smrg 567821949aSmrg#if DRI2INFOREC_VERSION >= 1 577821949aSmrg#define USE_DRI2_1_1_0 587821949aSmrg#endif 59de2362d3Smrg 607821949aSmrg#if DRI2INFOREC_VERSION >= 4 && HAVE_LIST_H 617821949aSmrg#define USE_DRI2_SCHEDULING 627821949aSmrg#endif 63de2362d3Smrg 647821949aSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0, 0) 65de2362d3Smrgtypedef DRI2BufferPtr BufferPtr; 667821949aSmrg#else 677821949aSmrgtypedef DRI2Buffer2Ptr BufferPtr; 687821949aSmrg#endif 69de2362d3Smrg 70de2362d3Smrgstruct dri2_buffer_priv { 71de2362d3Smrg PixmapPtr pixmap; 72de2362d3Smrg unsigned int attachment; 73de2362d3Smrg unsigned int refcnt; 74de2362d3Smrg}; 75de2362d3Smrg 76de2362d3Smrg 777821949aSmrg#ifndef USE_DRI2_1_1_0 787821949aSmrgstatic BufferPtr 797821949aSmrgradeon_dri2_create_buffers(DrawablePtr drawable, 807821949aSmrg unsigned int *attachments, 817821949aSmrg int count) 827821949aSmrg{ 837821949aSmrg ScreenPtr pScreen = drawable->pScreen; 847821949aSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 857821949aSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 867821949aSmrg BufferPtr buffers; 877821949aSmrg struct dri2_buffer_priv *privates; 887821949aSmrg PixmapPtr pixmap, depth_pixmap; 897821949aSmrg struct radeon_exa_pixmap_priv *driver_priv; 907821949aSmrg int i, r, need_enlarge = 0; 917821949aSmrg int flags = 0; 927821949aSmrg unsigned front_width; 937821949aSmrg uint32_t tiling = 0; 940d16fef4Smrg 957821949aSmrg pixmap = screen->GetScreenPixmap(screen); 967821949aSmrg front_width = pixmap->drawable.width; 970d16fef4Smrg 987821949aSmrg buffers = calloc(count, sizeof *buffers); 997821949aSmrg if (buffers == NULL) { 1007821949aSmrg return NULL; 1017821949aSmrg } 1027821949aSmrg privates = calloc(count, sizeof(struct dri2_buffer_priv)); 1037821949aSmrg if (privates == NULL) { 1047821949aSmrg free(buffers); 1057821949aSmrg return NULL; 1067821949aSmrg } 1070d16fef4Smrg 1087821949aSmrg depth_pixmap = NULL; 1097821949aSmrg for (i = 0; i < count; i++) { 1107821949aSmrg if (attachments[i] == DRI2BufferFrontLeft) { 1117821949aSmrg if (drawable->type == DRAWABLE_PIXMAP) { 1127821949aSmrg pixmap = (Pixmap*)drawable; 1137821949aSmrg } else { 1147821949aSmrg pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable); 1157821949aSmrg } 1167821949aSmrg pixmap->refcnt++; 1177821949aSmrg } else if (attachments[i] == DRI2BufferStencil && depth_pixmap) { 1187821949aSmrg pixmap = depth_pixmap; 1197821949aSmrg pixmap->refcnt++; 1207821949aSmrg } else { 1217821949aSmrg /* tile the back buffer */ 1227821949aSmrg switch(attachments[i]) { 1237821949aSmrg case DRI2BufferDepth: 1247821949aSmrg if (info->ChipFamily >= CHIP_FAMILY_R600) 1257821949aSmrg /* macro is the preferred setting, but the 2D detiling for software 1267821949aSmrg * fallbacks in mesa still has issues on some configurations 1277821949aSmrg */ 1287821949aSmrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 1297821949aSmrg else 1307821949aSmrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 1317821949aSmrg if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON) 1327821949aSmrg flags |= RADEON_CREATE_PIXMAP_DEPTH; 1337821949aSmrg break; 1347821949aSmrg case DRI2BufferDepthStencil: 1357821949aSmrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 1367821949aSmrg /* macro is the preferred setting, but the 2D detiling for software 1377821949aSmrg * fallbacks in mesa still has issues on some configurations 1387821949aSmrg */ 1397821949aSmrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 1407821949aSmrg if (info->ChipFamily >= CHIP_FAMILY_CEDAR) 1417821949aSmrg need_enlarge = 1; 1427821949aSmrg } else 1437821949aSmrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 1447821949aSmrg if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON) 1457821949aSmrg flags |= RADEON_CREATE_PIXMAP_DEPTH; 1467821949aSmrg break; 1477821949aSmrg case DRI2BufferBackLeft: 1487821949aSmrg case DRI2BufferBackRight: 1497821949aSmrg case DRI2BufferFakeFrontLeft: 1507821949aSmrg case DRI2BufferFakeFrontRight: 1517821949aSmrg if (info->ChipFamily >= CHIP_FAMILY_R600) 1527821949aSmrg /* macro is the preferred setting, but the 2D detiling for software 1537821949aSmrg * fallbacks in mesa still has issues on some configurations 1547821949aSmrg */ 1557821949aSmrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 1567821949aSmrg else 1577821949aSmrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 1587821949aSmrg break; 1597821949aSmrg default: 1607821949aSmrg flags = 0; 1617821949aSmrg } 1620d16fef4Smrg 1637821949aSmrg if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO) 1647821949aSmrg tiling |= RADEON_TILING_MICRO; 1657821949aSmrg if (flags & RADEON_CREATE_PIXMAP_TILING_MACRO) 1667821949aSmrg tiling |= RADEON_TILING_MACRO; 1677821949aSmrg 1687821949aSmrg if (need_enlarge) { 1697821949aSmrg /* evergreen uses separate allocations for depth and stencil 1707821949aSmrg * so we make an extra large depth buffer to cover stencil 1717821949aSmrg * as well. 1727821949aSmrg */ 1737821949aSmrg unsigned aligned_width = drawable->width; 1747821949aSmrg unsigned width_align = drmmode_get_pitch_align(pScrn, drawable->depth / 8, tiling); 1757821949aSmrg unsigned aligned_height; 1767821949aSmrg unsigned height_align = drmmode_get_height_align(pScrn, tiling); 1777821949aSmrg unsigned base_align = drmmode_get_base_align(pScrn, drawable->depth / 8, tiling); 1787821949aSmrg unsigned pitch_bytes; 1797821949aSmrg unsigned size; 1807821949aSmrg 1817821949aSmrg if (aligned_width == front_width) 1827821949aSmrg aligned_width = pScrn->virtualX; 1837821949aSmrg aligned_width = RADEON_ALIGN(aligned_width, width_align); 1847821949aSmrg pitch_bytes = aligned_width * (drawable->depth / 8); 1857821949aSmrg aligned_height = RADEON_ALIGN(drawable->height, height_align); 1867821949aSmrg size = pitch_bytes * aligned_height; 1877821949aSmrg size = RADEON_ALIGN(size, base_align); 1887821949aSmrg /* add additional size for stencil */ 1897821949aSmrg size += aligned_width * aligned_height; 1907821949aSmrg aligned_height = RADEON_ALIGN(size / pitch_bytes, height_align); 1917821949aSmrg 1927821949aSmrg pixmap = (*pScreen->CreatePixmap)(pScreen, 1937821949aSmrg aligned_width, 1947821949aSmrg aligned_height, 1957821949aSmrg drawable->depth, 1967821949aSmrg flags); 1977821949aSmrg 1987821949aSmrg } else { 1997821949aSmrg unsigned aligned_width = drawable->width; 2007821949aSmrg 2017821949aSmrg if (aligned_width == front_width) 2027821949aSmrg aligned_width = pScrn->virtualX; 2037821949aSmrg 2047821949aSmrg pixmap = (*pScreen->CreatePixmap)(pScreen, 2057821949aSmrg aligned_width, 2067821949aSmrg drawable->height, 2077821949aSmrg drawable->depth, 2087821949aSmrg flags); 2097821949aSmrg } 2107821949aSmrg } 2110d16fef4Smrg 2127821949aSmrg if (attachments[i] == DRI2BufferDepth) { 2137821949aSmrg depth_pixmap = pixmap; 2147821949aSmrg } 2157821949aSmrg info->exa_force_create = TRUE; 2167821949aSmrg exaMoveInPixmap(pixmap); 2177821949aSmrg info->exa_force_create = FALSE; 2187821949aSmrg driver_priv = exaGetPixmapDriverPrivate(pixmap); 2197821949aSmrg if (!driver_priv || 2207821949aSmrg radeon_gem_get_kernel_name(driver_priv->bo, &buffers[i].name) != 0) { 2217821949aSmrg int j; 2227821949aSmrg 2237821949aSmrg for (j = 0; j < i; j++) 2247821949aSmrg (*pScreen->DestroyPixmap)(privates[j].pixmap); 2257821949aSmrg (*pScreen->DestroyPixmap)(pixmap); 2267821949aSmrg free(privates); 2277821949aSmrg free(buffers); 2287821949aSmrg return NULL; 2297821949aSmrg } 2300d16fef4Smrg 2317821949aSmrg buffers[i].attachment = attachments[i]; 2327821949aSmrg buffers[i].pitch = pixmap->devKind; 2337821949aSmrg buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8; 2347821949aSmrg buffers[i].driverPrivate = &privates[i]; 2357821949aSmrg buffers[i].flags = 0; 2367821949aSmrg privates[i].pixmap = pixmap; 2377821949aSmrg privates[i].attachment = attachments[i]; 2380d16fef4Smrg } 2397821949aSmrg return buffers; 2400d16fef4Smrg} 2417821949aSmrg#else 242de2362d3Smrgstatic BufferPtr 2437821949aSmrgradeon_dri2_create_buffer(DrawablePtr drawable, 2447821949aSmrg unsigned int attachment, 2457821949aSmrg unsigned int format) 246de2362d3Smrg{ 2477821949aSmrg ScreenPtr pScreen = drawable->pScreen; 248de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 249de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 250de2362d3Smrg BufferPtr buffers; 251de2362d3Smrg struct dri2_buffer_priv *privates; 2527821949aSmrg PixmapPtr pixmap, depth_pixmap; 2537821949aSmrg struct radeon_exa_pixmap_priv *driver_priv; 254de2362d3Smrg int flags; 255de2362d3Smrg unsigned front_width; 256de2362d3Smrg uint32_t tiling = 0; 257de2362d3Smrg unsigned aligned_width = drawable->width; 258de2362d3Smrg 2597821949aSmrg pixmap = pScreen->GetScreenPixmap(pScreen); 2607821949aSmrg front_width = pixmap->drawable.width; 261de2362d3Smrg 2627821949aSmrg pixmap = depth_pixmap = NULL; 263de2362d3Smrg 264de2362d3Smrg if (attachment == DRI2BufferFrontLeft) { 2657821949aSmrg if (drawable->type == DRAWABLE_PIXMAP) { 2667821949aSmrg pixmap = (PixmapPtr)drawable; 2677821949aSmrg } else { 2687821949aSmrg pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable); 2697821949aSmrg } 2707821949aSmrg pixmap->refcnt++; 2717821949aSmrg } else if (attachment == DRI2BufferStencil && depth_pixmap) { 2727821949aSmrg pixmap = depth_pixmap; 2737821949aSmrg pixmap->refcnt++; 2747821949aSmrg } else { 275de2362d3Smrg /* tile the back buffer */ 276de2362d3Smrg switch(attachment) { 277de2362d3Smrg case DRI2BufferDepth: 278de2362d3Smrg /* macro is the preferred setting, but the 2D detiling for software 279de2362d3Smrg * fallbacks in mesa still has issues on some configurations 280de2362d3Smrg */ 281de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 282de2362d3Smrg if (info->allowColorTiling2D) { 283de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 284de2362d3Smrg } else { 285de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 286de2362d3Smrg } 287de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_CEDAR) 288de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_SZBUFFER; 2897821949aSmrg } else 290de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 291de2362d3Smrg if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON) 292de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_DEPTH; 293de2362d3Smrg break; 294de2362d3Smrg case DRI2BufferDepthStencil: 295de2362d3Smrg /* macro is the preferred setting, but the 2D detiling for software 296de2362d3Smrg * fallbacks in mesa still has issues on some configurations 297de2362d3Smrg */ 298de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 299de2362d3Smrg if (info->allowColorTiling2D) { 300de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 301de2362d3Smrg } else { 302de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 303de2362d3Smrg } 304de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_CEDAR) 305de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_SZBUFFER; 3067821949aSmrg } else 307de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 308de2362d3Smrg if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON) 309de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_DEPTH; 310de2362d3Smrg 311de2362d3Smrg break; 312de2362d3Smrg case DRI2BufferBackLeft: 313de2362d3Smrg case DRI2BufferBackRight: 314de2362d3Smrg case DRI2BufferFakeFrontLeft: 315de2362d3Smrg case DRI2BufferFakeFrontRight: 316de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 317de2362d3Smrg if (info->allowColorTiling2D) { 318de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 319de2362d3Smrg } else { 320de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 321de2362d3Smrg } 322de2362d3Smrg } else 323de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 324de2362d3Smrg break; 325de2362d3Smrg default: 326de2362d3Smrg flags = 0; 327de2362d3Smrg } 328de2362d3Smrg 329de2362d3Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO) 330de2362d3Smrg tiling |= RADEON_TILING_MICRO; 331de2362d3Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MACRO) 332de2362d3Smrg tiling |= RADEON_TILING_MACRO; 333de2362d3Smrg 334de2362d3Smrg 3357821949aSmrg if (aligned_width == front_width) 3367821949aSmrg aligned_width = pScrn->virtualX; 3377821949aSmrg 3387821949aSmrg pixmap = (*pScreen->CreatePixmap)(pScreen, 3397821949aSmrg aligned_width, 3407821949aSmrg drawable->height, 3417821949aSmrg (format != 0)?format:drawable->depth, 3427821949aSmrg flags); 343de2362d3Smrg } 344de2362d3Smrg 3457821949aSmrg if (!pixmap) 3467821949aSmrg return NULL; 3477821949aSmrg 348de2362d3Smrg buffers = calloc(1, sizeof *buffers); 349de2362d3Smrg if (buffers == NULL) 350de2362d3Smrg goto error; 351de2362d3Smrg 3527821949aSmrg if (attachment == DRI2BufferDepth) { 3537821949aSmrg depth_pixmap = pixmap; 354de2362d3Smrg } 3557821949aSmrg info->exa_force_create = TRUE; 3567821949aSmrg exaMoveInPixmap(pixmap); 3577821949aSmrg info->exa_force_create = FALSE; 3587821949aSmrg driver_priv = exaGetPixmapDriverPrivate(pixmap); 3597821949aSmrg if (!driver_priv || 3607821949aSmrg (radeon_gem_get_kernel_name(driver_priv->bo, &buffers->name) != 0)) 3617821949aSmrg goto error; 362de2362d3Smrg 363de2362d3Smrg privates = calloc(1, sizeof(struct dri2_buffer_priv)); 364de2362d3Smrg if (privates == NULL) 365de2362d3Smrg goto error; 366de2362d3Smrg 367de2362d3Smrg buffers->attachment = attachment; 3687821949aSmrg buffers->pitch = pixmap->devKind; 3697821949aSmrg buffers->cpp = pixmap->drawable.bitsPerPixel / 8; 370de2362d3Smrg buffers->driverPrivate = privates; 371de2362d3Smrg buffers->format = format; 372de2362d3Smrg buffers->flags = 0; /* not tiled */ 373de2362d3Smrg privates->pixmap = pixmap; 374de2362d3Smrg privates->attachment = attachment; 375de2362d3Smrg privates->refcnt = 1; 376de2362d3Smrg 377de2362d3Smrg return buffers; 378de2362d3Smrg 379de2362d3Smrgerror: 380de2362d3Smrg free(buffers); 381de2362d3Smrg if (pixmap) 382de2362d3Smrg (*pScreen->DestroyPixmap)(pixmap); 383de2362d3Smrg return NULL; 384de2362d3Smrg} 3857821949aSmrg#endif 386de2362d3Smrg 3877821949aSmrg#ifndef USE_DRI2_1_1_0 3887821949aSmrgstatic void 3897821949aSmrgradeon_dri2_destroy_buffers(DrawablePtr drawable, 3907821949aSmrg BufferPtr buffers, 3917821949aSmrg int count) 392de2362d3Smrg{ 3937821949aSmrg ScreenPtr pScreen = drawable->pScreen; 3947821949aSmrg struct dri2_buffer_priv *private; 3957821949aSmrg int i; 396de2362d3Smrg 3977821949aSmrg for (i = 0; i < count; i++) { 3987821949aSmrg private = buffers[i].driverPrivate; 3997821949aSmrg (*pScreen->DestroyPixmap)(private->pixmap); 4007821949aSmrg } 4017821949aSmrg if (buffers) { 4027821949aSmrg free(buffers[0].driverPrivate); 4037821949aSmrg free(buffers); 4047821949aSmrg } 4057821949aSmrg} 4067821949aSmrg#else 407de2362d3Smrgstatic void 4087821949aSmrgradeon_dri2_destroy_buffer(DrawablePtr drawable, BufferPtr buffers) 409de2362d3Smrg{ 410de2362d3Smrg if(buffers) 411de2362d3Smrg { 4127821949aSmrg ScreenPtr pScreen = drawable->pScreen; 413de2362d3Smrg struct dri2_buffer_priv *private = buffers->driverPrivate; 414de2362d3Smrg 415de2362d3Smrg /* Trying to free an already freed buffer is unlikely to end well */ 416de2362d3Smrg if (private->refcnt == 0) { 417de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 418de2362d3Smrg 419de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 420de2362d3Smrg "Attempted to destroy previously destroyed buffer.\ 421de2362d3Smrg This is a programming error\n"); 422de2362d3Smrg return; 423de2362d3Smrg } 424de2362d3Smrg 425de2362d3Smrg private->refcnt--; 426de2362d3Smrg if (private->refcnt == 0) 427de2362d3Smrg { 4287821949aSmrg (*pScreen->DestroyPixmap)(private->pixmap); 429de2362d3Smrg 430de2362d3Smrg free(buffers->driverPrivate); 431de2362d3Smrg free(buffers); 432de2362d3Smrg } 433de2362d3Smrg } 434de2362d3Smrg} 4357821949aSmrg#endif 436de2362d3Smrg 437de2362d3Smrgstatic void 4387821949aSmrgradeon_dri2_copy_region(DrawablePtr drawable, 4397821949aSmrg RegionPtr region, 4407821949aSmrg BufferPtr dest_buffer, 4417821949aSmrg BufferPtr src_buffer) 442de2362d3Smrg{ 443de2362d3Smrg struct dri2_buffer_priv *src_private = src_buffer->driverPrivate; 444de2362d3Smrg struct dri2_buffer_priv *dst_private = dest_buffer->driverPrivate; 4457821949aSmrg ScreenPtr pScreen = drawable->pScreen; 446de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 447de2362d3Smrg DrawablePtr src_drawable; 448de2362d3Smrg DrawablePtr dst_drawable; 449de2362d3Smrg RegionPtr copy_clip; 450de2362d3Smrg GCPtr gc; 451de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 452de2362d3Smrg Bool vsync; 453de2362d3Smrg 454de2362d3Smrg if (src_private->attachment == DRI2BufferFrontLeft) { 4557821949aSmrg src_drawable = drawable; 4567821949aSmrg } else { 4577821949aSmrg src_drawable = &src_private->pixmap->drawable; 458de2362d3Smrg } 459de2362d3Smrg if (dst_private->attachment == DRI2BufferFrontLeft) { 4607821949aSmrg dst_drawable = drawable; 4617821949aSmrg } else { 4627821949aSmrg dst_drawable = &dst_private->pixmap->drawable; 463de2362d3Smrg } 464de2362d3Smrg gc = GetScratchGC(dst_drawable->depth, pScreen); 465de2362d3Smrg copy_clip = REGION_CREATE(pScreen, NULL, 0); 466de2362d3Smrg REGION_COPY(pScreen, copy_clip, region); 467de2362d3Smrg (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0); 468de2362d3Smrg ValidateGC(dst_drawable, gc); 469de2362d3Smrg 470de2362d3Smrg /* If this is a full buffer swap or frontbuffer flush, throttle on the 471de2362d3Smrg * previous one 472de2362d3Smrg */ 473de2362d3Smrg if (dst_private->attachment == DRI2BufferFrontLeft) { 474de2362d3Smrg if (REGION_NUM_RECTS(region) == 1) { 475de2362d3Smrg BoxPtr extents = REGION_EXTENTS(pScreen, region); 476de2362d3Smrg 477de2362d3Smrg if (extents->x1 == 0 && extents->y1 == 0 && 478de2362d3Smrg extents->x2 == drawable->width && 479de2362d3Smrg extents->y2 == drawable->height) { 4807821949aSmrg struct radeon_exa_pixmap_priv *exa_priv = 4817821949aSmrg exaGetPixmapDriverPrivate(dst_private->pixmap); 482de2362d3Smrg 4837821949aSmrg if (exa_priv && exa_priv->bo) 4847821949aSmrg radeon_bo_wait(exa_priv->bo); 485de2362d3Smrg } 486de2362d3Smrg } 487de2362d3Smrg } 488de2362d3Smrg 489de2362d3Smrg vsync = info->accel_state->vsync; 490de2362d3Smrg 491de2362d3Smrg /* Driver option "SwapbuffersWait" defines if we vsync DRI2 copy-swaps. */ 492de2362d3Smrg info->accel_state->vsync = info->swapBuffersWait; 493de2362d3Smrg 494de2362d3Smrg (*gc->ops->CopyArea)(src_drawable, dst_drawable, gc, 4957821949aSmrg 0, 0, drawable->width, drawable->height, 0, 0); 496de2362d3Smrg 497de2362d3Smrg info->accel_state->vsync = vsync; 498de2362d3Smrg 499de2362d3Smrg FreeScratchGC(gc); 500de2362d3Smrg} 501de2362d3Smrg 5027821949aSmrg 5037821949aSmrg#ifdef USE_DRI2_SCHEDULING 504de2362d3Smrg 505de2362d3Smrgenum DRI2FrameEventType { 506de2362d3Smrg DRI2_SWAP, 507de2362d3Smrg DRI2_FLIP, 508de2362d3Smrg DRI2_WAITMSC, 509de2362d3Smrg}; 510de2362d3Smrg 511de2362d3Smrgtypedef struct _DRI2FrameEvent { 512de2362d3Smrg XID drawable_id; 513de2362d3Smrg ClientPtr client; 514de2362d3Smrg enum DRI2FrameEventType type; 5157821949aSmrg int frame; 516de2362d3Smrg 517de2362d3Smrg /* for swaps & flips only */ 518de2362d3Smrg DRI2SwapEventPtr event_complete; 519de2362d3Smrg void *event_data; 520de2362d3Smrg DRI2BufferPtr front; 521de2362d3Smrg DRI2BufferPtr back; 5227821949aSmrg 5237821949aSmrg Bool valid; 5247821949aSmrg 5257821949aSmrg struct xorg_list link; 526de2362d3Smrg} DRI2FrameEventRec, *DRI2FrameEventPtr; 527de2362d3Smrg 5287821949aSmrgtypedef struct _DRI2ClientEvents { 5297821949aSmrg struct xorg_list reference_list; 5307821949aSmrg} DRI2ClientEventsRec, *DRI2ClientEventsPtr; 5317821949aSmrg 5327821949aSmrg#if HAS_DEVPRIVATEKEYREC 5337821949aSmrg 5347821949aSmrgstatic DevPrivateKeyRec DRI2ClientEventsPrivateKeyRec; 5357821949aSmrg#define DRI2ClientEventsPrivateKey (&DRI2ClientEventsPrivateKeyRec) 5367821949aSmrg 5377821949aSmrg#else 5387821949aSmrg 5397821949aSmrgstatic int DRI2ClientEventsPrivateKeyIndex; 5407821949aSmrgDevPrivateKey DRI2ClientEventsPrivateKey = &DRI2ClientEventsPrivateKeyIndex; 5417821949aSmrg 5427821949aSmrg#endif /* HAS_DEVPRIVATEKEYREC */ 5437821949aSmrg 5447821949aSmrg#define GetDRI2ClientEvents(pClient) ((DRI2ClientEventsPtr) \ 5457821949aSmrg dixLookupPrivate(&(pClient)->devPrivates, DRI2ClientEventsPrivateKey)) 5467821949aSmrg 5477821949aSmrgstatic int 5487821949aSmrgListAddDRI2ClientEvents(ClientPtr client, struct xorg_list *entry) 5497821949aSmrg{ 5507821949aSmrg DRI2ClientEventsPtr pClientPriv; 5517821949aSmrg pClientPriv = GetDRI2ClientEvents(client); 5527821949aSmrg 5537821949aSmrg if (!pClientPriv) { 5547821949aSmrg return BadAlloc; 5557821949aSmrg } 5567821949aSmrg 5577821949aSmrg xorg_list_add(entry, &pClientPriv->reference_list); 5587821949aSmrg return 0; 5597821949aSmrg} 5607821949aSmrg 5617821949aSmrgstatic void 5627821949aSmrgListDelDRI2ClientEvents(ClientPtr client, struct xorg_list *entry) 5637821949aSmrg{ 5647821949aSmrg DRI2ClientEventsPtr pClientPriv; 5657821949aSmrg pClientPriv = GetDRI2ClientEvents(client); 5667821949aSmrg 5677821949aSmrg if (!pClientPriv) { 5687821949aSmrg return; 5697821949aSmrg } 5707821949aSmrg xorg_list_del(entry); 5717821949aSmrg} 572de2362d3Smrg 573de2362d3Smrgstatic void 574de2362d3Smrgradeon_dri2_ref_buffer(BufferPtr buffer) 575de2362d3Smrg{ 576de2362d3Smrg struct dri2_buffer_priv *private = buffer->driverPrivate; 577de2362d3Smrg private->refcnt++; 578de2362d3Smrg} 579de2362d3Smrg 580de2362d3Smrgstatic void 581de2362d3Smrgradeon_dri2_unref_buffer(BufferPtr buffer) 582de2362d3Smrg{ 583de2362d3Smrg if (buffer) { 584de2362d3Smrg struct dri2_buffer_priv *private = buffer->driverPrivate; 585de2362d3Smrg radeon_dri2_destroy_buffer(&(private->pixmap->drawable), buffer); 586de2362d3Smrg } 587de2362d3Smrg} 588de2362d3Smrg 589de2362d3Smrgstatic void 590de2362d3Smrgradeon_dri2_client_state_changed(CallbackListPtr *ClientStateCallback, pointer data, pointer calldata) 591de2362d3Smrg{ 5927821949aSmrg DRI2ClientEventsPtr pClientEventsPriv; 5937821949aSmrg DRI2FrameEventPtr ref; 594de2362d3Smrg NewClientInfoRec *clientinfo = calldata; 595de2362d3Smrg ClientPtr pClient = clientinfo->client; 5967821949aSmrg pClientEventsPriv = GetDRI2ClientEvents(pClient); 597de2362d3Smrg 598de2362d3Smrg switch (pClient->clientState) { 5997821949aSmrg case ClientStateInitial: 6007821949aSmrg xorg_list_init(&pClientEventsPriv->reference_list); 6017821949aSmrg break; 6027821949aSmrg case ClientStateRunning: 6037821949aSmrg break; 6047821949aSmrg 605de2362d3Smrg case ClientStateRetained: 606de2362d3Smrg case ClientStateGone: 6077821949aSmrg if (pClientEventsPriv) { 6087821949aSmrg xorg_list_for_each_entry(ref, &pClientEventsPriv->reference_list, link) { 6097821949aSmrg ref->valid = FALSE; 6107821949aSmrg radeon_dri2_unref_buffer(ref->front); 6117821949aSmrg radeon_dri2_unref_buffer(ref->back); 6127821949aSmrg } 6137821949aSmrg } 614de2362d3Smrg break; 615de2362d3Smrg default: 616de2362d3Smrg break; 617de2362d3Smrg } 618de2362d3Smrg} 619de2362d3Smrg 6207821949aSmrgstatic int radeon_dri2_drawable_crtc(DrawablePtr pDraw) 621de2362d3Smrg{ 622de2362d3Smrg ScreenPtr pScreen = pDraw->pScreen; 623de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 6247821949aSmrg xf86CrtcPtr crtc; 6257821949aSmrg int crtc_id = -1; 6260d16fef4Smrg 6277821949aSmrg crtc = radeon_pick_best_crtc(pScrn, 6287821949aSmrg pDraw->x, 6297821949aSmrg pDraw->x + pDraw->width, 6307821949aSmrg pDraw->y, 6317821949aSmrg pDraw->y + pDraw->height); 6320d16fef4Smrg 6337821949aSmrg /* Make sure the CRTC is valid and this is the real front buffer */ 6347821949aSmrg if (crtc != NULL && !crtc->rotatedData) { 6357821949aSmrg crtc_id = drmmode_get_crtc_id(crtc); 6360d16fef4Smrg } 6377821949aSmrg return crtc_id; 638de2362d3Smrg} 639de2362d3Smrg 640de2362d3Smrgstatic Bool 6417821949aSmrgradeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client, 642de2362d3Smrg DrawablePtr draw, DRI2BufferPtr front, 643de2362d3Smrg DRI2BufferPtr back, DRI2SwapEventPtr func, 644de2362d3Smrg void *data, unsigned int target_msc) 645de2362d3Smrg{ 646de2362d3Smrg struct dri2_buffer_priv *back_priv; 6477821949aSmrg struct radeon_exa_pixmap_priv *exa_priv; 648de2362d3Smrg DRI2FrameEventPtr flip_info; 6497821949aSmrg 6507821949aSmrg /* Main crtc for this drawable shall finally deliver pageflip event. */ 6517821949aSmrg int ref_crtc_hw_id = radeon_dri2_drawable_crtc(draw); 652de2362d3Smrg 653de2362d3Smrg flip_info = calloc(1, sizeof(DRI2FrameEventRec)); 654de2362d3Smrg if (!flip_info) 655de2362d3Smrg return FALSE; 656de2362d3Smrg 657de2362d3Smrg flip_info->drawable_id = draw->id; 658de2362d3Smrg flip_info->client = client; 659de2362d3Smrg flip_info->type = DRI2_SWAP; 660de2362d3Smrg flip_info->event_complete = func; 661de2362d3Smrg flip_info->event_data = data; 662de2362d3Smrg flip_info->frame = target_msc; 663de2362d3Smrg 664de2362d3Smrg xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 665de2362d3Smrg "%s:%d fevent[%p]\n", __func__, __LINE__, flip_info); 666de2362d3Smrg 667de2362d3Smrg /* Page flip the full screen buffer */ 668de2362d3Smrg back_priv = back->driverPrivate; 6697821949aSmrg exa_priv = exaGetPixmapDriverPrivate(back_priv->pixmap); 6700d16fef4Smrg 6717821949aSmrg return radeon_do_pageflip(scrn, exa_priv->bo, flip_info, ref_crtc_hw_id); 672de2362d3Smrg} 673de2362d3Smrg 674de2362d3Smrgstatic Bool 675de2362d3Smrgupdate_front(DrawablePtr draw, DRI2BufferPtr front) 676de2362d3Smrg{ 6777821949aSmrg int r; 678de2362d3Smrg PixmapPtr pixmap; 679de2362d3Smrg struct dri2_buffer_priv *priv = front->driverPrivate; 6807821949aSmrg struct radeon_exa_pixmap_priv *driver_priv; 6817821949aSmrg 6827821949aSmrg if (draw->type == DRAWABLE_PIXMAP) 6837821949aSmrg pixmap = (PixmapPtr)draw; 6847821949aSmrg else 6857821949aSmrg pixmap = (*draw->pScreen->GetWindowPixmap)((WindowPtr)draw); 686de2362d3Smrg 687de2362d3Smrg pixmap->refcnt++; 688de2362d3Smrg 6897821949aSmrg exaMoveInPixmap(pixmap); 6907821949aSmrg driver_priv = exaGetPixmapDriverPrivate(pixmap); 6917821949aSmrg r = radeon_gem_get_kernel_name(driver_priv->bo, &front->name); 6927821949aSmrg if (r) { 693de2362d3Smrg (*draw->pScreen->DestroyPixmap)(pixmap); 694de2362d3Smrg return FALSE; 695de2362d3Smrg } 696de2362d3Smrg (*draw->pScreen->DestroyPixmap)(priv->pixmap); 697de2362d3Smrg front->pitch = pixmap->devKind; 698de2362d3Smrg front->cpp = pixmap->drawable.bitsPerPixel / 8; 699de2362d3Smrg priv->pixmap = pixmap; 700de2362d3Smrg 701de2362d3Smrg return TRUE; 702de2362d3Smrg} 703de2362d3Smrg 704de2362d3Smrgstatic Bool 705de2362d3Smrgcan_exchange(ScrnInfoPtr pScrn, DrawablePtr draw, 706de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back) 707de2362d3Smrg{ 708de2362d3Smrg struct dri2_buffer_priv *front_priv = front->driverPrivate; 709de2362d3Smrg struct dri2_buffer_priv *back_priv = back->driverPrivate; 710de2362d3Smrg PixmapPtr front_pixmap; 711de2362d3Smrg PixmapPtr back_pixmap = back_priv->pixmap; 712de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 713de2362d3Smrg int i; 714de2362d3Smrg 715de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 716de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 7177821949aSmrg if (crtc->enabled && crtc->rotatedData) 718de2362d3Smrg return FALSE; 719de2362d3Smrg } 720de2362d3Smrg 721de2362d3Smrg if (!update_front(draw, front)) 722de2362d3Smrg return FALSE; 723de2362d3Smrg 724de2362d3Smrg front_pixmap = front_priv->pixmap; 725de2362d3Smrg 726de2362d3Smrg if (front_pixmap->drawable.width != back_pixmap->drawable.width) 727de2362d3Smrg return FALSE; 728de2362d3Smrg 729de2362d3Smrg if (front_pixmap->drawable.height != back_pixmap->drawable.height) 730de2362d3Smrg return FALSE; 731de2362d3Smrg 732de2362d3Smrg if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) 733de2362d3Smrg return FALSE; 734de2362d3Smrg 735de2362d3Smrg if (front_pixmap->devKind != back_pixmap->devKind) 736de2362d3Smrg return FALSE; 737de2362d3Smrg 738de2362d3Smrg return TRUE; 739de2362d3Smrg} 740de2362d3Smrg 741de2362d3Smrgstatic Bool 742de2362d3Smrgcan_flip(ScrnInfoPtr pScrn, DrawablePtr draw, 743de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back) 744de2362d3Smrg{ 745de2362d3Smrg return draw->type == DRAWABLE_WINDOW && 7467821949aSmrg RADEONPTR(pScrn)->allowPageFlip && 747de2362d3Smrg pScrn->vtSema && 748de2362d3Smrg DRI2CanFlip(draw) && 749de2362d3Smrg can_exchange(pScrn, draw, front, back); 750de2362d3Smrg} 751de2362d3Smrg 752de2362d3Smrgstatic void 753de2362d3Smrgradeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back) 754de2362d3Smrg{ 755de2362d3Smrg struct dri2_buffer_priv *front_priv = front->driverPrivate; 756de2362d3Smrg struct dri2_buffer_priv *back_priv = back->driverPrivate; 7577821949aSmrg struct radeon_exa_pixmap_priv *front_radeon, *back_radeon; 758de2362d3Smrg ScreenPtr screen; 759de2362d3Smrg RADEONInfoPtr info; 7607821949aSmrg struct radeon_bo *bo; 761de2362d3Smrg int tmp; 762de2362d3Smrg 763de2362d3Smrg /* Swap BO names so DRI works */ 764de2362d3Smrg tmp = front->name; 765de2362d3Smrg front->name = back->name; 766de2362d3Smrg back->name = tmp; 767de2362d3Smrg 768de2362d3Smrg /* Swap pixmap bos */ 7697821949aSmrg front_radeon = exaGetPixmapDriverPrivate(front_priv->pixmap); 7707821949aSmrg back_radeon = exaGetPixmapDriverPrivate(back_priv->pixmap); 7717821949aSmrg bo = back_radeon->bo; 7727821949aSmrg back_radeon->bo = front_radeon->bo; 7737821949aSmrg front_radeon->bo = bo; 774de2362d3Smrg 775de2362d3Smrg /* Do we need to update the Screen? */ 776de2362d3Smrg screen = draw->pScreen; 777de2362d3Smrg info = RADEONPTR(xf86ScreenToScrn(screen)); 7787821949aSmrg if (front_radeon->bo == info->front_bo) { 779de2362d3Smrg radeon_bo_unref(info->front_bo); 7807821949aSmrg info->front_bo = back_radeon->bo; 7817821949aSmrg radeon_bo_ref(info->front_bo); 7827821949aSmrg front_radeon = exaGetPixmapDriverPrivate(screen->GetScreenPixmap(screen)); 7837821949aSmrg front_radeon->bo = bo; 784de2362d3Smrg } 785de2362d3Smrg} 786de2362d3Smrg 7877821949aSmrgvoid radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, 7887821949aSmrg unsigned int tv_usec, void *event_data) 789de2362d3Smrg{ 790de2362d3Smrg DRI2FrameEventPtr event = event_data; 791de2362d3Smrg DrawablePtr drawable; 7927821949aSmrg ScreenPtr screen; 7937821949aSmrg ScrnInfoPtr scrn; 794de2362d3Smrg int status; 795de2362d3Smrg int swap_type; 796de2362d3Smrg BoxRec box; 797de2362d3Smrg RegionRec region; 798de2362d3Smrg 7997821949aSmrg if (!event->valid) 8007821949aSmrg goto cleanup; 8017821949aSmrg 802de2362d3Smrg status = dixLookupDrawable(&drawable, event->drawable_id, serverClient, 803de2362d3Smrg M_ANY, DixWriteAccess); 804de2362d3Smrg if (status != Success) 805de2362d3Smrg goto cleanup; 806de2362d3Smrg 8077821949aSmrg screen = drawable->pScreen; 8087821949aSmrg scrn = xf86ScreenToScrn(screen); 809de2362d3Smrg 810de2362d3Smrg switch (event->type) { 811de2362d3Smrg case DRI2_FLIP: 812de2362d3Smrg if (can_flip(scrn, drawable, event->front, event->back) && 8137821949aSmrg radeon_dri2_schedule_flip(scrn, 814de2362d3Smrg event->client, 815de2362d3Smrg drawable, 816de2362d3Smrg event->front, 817de2362d3Smrg event->back, 818de2362d3Smrg event->event_complete, 819de2362d3Smrg event->event_data, 820de2362d3Smrg event->frame)) { 821de2362d3Smrg radeon_dri2_exchange_buffers(drawable, event->front, event->back); 822de2362d3Smrg break; 823de2362d3Smrg } 824de2362d3Smrg /* else fall through to exchange/blit */ 825de2362d3Smrg case DRI2_SWAP: 826de2362d3Smrg if (DRI2CanExchange(drawable) && 827de2362d3Smrg can_exchange(scrn, drawable, event->front, event->back)) { 828de2362d3Smrg radeon_dri2_exchange_buffers(drawable, event->front, event->back); 829de2362d3Smrg swap_type = DRI2_EXCHANGE_COMPLETE; 830de2362d3Smrg } else { 831de2362d3Smrg box.x1 = 0; 832de2362d3Smrg box.y1 = 0; 833de2362d3Smrg box.x2 = drawable->width; 834de2362d3Smrg box.y2 = drawable->height; 835de2362d3Smrg REGION_INIT(pScreen, ®ion, &box, 0); 836de2362d3Smrg radeon_dri2_copy_region(drawable, ®ion, event->front, event->back); 837de2362d3Smrg swap_type = DRI2_BLIT_COMPLETE; 838de2362d3Smrg } 839de2362d3Smrg 8407821949aSmrg DRI2SwapComplete(event->client, drawable, frame, tv_sec, tv_usec, 8417821949aSmrg swap_type, event->event_complete, event->event_data); 842de2362d3Smrg 843de2362d3Smrg break; 844de2362d3Smrg case DRI2_WAITMSC: 8457821949aSmrg DRI2WaitMSCComplete(event->client, drawable, frame, tv_sec, tv_usec); 846de2362d3Smrg break; 847de2362d3Smrg default: 848de2362d3Smrg /* Unknown type */ 849de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 850de2362d3Smrg "%s: unknown vblank event received\n", __func__); 851de2362d3Smrg break; 852de2362d3Smrg } 853de2362d3Smrg 854de2362d3Smrgcleanup: 8557821949aSmrg if (event->valid) { 8567821949aSmrg radeon_dri2_unref_buffer(event->front); 8577821949aSmrg radeon_dri2_unref_buffer(event->back); 8587821949aSmrg ListDelDRI2ClientEvents(event->client, &event->link); 8597821949aSmrg } 8607821949aSmrg free(event); 861de2362d3Smrg} 862de2362d3Smrg 8637821949aSmrgstatic drmVBlankSeqType populate_vbl_request_type(RADEONInfoPtr info, int crtc) 864de2362d3Smrg{ 865de2362d3Smrg drmVBlankSeqType type = 0; 866de2362d3Smrg 8677821949aSmrg if (crtc == 1) 868de2362d3Smrg type |= DRM_VBLANK_SECONDARY; 8697821949aSmrg else if (crtc > 1) 870de2362d3Smrg#ifdef DRM_VBLANK_HIGH_CRTC_SHIFT 8717821949aSmrg type |= (crtc << DRM_VBLANK_HIGH_CRTC_SHIFT) & 872de2362d3Smrg DRM_VBLANK_HIGH_CRTC_MASK; 873de2362d3Smrg#else 874de2362d3Smrg ErrorF("radeon driver bug: %s called for CRTC %d > 1, but " 875de2362d3Smrg "DRM_VBLANK_HIGH_CRTC_MASK not defined at build time\n", 8767821949aSmrg __func__, crtc); 877de2362d3Smrg#endif 878de2362d3Smrg 879de2362d3Smrg return type; 880de2362d3Smrg} 881de2362d3Smrg 882de2362d3Smrg/* 8837821949aSmrg * Get current frame count and frame count timestamp, based on drawable's 8847821949aSmrg * crtc. 885de2362d3Smrg */ 886de2362d3Smrgstatic int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 887de2362d3Smrg{ 8887821949aSmrg ScreenPtr screen = draw->pScreen; 8897821949aSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 8907821949aSmrg RADEONInfoPtr info = RADEONPTR(scrn); 8917821949aSmrg drmVBlank vbl; 8927821949aSmrg int ret; 8937821949aSmrg int crtc = radeon_dri2_drawable_crtc(draw); 894de2362d3Smrg 895de2362d3Smrg /* Drawable not displayed, make up a value */ 8967821949aSmrg if (crtc == -1) { 897de2362d3Smrg *ust = 0; 898de2362d3Smrg *msc = 0; 899de2362d3Smrg return TRUE; 900de2362d3Smrg } 9017821949aSmrg vbl.request.type = DRM_VBLANK_RELATIVE; 9027821949aSmrg vbl.request.type |= populate_vbl_request_type(info, crtc); 9037821949aSmrg vbl.request.sequence = 0; 904de2362d3Smrg 9057821949aSmrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 906de2362d3Smrg if (ret) { 9077821949aSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 9087821949aSmrg "get vblank counter failed: %s\n", strerror(errno)); 9097821949aSmrg return FALSE; 910de2362d3Smrg } 911de2362d3Smrg 9127821949aSmrg *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec; 9137821949aSmrg *msc = vbl.reply.sequence; 9147821949aSmrg 9157821949aSmrg return TRUE; 916de2362d3Smrg} 917de2362d3Smrg 918de2362d3Smrg/* 919de2362d3Smrg * Request a DRM event when the requested conditions will be satisfied. 920de2362d3Smrg * 921de2362d3Smrg * We need to handle the event and ask the server to wake up the client when 922de2362d3Smrg * we receive it. 923de2362d3Smrg */ 924de2362d3Smrgstatic int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, 925de2362d3Smrg CARD64 target_msc, CARD64 divisor, 926de2362d3Smrg CARD64 remainder) 927de2362d3Smrg{ 928de2362d3Smrg ScreenPtr screen = draw->pScreen; 929de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 930de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 931de2362d3Smrg DRI2FrameEventPtr wait_info = NULL; 932de2362d3Smrg drmVBlank vbl; 9337821949aSmrg int ret, crtc = radeon_dri2_drawable_crtc(draw); 934de2362d3Smrg CARD64 current_msc; 935de2362d3Smrg 936de2362d3Smrg /* Truncate to match kernel interfaces; means occasional overflow 937de2362d3Smrg * misses, but that's generally not a big deal */ 938de2362d3Smrg target_msc &= 0xffffffff; 939de2362d3Smrg divisor &= 0xffffffff; 940de2362d3Smrg remainder &= 0xffffffff; 941de2362d3Smrg 942de2362d3Smrg /* Drawable not visible, return immediately */ 9437821949aSmrg if (crtc == -1) 944de2362d3Smrg goto out_complete; 945de2362d3Smrg 946de2362d3Smrg wait_info = calloc(1, sizeof(DRI2FrameEventRec)); 947de2362d3Smrg if (!wait_info) 948de2362d3Smrg goto out_complete; 949de2362d3Smrg 950de2362d3Smrg wait_info->drawable_id = draw->id; 951de2362d3Smrg wait_info->client = client; 952de2362d3Smrg wait_info->type = DRI2_WAITMSC; 9537821949aSmrg wait_info->valid = TRUE; 954de2362d3Smrg 9557821949aSmrg if (ListAddDRI2ClientEvents(client, &wait_info->link)) { 9567821949aSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 9577821949aSmrg "add events to client private failed.\n"); 9587821949aSmrg free(wait_info); 9597821949aSmrg wait_info = NULL; 9607821949aSmrg goto out_complete; 961de2362d3Smrg } 962de2362d3Smrg 963de2362d3Smrg /* Get current count */ 964de2362d3Smrg vbl.request.type = DRM_VBLANK_RELATIVE; 9657821949aSmrg vbl.request.type |= populate_vbl_request_type(info, crtc); 966de2362d3Smrg vbl.request.sequence = 0; 967de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 968de2362d3Smrg if (ret) { 969de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 970de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 971de2362d3Smrg goto out_complete; 972de2362d3Smrg } 973de2362d3Smrg 9747821949aSmrg current_msc = vbl.reply.sequence; 9750d16fef4Smrg 976de2362d3Smrg /* 977de2362d3Smrg * If divisor is zero, or current_msc is smaller than target_msc, 978de2362d3Smrg * we just need to make sure target_msc passes before waking up the 979de2362d3Smrg * client. 980de2362d3Smrg */ 981de2362d3Smrg if (divisor == 0 || current_msc < target_msc) { 982de2362d3Smrg /* If target_msc already reached or passed, set it to 983de2362d3Smrg * current_msc to ensure we return a reasonable value back 984de2362d3Smrg * to the caller. This keeps the client from continually 985de2362d3Smrg * sending us MSC targets from the past by forcibly updating 986de2362d3Smrg * their count on this call. 987de2362d3Smrg */ 988de2362d3Smrg if (current_msc >= target_msc) 989de2362d3Smrg target_msc = current_msc; 990de2362d3Smrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 9917821949aSmrg vbl.request.type |= populate_vbl_request_type(info, crtc); 9927821949aSmrg vbl.request.sequence = target_msc; 9937821949aSmrg vbl.request.signal = (unsigned long)wait_info; 994de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 995de2362d3Smrg if (ret) { 996de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 997de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 998de2362d3Smrg goto out_complete; 999de2362d3Smrg } 1000de2362d3Smrg 10017821949aSmrg wait_info->frame = vbl.reply.sequence; 1002de2362d3Smrg DRI2BlockClient(client, draw); 1003de2362d3Smrg return TRUE; 1004de2362d3Smrg } 1005de2362d3Smrg 1006de2362d3Smrg /* 1007de2362d3Smrg * If we get here, target_msc has already passed or we don't have one, 1008de2362d3Smrg * so we queue an event that will satisfy the divisor/remainder equation. 1009de2362d3Smrg */ 1010de2362d3Smrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 10117821949aSmrg vbl.request.type |= populate_vbl_request_type(info, crtc); 1012de2362d3Smrg 1013de2362d3Smrg vbl.request.sequence = current_msc - (current_msc % divisor) + 10147821949aSmrg remainder; 1015de2362d3Smrg 1016de2362d3Smrg /* 1017de2362d3Smrg * If calculated remainder is larger than requested remainder, 1018de2362d3Smrg * it means we've passed the last point where 1019de2362d3Smrg * seq % divisor == remainder, so we need to wait for the next time 1020de2362d3Smrg * that will happen. 1021de2362d3Smrg */ 1022de2362d3Smrg if ((current_msc % divisor) >= remainder) 1023de2362d3Smrg vbl.request.sequence += divisor; 1024de2362d3Smrg 10257821949aSmrg vbl.request.signal = (unsigned long)wait_info; 1026de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1027de2362d3Smrg if (ret) { 1028de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1029de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1030de2362d3Smrg goto out_complete; 1031de2362d3Smrg } 1032de2362d3Smrg 10337821949aSmrg wait_info->frame = vbl.reply.sequence; 1034de2362d3Smrg DRI2BlockClient(client, draw); 1035de2362d3Smrg 1036de2362d3Smrg return TRUE; 1037de2362d3Smrg 1038de2362d3Smrgout_complete: 10397821949aSmrg if (wait_info) { 10407821949aSmrg ListDelDRI2ClientEvents(wait_info->client, &wait_info->link); 10417821949aSmrg free(wait_info); 10427821949aSmrg } 10437821949aSmrg DRI2WaitMSCComplete(client, draw, target_msc, 0, 0); 1044de2362d3Smrg return TRUE; 1045de2362d3Smrg} 1046de2362d3Smrg 10477821949aSmrgvoid radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, 10487821949aSmrg unsigned int tv_usec, void *event_data) 10497821949aSmrg{ 10507821949aSmrg DRI2FrameEventPtr flip = event_data; 10517821949aSmrg DrawablePtr drawable; 10527821949aSmrg ScreenPtr screen; 10537821949aSmrg ScrnInfoPtr scrn; 10547821949aSmrg int status; 10557821949aSmrg PixmapPtr pixmap; 10567821949aSmrg 10577821949aSmrg status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient, 10587821949aSmrg M_ANY, DixWriteAccess); 10597821949aSmrg if (status != Success) { 10607821949aSmrg free(flip); 10617821949aSmrg return; 10627821949aSmrg } 10637821949aSmrg 10647821949aSmrg screen = drawable->pScreen; 10657821949aSmrg scrn = xf86ScreenToScrn(screen); 10667821949aSmrg 10677821949aSmrg pixmap = screen->GetScreenPixmap(screen); 10687821949aSmrg xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 10697821949aSmrg "%s:%d fevent[%p] width %d pitch %d (/4 %d)\n", 10707821949aSmrg __func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4); 10717821949aSmrg 10727821949aSmrg /* We assume our flips arrive in order, so we don't check the frame */ 10737821949aSmrg switch (flip->type) { 10747821949aSmrg case DRI2_SWAP: 10757821949aSmrg /* Check for too small vblank count of pageflip completion, taking wraparound 10767821949aSmrg * into account. This usually means some defective kms pageflip completion, 10777821949aSmrg * causing wrong (msc, ust) return values and possible visual corruption. 10787821949aSmrg */ 10797821949aSmrg if ((frame < flip->frame) && (flip->frame - frame < 5)) { 10807821949aSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 10817821949aSmrg "%s: Pageflip completion event has impossible msc %d < target_msc %d\n", 10827821949aSmrg __func__, frame, flip->frame); 10837821949aSmrg /* All-Zero values signal failure of (msc, ust) timestamping to client. */ 10847821949aSmrg frame = tv_sec = tv_usec = 0; 10857821949aSmrg } 10867821949aSmrg 10877821949aSmrg DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec, 10887821949aSmrg DRI2_FLIP_COMPLETE, flip->event_complete, 10897821949aSmrg flip->event_data); 10907821949aSmrg break; 10917821949aSmrg default: 10927821949aSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__); 10937821949aSmrg /* Unknown type */ 10947821949aSmrg break; 10957821949aSmrg } 10967821949aSmrg 10977821949aSmrg free(flip); 10987821949aSmrg} 10997821949aSmrg 1100de2362d3Smrg/* 1101de2362d3Smrg * ScheduleSwap is responsible for requesting a DRM vblank event for the 1102de2362d3Smrg * appropriate frame. 1103de2362d3Smrg * 1104de2362d3Smrg * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 1105de2362d3Smrg * the vblank requested can simply be the last queued swap frame + the swap 1106de2362d3Smrg * interval for the drawable. 1107de2362d3Smrg * 1108de2362d3Smrg * In the case of a page flip, we request an event for the last queued swap 1109de2362d3Smrg * frame + swap interval - 1, since we'll need to queue the flip for the frame 1110de2362d3Smrg * immediately following the received event. 1111de2362d3Smrg * 1112de2362d3Smrg * The client will be blocked if it tries to perform further GL commands 1113de2362d3Smrg * after queueing a swap, though in the Intel case after queueing a flip, the 1114de2362d3Smrg * client is free to queue more commands; they'll block in the kernel if 1115de2362d3Smrg * they access buffers busy with the flip. 1116de2362d3Smrg * 1117de2362d3Smrg * When the swap is complete, the driver should call into the server so it 1118de2362d3Smrg * can send any swap complete events that have been requested. 1119de2362d3Smrg */ 1120de2362d3Smrgstatic int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, 1121de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back, 1122de2362d3Smrg CARD64 *target_msc, CARD64 divisor, 1123de2362d3Smrg CARD64 remainder, DRI2SwapEventPtr func, 1124de2362d3Smrg void *data) 1125de2362d3Smrg{ 1126de2362d3Smrg ScreenPtr screen = draw->pScreen; 1127de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1128de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1129de2362d3Smrg drmVBlank vbl; 11307821949aSmrg int ret, crtc= radeon_dri2_drawable_crtc(draw), flip = 0; 1131de2362d3Smrg DRI2FrameEventPtr swap_info = NULL; 11327821949aSmrg enum DRI2FrameEventType swap_type = DRI2_SWAP; 1133de2362d3Smrg CARD64 current_msc; 1134de2362d3Smrg BoxRec box; 1135de2362d3Smrg RegionRec region; 1136de2362d3Smrg 1137de2362d3Smrg /* Truncate to match kernel interfaces; means occasional overflow 1138de2362d3Smrg * misses, but that's generally not a big deal */ 1139de2362d3Smrg *target_msc &= 0xffffffff; 1140de2362d3Smrg divisor &= 0xffffffff; 1141de2362d3Smrg remainder &= 0xffffffff; 1142de2362d3Smrg 1143de2362d3Smrg /* radeon_dri2_frame_event_handler will get called some unknown time in the 1144de2362d3Smrg * future with these buffers. Take a reference to ensure that they won't 1145de2362d3Smrg * get destroyed before then. 1146de2362d3Smrg */ 1147de2362d3Smrg radeon_dri2_ref_buffer(front); 1148de2362d3Smrg radeon_dri2_ref_buffer(back); 1149de2362d3Smrg 11507821949aSmrg /* Drawable not displayed... just complete the swap */ 11517821949aSmrg if (crtc == -1) 1152de2362d3Smrg goto blit_fallback; 1153de2362d3Smrg 1154de2362d3Smrg swap_info = calloc(1, sizeof(DRI2FrameEventRec)); 1155de2362d3Smrg if (!swap_info) 1156de2362d3Smrg goto blit_fallback; 1157de2362d3Smrg 1158de2362d3Smrg swap_info->drawable_id = draw->id; 1159de2362d3Smrg swap_info->client = client; 1160de2362d3Smrg swap_info->event_complete = func; 1161de2362d3Smrg swap_info->event_data = data; 1162de2362d3Smrg swap_info->front = front; 1163de2362d3Smrg swap_info->back = back; 11647821949aSmrg swap_info->valid = TRUE; 11657821949aSmrg if (ListAddDRI2ClientEvents(client, &swap_info->link)) { 1166de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 11677821949aSmrg "add events to client private failed.\n"); 11687821949aSmrg free(swap_info); 11697821949aSmrg swap_info = NULL; 1170de2362d3Smrg goto blit_fallback; 1171de2362d3Smrg } 1172de2362d3Smrg 1173de2362d3Smrg /* Get current count */ 1174de2362d3Smrg vbl.request.type = DRM_VBLANK_RELATIVE; 11757821949aSmrg vbl.request.type |= populate_vbl_request_type(info, crtc); 1176de2362d3Smrg vbl.request.sequence = 0; 1177de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1178de2362d3Smrg if (ret) { 1179de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1180de2362d3Smrg "first get vblank counter failed: %s\n", 1181de2362d3Smrg strerror(errno)); 11827821949aSmrg goto blit_fallback; 1183de2362d3Smrg } 1184de2362d3Smrg 11857821949aSmrg current_msc = vbl.reply.sequence; 1186de2362d3Smrg 1187de2362d3Smrg /* Flips need to be submitted one frame before */ 1188de2362d3Smrg if (can_flip(scrn, draw, front, back)) { 11897821949aSmrg swap_type = DRI2_FLIP; 1190de2362d3Smrg flip = 1; 1191de2362d3Smrg } 1192de2362d3Smrg 11937821949aSmrg swap_info->type = swap_type; 11947821949aSmrg 11957821949aSmrg /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP. 1196de2362d3Smrg * Do it early, so handling of different timing constraints 1197de2362d3Smrg * for divisor, remainder and msc vs. target_msc works. 1198de2362d3Smrg */ 1199de2362d3Smrg if (*target_msc > 0) 1200de2362d3Smrg *target_msc -= flip; 1201de2362d3Smrg 1202de2362d3Smrg /* 1203de2362d3Smrg * If divisor is zero, or current_msc is smaller than target_msc 1204de2362d3Smrg * we just need to make sure target_msc passes before initiating 1205de2362d3Smrg * the swap. 1206de2362d3Smrg */ 1207de2362d3Smrg if (divisor == 0 || current_msc < *target_msc) { 1208de2362d3Smrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1209de2362d3Smrg /* If non-pageflipping, but blitting/exchanging, we need to use 1210de2362d3Smrg * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later 1211de2362d3Smrg * on. 1212de2362d3Smrg */ 1213de2362d3Smrg if (flip == 0) 1214de2362d3Smrg vbl.request.type |= DRM_VBLANK_NEXTONMISS; 12157821949aSmrg vbl.request.type |= populate_vbl_request_type(info, crtc); 1216de2362d3Smrg 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 makes swap_interval logic more robust. 1220de2362d3Smrg */ 1221de2362d3Smrg if (current_msc >= *target_msc) 1222de2362d3Smrg *target_msc = current_msc; 1223de2362d3Smrg 12247821949aSmrg vbl.request.sequence = *target_msc; 12257821949aSmrg vbl.request.signal = (unsigned long)swap_info; 1226de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1227de2362d3Smrg if (ret) { 1228de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1229de2362d3Smrg "divisor 0 get vblank counter failed: %s\n", 1230de2362d3Smrg strerror(errno)); 12317821949aSmrg goto blit_fallback; 1232de2362d3Smrg } 1233de2362d3Smrg 12347821949aSmrg *target_msc = vbl.reply.sequence + flip; 1235de2362d3Smrg swap_info->frame = *target_msc; 1236de2362d3Smrg 1237de2362d3Smrg return TRUE; 1238de2362d3Smrg } 1239de2362d3Smrg 1240de2362d3Smrg /* 1241de2362d3Smrg * If we get here, target_msc has already passed or we don't have one, 1242de2362d3Smrg * and we need to queue an event that will satisfy the divisor/remainder 1243de2362d3Smrg * equation. 1244de2362d3Smrg */ 1245de2362d3Smrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1246de2362d3Smrg if (flip == 0) 1247de2362d3Smrg vbl.request.type |= DRM_VBLANK_NEXTONMISS; 12487821949aSmrg vbl.request.type |= populate_vbl_request_type(info, crtc); 1249de2362d3Smrg 1250de2362d3Smrg vbl.request.sequence = current_msc - (current_msc % divisor) + 12517821949aSmrg remainder; 1252de2362d3Smrg 1253de2362d3Smrg /* 1254de2362d3Smrg * If the calculated deadline vbl.request.sequence is smaller than 1255de2362d3Smrg * or equal to current_msc, it means we've passed the last point 1256de2362d3Smrg * when effective onset frame seq could satisfy 1257de2362d3Smrg * seq % divisor == remainder, so we need to wait for the next time 1258de2362d3Smrg * this will happen. 1259de2362d3Smrg 1260de2362d3Smrg * This comparison takes the 1 frame swap delay in pageflipping mode 1261de2362d3Smrg * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay 1262de2362d3Smrg * if we are blitting/exchanging instead of flipping. 1263de2362d3Smrg */ 1264de2362d3Smrg if (vbl.request.sequence <= current_msc) 1265de2362d3Smrg vbl.request.sequence += divisor; 1266de2362d3Smrg 1267de2362d3Smrg /* Account for 1 frame extra pageflip delay if flip > 0 */ 1268de2362d3Smrg vbl.request.sequence -= flip; 1269de2362d3Smrg 12707821949aSmrg vbl.request.signal = (unsigned long)swap_info; 1271de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1272de2362d3Smrg if (ret) { 1273de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1274de2362d3Smrg "final get vblank counter failed: %s\n", 1275de2362d3Smrg strerror(errno)); 12767821949aSmrg goto blit_fallback; 1277de2362d3Smrg } 1278de2362d3Smrg 1279de2362d3Smrg /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ 12807821949aSmrg *target_msc = vbl.reply.sequence + flip; 1281de2362d3Smrg swap_info->frame = *target_msc; 1282de2362d3Smrg 1283de2362d3Smrg return TRUE; 1284de2362d3Smrg 1285de2362d3Smrgblit_fallback: 12867821949aSmrg box.x1 = 0; 12877821949aSmrg box.y1 = 0; 12887821949aSmrg box.x2 = draw->width; 12897821949aSmrg box.y2 = draw->height; 12907821949aSmrg REGION_INIT(pScreen, ®ion, &box, 0); 1291de2362d3Smrg 12927821949aSmrg radeon_dri2_copy_region(draw, ®ion, front, back); 1293de2362d3Smrg 12947821949aSmrg DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); 12957821949aSmrg if (swap_info) { 12967821949aSmrg ListDelDRI2ClientEvents(swap_info->client, &swap_info->link); 12977821949aSmrg free(swap_info); 12980d16fef4Smrg } 1299de2362d3Smrg 13007821949aSmrg radeon_dri2_unref_buffer(front); 13017821949aSmrg radeon_dri2_unref_buffer(back); 13027821949aSmrg 1303de2362d3Smrg *target_msc = 0; /* offscreen, so zero out target vblank count */ 1304de2362d3Smrg return TRUE; 1305de2362d3Smrg} 1306de2362d3Smrg 13077821949aSmrg#endif /* USE_DRI2_SCHEDULING */ 13087821949aSmrg 1309de2362d3Smrg 1310de2362d3SmrgBool 1311de2362d3Smrgradeon_dri2_screen_init(ScreenPtr pScreen) 1312de2362d3Smrg{ 1313de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1314de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1315de2362d3Smrg DRI2InfoRec dri2_info = { 0 }; 13167821949aSmrg#ifdef USE_DRI2_SCHEDULING 13177821949aSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1318de2362d3Smrg const char *driverNames[2]; 1319de2362d3Smrg Bool scheduling_works = TRUE; 13207821949aSmrg#endif 1321de2362d3Smrg 13227821949aSmrg if (!info->useEXA) { 13237821949aSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 requires EXA\n"); 1324de2362d3Smrg return FALSE; 13257821949aSmrg } 1326de2362d3Smrg 1327de2362d3Smrg info->dri2.device_name = drmGetDeviceNameFromFd(info->dri2.drm_fd); 1328de2362d3Smrg 13297821949aSmrg if ( (info->ChipFamily >= CHIP_FAMILY_R600) ) { 1330de2362d3Smrg dri2_info.driverName = R600_DRIVER_NAME; 1331de2362d3Smrg } else if ( (info->ChipFamily >= CHIP_FAMILY_R300) ) { 1332de2362d3Smrg dri2_info.driverName = R300_DRIVER_NAME; 1333de2362d3Smrg } else if ( info->ChipFamily >= CHIP_FAMILY_R200 ) { 1334de2362d3Smrg dri2_info.driverName = R200_DRIVER_NAME; 1335de2362d3Smrg } else { 1336de2362d3Smrg dri2_info.driverName = RADEON_DRIVER_NAME; 1337de2362d3Smrg } 1338de2362d3Smrg dri2_info.fd = info->dri2.drm_fd; 1339de2362d3Smrg dri2_info.deviceName = info->dri2.device_name; 13407821949aSmrg#ifndef USE_DRI2_1_1_0 13417821949aSmrg dri2_info.version = 1; 13427821949aSmrg dri2_info.CreateBuffers = radeon_dri2_create_buffers; 13437821949aSmrg dri2_info.DestroyBuffers = radeon_dri2_destroy_buffers; 13447821949aSmrg#else 1345de2362d3Smrg dri2_info.version = DRI2INFOREC_VERSION; 1346de2362d3Smrg dri2_info.CreateBuffer = radeon_dri2_create_buffer; 1347de2362d3Smrg dri2_info.DestroyBuffer = radeon_dri2_destroy_buffer; 13487821949aSmrg#endif 1349de2362d3Smrg dri2_info.CopyRegion = radeon_dri2_copy_region; 1350de2362d3Smrg 13517821949aSmrg#ifdef USE_DRI2_SCHEDULING 13527821949aSmrg if (info->dri->pKernelDRMVersion->version_minor < 4) { 1353de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for " 1354de2362d3Smrg "sync extension\n"); 1355de2362d3Smrg scheduling_works = FALSE; 1356de2362d3Smrg } 1357de2362d3Smrg 13587821949aSmrg if (scheduling_works && info->drmmode.mode_res->count_crtcs > 2) { 1359de2362d3Smrg#ifdef DRM_CAP_VBLANK_HIGH_CRTC 1360de2362d3Smrg uint64_t cap_value; 1361de2362d3Smrg 1362de2362d3Smrg if (drmGetCap(info->dri2.drm_fd, DRM_CAP_VBLANK_HIGH_CRTC, &cap_value)) { 1363de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel " 1364de2362d3Smrg "for VBLANKs on CRTC > 1\n"); 1365de2362d3Smrg scheduling_works = FALSE; 1366de2362d3Smrg } else if (!cap_value) { 1367de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Your kernel does not " 1368de2362d3Smrg "handle VBLANKs on CRTC > 1\n"); 1369de2362d3Smrg scheduling_works = FALSE; 1370de2362d3Smrg } 1371de2362d3Smrg#else 1372de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need to rebuild against a " 1373de2362d3Smrg "newer libdrm to handle VBLANKs on CRTC > 1\n"); 1374de2362d3Smrg scheduling_works = FALSE; 1375de2362d3Smrg#endif 1376de2362d3Smrg } 1377de2362d3Smrg 1378de2362d3Smrg if (scheduling_works) { 1379de2362d3Smrg dri2_info.version = 4; 1380de2362d3Smrg dri2_info.ScheduleSwap = radeon_dri2_schedule_swap; 1381de2362d3Smrg dri2_info.GetMSC = radeon_dri2_get_msc; 1382de2362d3Smrg dri2_info.ScheduleWaitMSC = radeon_dri2_schedule_wait_msc; 1383de2362d3Smrg dri2_info.numDrivers = RADEON_ARRAY_SIZE(driverNames); 1384de2362d3Smrg dri2_info.driverNames = driverNames; 13857821949aSmrg driverNames[0] = driverNames[1] = dri2_info.driverName; 13867821949aSmrg 13877821949aSmrg if (pRADEONEnt->dri2_info_cnt == 0) { 13887821949aSmrg#if HAS_DIXREGISTERPRIVATEKEY 13897821949aSmrg if (!dixRegisterPrivateKey(DRI2ClientEventsPrivateKey, 13907821949aSmrg PRIVATE_CLIENT, sizeof(DRI2ClientEventsRec))) { 13917821949aSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 registering " 13927821949aSmrg "private key to client failed\n"); 13937821949aSmrg return FALSE; 13947821949aSmrg } 13957821949aSmrg#else 13967821949aSmrg if (!dixRequestPrivate(DRI2ClientEventsPrivateKey, 13977821949aSmrg sizeof(DRI2ClientEventsRec))) { 13987821949aSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 requesting " 13997821949aSmrg "private key to client failed\n"); 1400de2362d3Smrg return FALSE; 1401de2362d3Smrg } 14027821949aSmrg#endif 1403de2362d3Smrg 1404de2362d3Smrg AddCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); 1405de2362d3Smrg } 1406de2362d3Smrg 14077821949aSmrg pRADEONEnt->dri2_info_cnt++; 1408de2362d3Smrg } 1409de2362d3Smrg#endif 1410de2362d3Smrg 1411de2362d3Smrg info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info); 1412de2362d3Smrg return info->dri2.enabled; 1413de2362d3Smrg} 1414de2362d3Smrg 1415de2362d3Smrgvoid radeon_dri2_close_screen(ScreenPtr pScreen) 1416de2362d3Smrg{ 1417de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1418de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 14197821949aSmrg#ifdef USE_DRI2_SCHEDULING 14207821949aSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1421de2362d3Smrg 14227821949aSmrg if (--pRADEONEnt->dri2_info_cnt == 0) 1423de2362d3Smrg DeleteCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); 14247821949aSmrg#endif 1425de2362d3Smrg DRI2CloseScreen(pScreen); 1426de2362d3Smrg drmFree(info->dri2.device_name); 1427de2362d3Smrg} 1428de2362d3Smrg 14297821949aSmrg#endif 1430