1428d7b3dSmrg/************************************************************************** 2428d7b3dSmrg 3428d7b3dSmrgCopyright 2001 VA Linux Systems Inc., Fremont, California. 4428d7b3dSmrgCopyright © 2002 by David Dawes 5428d7b3dSmrg 6428d7b3dSmrgAll Rights Reserved. 7428d7b3dSmrg 8428d7b3dSmrgPermission is hereby granted, free of charge, to any person obtaining a 9428d7b3dSmrgcopy of this software and associated documentation files (the "Software"), 10428d7b3dSmrgto deal in the Software without restriction, including without limitation 11428d7b3dSmrgon the rights to use, copy, modify, merge, publish, distribute, sub 12428d7b3dSmrglicense, and/or sell copies of the Software, and to permit persons to whom 13428d7b3dSmrgthe Software is furnished to do so, subject to the following conditions: 14428d7b3dSmrg 15428d7b3dSmrgThe above copyright notice and this permission notice (including the next 16428d7b3dSmrgparagraph) shall be included in all copies or substantial portions of the 17428d7b3dSmrgSoftware. 18428d7b3dSmrg 19428d7b3dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20428d7b3dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21428d7b3dSmrgFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22428d7b3dSmrgATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 23428d7b3dSmrgDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24428d7b3dSmrgOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25428d7b3dSmrgUSE OR OTHER DEALINGS IN THE SOFTWARE. 26428d7b3dSmrg 27428d7b3dSmrg**************************************************************************/ 28428d7b3dSmrg 29428d7b3dSmrg/* 30428d7b3dSmrg * Authors: Jeff Hartmann <jhartmann@valinux.com> 31428d7b3dSmrg * David Dawes <dawes@xfree86.org> 32428d7b3dSmrg * Keith Whitwell <keith@tungstengraphics.com> 33428d7b3dSmrg */ 34428d7b3dSmrg 35428d7b3dSmrg#ifdef HAVE_CONFIG_H 36428d7b3dSmrg#include "config.h" 37428d7b3dSmrg#endif 38428d7b3dSmrg 39428d7b3dSmrg#include <stdio.h> 40428d7b3dSmrg#include <string.h> 41428d7b3dSmrg#include <assert.h> 42428d7b3dSmrg#include <sys/types.h> 43428d7b3dSmrg#include <sys/stat.h> 44428d7b3dSmrg#include <sys/ioctl.h> 45428d7b3dSmrg#include <unistd.h> 46428d7b3dSmrg#include <fcntl.h> 47428d7b3dSmrg#include <sys/time.h> 48428d7b3dSmrg#include <time.h> 49428d7b3dSmrg#include <errno.h> 50428d7b3dSmrg 51428d7b3dSmrg#include "xorg-server.h" 52428d7b3dSmrg#include "xf86.h" 53428d7b3dSmrg#include "xf86_OSproc.h" 54428d7b3dSmrg 55428d7b3dSmrg#include "xf86Pci.h" 56428d7b3dSmrg#include "xf86drm.h" 57428d7b3dSmrg 58428d7b3dSmrg#include "windowstr.h" 59428d7b3dSmrg#include "shadow.h" 60428d7b3dSmrg#include "fb.h" 61428d7b3dSmrg 62428d7b3dSmrg#include "intel.h" 63428d7b3dSmrg#include "i830_reg.h" 64428d7b3dSmrg 65428d7b3dSmrg#include "i915_drm.h" 66428d7b3dSmrg 67428d7b3dSmrg#include "dri2.h" 68428d7b3dSmrg 69428d7b3dSmrg#if USE_UXA 70428d7b3dSmrg#include "intel_uxa.h" 71428d7b3dSmrg#endif 72428d7b3dSmrg 73428d7b3dSmrgtypedef struct { 74428d7b3dSmrg int refcnt; 75428d7b3dSmrg PixmapPtr pixmap; 76428d7b3dSmrg} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr; 77428d7b3dSmrg 78428d7b3dSmrg#if HAS_DEVPRIVATEKEYREC 79428d7b3dSmrgstatic DevPrivateKeyRec i830_client_key; 80428d7b3dSmrg#else 81428d7b3dSmrgstatic int i830_client_key; 82428d7b3dSmrg#endif 83428d7b3dSmrg 84428d7b3dSmrgstatic uint32_t pixmap_flink(PixmapPtr pixmap) 85428d7b3dSmrg{ 86428d7b3dSmrg struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap); 87428d7b3dSmrg uint32_t name; 88428d7b3dSmrg 89428d7b3dSmrg if (priv == NULL || priv->bo == NULL) 90428d7b3dSmrg return 0; 91428d7b3dSmrg 92428d7b3dSmrg if (dri_bo_flink(priv->bo, &name) != 0) 93428d7b3dSmrg return 0; 94428d7b3dSmrg 95428d7b3dSmrg priv->pinned |= PIN_DRI2; 96428d7b3dSmrg return name; 97428d7b3dSmrg} 98428d7b3dSmrg 99428d7b3dSmrgstatic PixmapPtr get_front_buffer(DrawablePtr drawable) 100428d7b3dSmrg{ 101428d7b3dSmrg PixmapPtr pixmap; 102428d7b3dSmrg 103428d7b3dSmrg pixmap = get_drawable_pixmap(drawable); 104428d7b3dSmrg if (!intel_get_pixmap_bo(pixmap)) 105428d7b3dSmrg return NULL; 106428d7b3dSmrg 107428d7b3dSmrg pixmap->refcnt++; 108428d7b3dSmrg return pixmap; 109428d7b3dSmrg} 110428d7b3dSmrg 111428d7b3dSmrg#if DRI2INFOREC_VERSION < 2 112428d7b3dSmrgstatic DRI2BufferPtr 113428d7b3dSmrgI830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments, 114428d7b3dSmrg int count) 115428d7b3dSmrg{ 116428d7b3dSmrg ScreenPtr screen = drawable->pScreen; 117428d7b3dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 118428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 119428d7b3dSmrg DRI2BufferPtr buffers; 120428d7b3dSmrg I830DRI2BufferPrivatePtr privates; 121428d7b3dSmrg PixmapPtr pixmap, pDepthPixmap; 122428d7b3dSmrg int i; 123428d7b3dSmrg 124428d7b3dSmrg buffers = calloc(count, sizeof *buffers); 125428d7b3dSmrg if (buffers == NULL) 126428d7b3dSmrg return NULL; 127428d7b3dSmrg privates = calloc(count, sizeof *privates); 128428d7b3dSmrg if (privates == NULL) { 129428d7b3dSmrg free(buffers); 130428d7b3dSmrg return NULL; 131428d7b3dSmrg } 132428d7b3dSmrg 133428d7b3dSmrg pDepthPixmap = NULL; 134428d7b3dSmrg for (i = 0; i < count; i++) { 135428d7b3dSmrg pixmap = NULL; 136428d7b3dSmrg if (attachments[i] == DRI2BufferFrontLeft) { 137428d7b3dSmrg pixmap = get_front_buffer(drawable); 138428d7b3dSmrg 139428d7b3dSmrg if (pixmap == NULL) 140428d7b3dSmrg drawable = &(get_drawable_pixmap(drawable)->drawable); 141428d7b3dSmrg } else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) { 142428d7b3dSmrg pixmap = pDepthPixmap; 143428d7b3dSmrg pixmap->refcnt++; 144428d7b3dSmrg } 145428d7b3dSmrg 146428d7b3dSmrg if (pixmap == NULL) { 147428d7b3dSmrg unsigned int hint = INTEL_CREATE_PIXMAP_DRI2; 148428d7b3dSmrg 149428d7b3dSmrg if (intel->tiling & INTEL_TILING_3D) { 150428d7b3dSmrg switch (attachments[i]) { 151428d7b3dSmrg case DRI2BufferDepth: 152428d7b3dSmrg if (SUPPORTS_YTILING(intel)) 153428d7b3dSmrg hint |= INTEL_CREATE_PIXMAP_TILING_Y; 154428d7b3dSmrg else 155428d7b3dSmrg hint |= INTEL_CREATE_PIXMAP_TILING_X; 156428d7b3dSmrg break; 157428d7b3dSmrg case DRI2BufferFakeFrontLeft: 158428d7b3dSmrg case DRI2BufferFakeFrontRight: 159428d7b3dSmrg case DRI2BufferBackLeft: 160428d7b3dSmrg case DRI2BufferBackRight: 161428d7b3dSmrg hint |= INTEL_CREATE_PIXMAP_TILING_X; 162428d7b3dSmrg break; 163428d7b3dSmrg } 164428d7b3dSmrg } 165428d7b3dSmrg 166428d7b3dSmrg pixmap = screen->CreatePixmap(screen, 167428d7b3dSmrg drawable->width, 168428d7b3dSmrg drawable->height, 169428d7b3dSmrg drawable->depth, 170428d7b3dSmrg hint); 171428d7b3dSmrg if (pixmap == NULL || 172428d7b3dSmrg intel_get_pixmap_bo(pixmap) == NULL) 173428d7b3dSmrg { 174428d7b3dSmrg if (pixmap) 175428d7b3dSmrg screen->DestroyPixmap(pixmap); 176428d7b3dSmrg goto unwind; 177428d7b3dSmrg } 178428d7b3dSmrg } 179428d7b3dSmrg 180428d7b3dSmrg if (attachments[i] == DRI2BufferDepth) 181428d7b3dSmrg pDepthPixmap = pixmap; 182428d7b3dSmrg 183428d7b3dSmrg buffers[i].attachment = attachments[i]; 184428d7b3dSmrg buffers[i].pitch = pixmap->devKind; 185428d7b3dSmrg buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8; 186428d7b3dSmrg buffers[i].driverPrivate = &privates[i]; 187428d7b3dSmrg buffers[i].flags = 0; /* not tiled */ 188428d7b3dSmrg privates[i].refcnt = 1; 189428d7b3dSmrg privates[i].pixmap = pixmap; 190428d7b3dSmrg 191428d7b3dSmrg if ((buffers[i].name = pixmap_flink(pixmap)) == 0) { 192428d7b3dSmrg /* failed to name buffer */ 193428d7b3dSmrg screen->DestroyPixmap(pixmap); 194428d7b3dSmrg goto unwind; 195428d7b3dSmrg } 196428d7b3dSmrg } 197428d7b3dSmrg 198428d7b3dSmrg return buffers; 199428d7b3dSmrg 200428d7b3dSmrgunwind: 201428d7b3dSmrg while (i--) 202428d7b3dSmrg screen->DestroyPixmap(privates[i].pixmap); 203428d7b3dSmrg free(privates); 204428d7b3dSmrg free(buffers); 205428d7b3dSmrg return NULL; 206428d7b3dSmrg} 207428d7b3dSmrg 208428d7b3dSmrgstatic void 209428d7b3dSmrgI830DRI2DestroyBuffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count) 210428d7b3dSmrg{ 211428d7b3dSmrg ScreenPtr screen = drawable->pScreen; 212428d7b3dSmrg I830DRI2BufferPrivatePtr private; 213428d7b3dSmrg int i; 214428d7b3dSmrg 215428d7b3dSmrg for (i = 0; i < count; i++) { 216428d7b3dSmrg private = buffers[i].driverPrivate; 217428d7b3dSmrg screen->DestroyPixmap(private->pixmap); 218428d7b3dSmrg } 219428d7b3dSmrg 220428d7b3dSmrg if (buffers) { 221428d7b3dSmrg free(buffers[0].driverPrivate); 222428d7b3dSmrg free(buffers); 223428d7b3dSmrg } 224428d7b3dSmrg} 225428d7b3dSmrg 226428d7b3dSmrg#else 227428d7b3dSmrg 228428d7b3dSmrgstatic DRI2Buffer2Ptr 229428d7b3dSmrgI830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment, 230428d7b3dSmrg unsigned int format) 231428d7b3dSmrg{ 232428d7b3dSmrg ScreenPtr screen = drawable->pScreen; 233428d7b3dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 234428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 235428d7b3dSmrg DRI2Buffer2Ptr buffer; 236428d7b3dSmrg I830DRI2BufferPrivatePtr privates; 237428d7b3dSmrg PixmapPtr pixmap; 238428d7b3dSmrg 239428d7b3dSmrg buffer = calloc(1, sizeof *buffer); 240428d7b3dSmrg if (buffer == NULL) 241428d7b3dSmrg return NULL; 242428d7b3dSmrg privates = calloc(1, sizeof *privates); 243428d7b3dSmrg if (privates == NULL) { 244428d7b3dSmrg free(buffer); 245428d7b3dSmrg return NULL; 246428d7b3dSmrg } 247428d7b3dSmrg 248428d7b3dSmrg pixmap = NULL; 249428d7b3dSmrg if (attachment == DRI2BufferFrontLeft) { 250428d7b3dSmrg pixmap = get_front_buffer(drawable); 251428d7b3dSmrg if (pixmap == NULL) 252428d7b3dSmrg drawable = &(get_drawable_pixmap(drawable)->drawable); 253428d7b3dSmrg } 254428d7b3dSmrg 255428d7b3dSmrg if (pixmap == NULL) { 256428d7b3dSmrg unsigned int hint = INTEL_CREATE_PIXMAP_DRI2; 257428d7b3dSmrg int pixmap_width = drawable->width; 258428d7b3dSmrg int pixmap_height = drawable->height; 259428d7b3dSmrg int pixmap_cpp = (format != 0) ? format : drawable->depth; 260428d7b3dSmrg 261428d7b3dSmrg if (intel->tiling & INTEL_TILING_3D) { 262428d7b3dSmrg switch (attachment) { 263428d7b3dSmrg case DRI2BufferDepth: 264428d7b3dSmrg case DRI2BufferDepthStencil: 265428d7b3dSmrg case DRI2BufferHiz: 266428d7b3dSmrg if (SUPPORTS_YTILING(intel)) { 267428d7b3dSmrg hint |= INTEL_CREATE_PIXMAP_TILING_Y; 268428d7b3dSmrg break; 269428d7b3dSmrg } 270428d7b3dSmrg case DRI2BufferAccum: 271428d7b3dSmrg case DRI2BufferBackLeft: 272428d7b3dSmrg case DRI2BufferBackRight: 273428d7b3dSmrg case DRI2BufferFakeFrontLeft: 274428d7b3dSmrg case DRI2BufferFakeFrontRight: 275428d7b3dSmrg case DRI2BufferFrontLeft: 276428d7b3dSmrg case DRI2BufferFrontRight: 277428d7b3dSmrg hint |= INTEL_CREATE_PIXMAP_TILING_X; 278428d7b3dSmrg break; 279428d7b3dSmrg case DRI2BufferStencil: 280428d7b3dSmrg /* 281428d7b3dSmrg * The stencil buffer is W tiled. However, we 282428d7b3dSmrg * request from the kernel a non-tiled buffer 283428d7b3dSmrg * because the GTT is incapable of W fencing. 284428d7b3dSmrg */ 285428d7b3dSmrg hint |= INTEL_CREATE_PIXMAP_TILING_NONE; 286428d7b3dSmrg break; 287428d7b3dSmrg default: 288428d7b3dSmrg free(privates); 289428d7b3dSmrg free(buffer); 290428d7b3dSmrg return NULL; 291428d7b3dSmrg } 292428d7b3dSmrg } 293428d7b3dSmrg 294428d7b3dSmrg /* 295428d7b3dSmrg * The stencil buffer has quirky pitch requirements. From Vol 296428d7b3dSmrg * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface 297428d7b3dSmrg * Pitch": 298428d7b3dSmrg * The pitch must be set to 2x the value computed based on 299428d7b3dSmrg * width, as the stencil buffer is stored with two rows 300428d7b3dSmrg * interleaved. 301428d7b3dSmrg * To accomplish this, we resort to the nasty hack of doubling 302428d7b3dSmrg * the drm region's cpp and halving its height. 303428d7b3dSmrg * 304428d7b3dSmrg * If we neglect to double the pitch, then render corruption 305428d7b3dSmrg * occurs. 306428d7b3dSmrg */ 307428d7b3dSmrg if (attachment == DRI2BufferStencil) { 308428d7b3dSmrg pixmap_width = ALIGN(pixmap_width, 64); 309428d7b3dSmrg pixmap_height = ALIGN((pixmap_height + 1) / 2, 64); 310428d7b3dSmrg pixmap_cpp *= 2; 311428d7b3dSmrg } 312428d7b3dSmrg 313428d7b3dSmrg pixmap = screen->CreatePixmap(screen, 314428d7b3dSmrg pixmap_width, 315428d7b3dSmrg pixmap_height, 316428d7b3dSmrg pixmap_cpp, 317428d7b3dSmrg hint); 318428d7b3dSmrg if (pixmap == NULL || intel_get_pixmap_bo(pixmap) == NULL) { 319428d7b3dSmrg if (pixmap) 320428d7b3dSmrg screen->DestroyPixmap(pixmap); 321428d7b3dSmrg free(privates); 322428d7b3dSmrg free(buffer); 323428d7b3dSmrg return NULL; 324428d7b3dSmrg } 325428d7b3dSmrg } 326428d7b3dSmrg 327428d7b3dSmrg buffer->attachment = attachment; 328428d7b3dSmrg buffer->pitch = pixmap->devKind; 329428d7b3dSmrg buffer->cpp = pixmap->drawable.bitsPerPixel / 8; 330428d7b3dSmrg buffer->driverPrivate = privates; 331428d7b3dSmrg buffer->format = format; 332428d7b3dSmrg buffer->flags = 0; /* not tiled */ 333428d7b3dSmrg privates->refcnt = 1; 334428d7b3dSmrg privates->pixmap = pixmap; 335428d7b3dSmrg 336428d7b3dSmrg if ((buffer->name = pixmap_flink(pixmap)) == 0) { 337428d7b3dSmrg /* failed to name buffer */ 338428d7b3dSmrg screen->DestroyPixmap(pixmap); 339428d7b3dSmrg free(privates); 340428d7b3dSmrg free(buffer); 341428d7b3dSmrg return NULL; 342428d7b3dSmrg } 343428d7b3dSmrg 344428d7b3dSmrg return buffer; 345428d7b3dSmrg} 346428d7b3dSmrg 347428d7b3dSmrgstatic void I830DRI2DestroyBuffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer) 348428d7b3dSmrg{ 349428d7b3dSmrg if (buffer && buffer->driverPrivate) { 350428d7b3dSmrg I830DRI2BufferPrivatePtr private = buffer->driverPrivate; 351428d7b3dSmrg if (--private->refcnt == 0) { 352428d7b3dSmrg ScreenPtr screen = private->pixmap->drawable.pScreen; 353428d7b3dSmrg screen->DestroyPixmap(private->pixmap); 354428d7b3dSmrg 355428d7b3dSmrg free(private); 356428d7b3dSmrg free(buffer); 357428d7b3dSmrg } 358428d7b3dSmrg } else 359428d7b3dSmrg free(buffer); 360428d7b3dSmrg} 361428d7b3dSmrg 362428d7b3dSmrg#endif 363428d7b3dSmrg 364428d7b3dSmrgstatic void 365428d7b3dSmrgI830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion, 366428d7b3dSmrg DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer) 367428d7b3dSmrg{ 368428d7b3dSmrg I830DRI2BufferPrivatePtr srcPrivate = sourceBuffer->driverPrivate; 369428d7b3dSmrg I830DRI2BufferPrivatePtr dstPrivate = destBuffer->driverPrivate; 370428d7b3dSmrg ScreenPtr screen = drawable->pScreen; 371428d7b3dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 372428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 373428d7b3dSmrg DrawablePtr src = (sourceBuffer->attachment == DRI2BufferFrontLeft) 374428d7b3dSmrg ? drawable : &srcPrivate->pixmap->drawable; 375428d7b3dSmrg DrawablePtr dst = (destBuffer->attachment == DRI2BufferFrontLeft) 376428d7b3dSmrg ? drawable : &dstPrivate->pixmap->drawable; 377428d7b3dSmrg RegionPtr pCopyClip; 378428d7b3dSmrg GCPtr gc; 379428d7b3dSmrg 380428d7b3dSmrg gc = GetScratchGC(dst->depth, screen); 381428d7b3dSmrg if (!gc) 382428d7b3dSmrg return; 383428d7b3dSmrg 384428d7b3dSmrg pCopyClip = REGION_CREATE(screen, NULL, 0); 385428d7b3dSmrg REGION_COPY(screen, pCopyClip, pRegion); 386428d7b3dSmrg (*gc->funcs->ChangeClip) (gc, CT_REGION, pCopyClip, 0); 387428d7b3dSmrg ValidateGC(dst, gc); 388428d7b3dSmrg 389428d7b3dSmrg /* Wait for the scanline to be outside the region to be copied */ 390428d7b3dSmrg if (scrn->vtSema && 391428d7b3dSmrg pixmap_is_scanout(get_drawable_pixmap(dst)) && 392428d7b3dSmrg intel->swapbuffers_wait && INTEL_INFO(intel)->gen < 060) { 393428d7b3dSmrg BoxPtr box; 394428d7b3dSmrg BoxRec crtcbox; 395428d7b3dSmrg int y1, y2; 396428d7b3dSmrg int event, load_scan_lines_pipe; 397428d7b3dSmrg xf86CrtcPtr crtc; 398428d7b3dSmrg Bool full_height = FALSE; 399428d7b3dSmrg 400428d7b3dSmrg box = REGION_EXTENTS(unused, gc->pCompositeClip); 401428d7b3dSmrg crtc = intel_covering_crtc(scrn, box, NULL, &crtcbox); 402428d7b3dSmrg 403428d7b3dSmrg /* 404428d7b3dSmrg * Make sure the CRTC is valid and this is the real front 405428d7b3dSmrg * buffer 406428d7b3dSmrg */ 407428d7b3dSmrg if (crtc != NULL && !crtc->rotatedData) { 408428d7b3dSmrg int pipe = intel_crtc_to_pipe(crtc); 409428d7b3dSmrg 410428d7b3dSmrg /* 411428d7b3dSmrg * Make sure we don't wait for a scanline that will 412428d7b3dSmrg * never occur 413428d7b3dSmrg */ 414428d7b3dSmrg y1 = (crtcbox.y1 <= box->y1) ? box->y1 - crtcbox.y1 : 0; 415428d7b3dSmrg y2 = (box->y2 <= crtcbox.y2) ? 416428d7b3dSmrg box->y2 - crtcbox.y1 : crtcbox.y2 - crtcbox.y1; 417428d7b3dSmrg 418428d7b3dSmrg if (y1 == 0 && y2 == (crtcbox.y2 - crtcbox.y1)) 419428d7b3dSmrg full_height = TRUE; 420428d7b3dSmrg 421428d7b3dSmrg /* 422428d7b3dSmrg * Pre-965 doesn't have SVBLANK, so we need a bit 423428d7b3dSmrg * of extra time for the blitter to start up and 424428d7b3dSmrg * do its job for a full height blit 425428d7b3dSmrg */ 426428d7b3dSmrg if (full_height && INTEL_INFO(intel)->gen < 040) 427428d7b3dSmrg y2 -= 2; 428428d7b3dSmrg 429428d7b3dSmrg if (pipe == 0) { 430428d7b3dSmrg event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; 431428d7b3dSmrg load_scan_lines_pipe = 432428d7b3dSmrg MI_LOAD_SCAN_LINES_DISPLAY_PIPEA; 433428d7b3dSmrg if (full_height && INTEL_INFO(intel)->gen >= 040) 434428d7b3dSmrg event = MI_WAIT_FOR_PIPEA_SVBLANK; 435428d7b3dSmrg } else { 436428d7b3dSmrg event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW; 437428d7b3dSmrg load_scan_lines_pipe = 438428d7b3dSmrg MI_LOAD_SCAN_LINES_DISPLAY_PIPEB; 439428d7b3dSmrg if (full_height && INTEL_INFO(intel)->gen >= 040) 440428d7b3dSmrg event = MI_WAIT_FOR_PIPEB_SVBLANK; 441428d7b3dSmrg } 442428d7b3dSmrg 443428d7b3dSmrg if (crtc->mode.Flags & V_INTERLACE) { 444428d7b3dSmrg /* DSL count field lines */ 445428d7b3dSmrg y1 /= 2; 446428d7b3dSmrg y2 /= 2; 447428d7b3dSmrg } 448428d7b3dSmrg 449428d7b3dSmrg BEGIN_BATCH(5); 450428d7b3dSmrg /* 451428d7b3dSmrg * The documentation says that the LOAD_SCAN_LINES 452428d7b3dSmrg * command always comes in pairs. Don't ask me why. 453428d7b3dSmrg */ 454428d7b3dSmrg OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | 455428d7b3dSmrg load_scan_lines_pipe); 456428d7b3dSmrg OUT_BATCH((y1 << 16) | (y2-1)); 457428d7b3dSmrg OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | 458428d7b3dSmrg load_scan_lines_pipe); 459428d7b3dSmrg OUT_BATCH((y1 << 16) | (y2-1)); 460428d7b3dSmrg OUT_BATCH(MI_WAIT_FOR_EVENT | event); 461428d7b3dSmrg ADVANCE_BATCH(); 462428d7b3dSmrg } 463428d7b3dSmrg } 464428d7b3dSmrg 465428d7b3dSmrg /* It's important that this copy gets submitted before the 466428d7b3dSmrg * direct rendering client submits rendering for the next 467428d7b3dSmrg * frame, but we don't actually need to submit right now. The 468428d7b3dSmrg * client will wait for the DRI2CopyRegion reply or the swap 469428d7b3dSmrg * buffer event before rendering, and we'll hit the flush 470428d7b3dSmrg * callback chain before those messages are sent. We submit 471428d7b3dSmrg * our batch buffers from the flush callback chain so we know 472428d7b3dSmrg * that will happen before the client tries to render 473428d7b3dSmrg * again. */ 474428d7b3dSmrg 475428d7b3dSmrg gc->ops->CopyArea(src, dst, gc, 476428d7b3dSmrg 0, 0, 477428d7b3dSmrg drawable->width, drawable->height, 478428d7b3dSmrg 0, 0); 479428d7b3dSmrg 480428d7b3dSmrg FreeScratchGC(gc); 481428d7b3dSmrg 482428d7b3dSmrg /* And make sure the WAIT_FOR_EVENT is queued before any 483428d7b3dSmrg * modesetting/dpms operations on the pipe. 484428d7b3dSmrg */ 485428d7b3dSmrg intel_batch_submit(scrn); 486428d7b3dSmrg} 487428d7b3dSmrg 488428d7b3dSmrgstatic void 489428d7b3dSmrgI830DRI2FallbackBlitSwap(DrawablePtr drawable, 490428d7b3dSmrg DRI2BufferPtr dst, 491428d7b3dSmrg DRI2BufferPtr src) 492428d7b3dSmrg{ 493428d7b3dSmrg BoxRec box; 494428d7b3dSmrg RegionRec region; 495428d7b3dSmrg 496428d7b3dSmrg box.x1 = 0; 497428d7b3dSmrg box.y1 = 0; 498428d7b3dSmrg box.x2 = drawable->width; 499428d7b3dSmrg box.y2 = drawable->height; 500428d7b3dSmrg REGION_INIT(pScreen, ®ion, &box, 0); 501428d7b3dSmrg 502428d7b3dSmrg I830DRI2CopyRegion(drawable, ®ion, dst, src); 503428d7b3dSmrg} 504428d7b3dSmrg 505428d7b3dSmrg#if DRI2INFOREC_VERSION >= 4 506428d7b3dSmrg 507428d7b3dSmrgstatic void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer) 508428d7b3dSmrg{ 509428d7b3dSmrg if (buffer) { 510428d7b3dSmrg I830DRI2BufferPrivatePtr private = buffer->driverPrivate; 511428d7b3dSmrg private->refcnt++; 512428d7b3dSmrg } 513428d7b3dSmrg} 514428d7b3dSmrg 515428d7b3dSmrgstatic xf86CrtcPtr 516428d7b3dSmrgI830DRI2DrawableCrtc(DrawablePtr pDraw) 517428d7b3dSmrg{ 518428d7b3dSmrg ScreenPtr pScreen = pDraw->pScreen; 519428d7b3dSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 520428d7b3dSmrg BoxRec box, crtcbox; 521428d7b3dSmrg xf86CrtcPtr crtc = NULL; 522428d7b3dSmrg 523428d7b3dSmrg box.x1 = pDraw->x; 524428d7b3dSmrg box.y1 = pDraw->y; 525428d7b3dSmrg box.x2 = box.x1 + pDraw->width; 526428d7b3dSmrg box.y2 = box.y1 + pDraw->height; 527428d7b3dSmrg 528428d7b3dSmrg if (pDraw->type != DRAWABLE_PIXMAP) 529428d7b3dSmrg crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox); 530428d7b3dSmrg 531428d7b3dSmrg /* Make sure the CRTC is valid and this is the real front buffer */ 532428d7b3dSmrg if (crtc != NULL && !crtc->rotatedData) 533428d7b3dSmrg return crtc; 534428d7b3dSmrg 535428d7b3dSmrg return NULL; 536428d7b3dSmrg} 537428d7b3dSmrg 538428d7b3dSmrgstatic RESTYPE frame_event_client_type, frame_event_drawable_type; 539428d7b3dSmrg 540428d7b3dSmrgstruct i830_dri2_resource { 541428d7b3dSmrg XID id; 542428d7b3dSmrg RESTYPE type; 543428d7b3dSmrg struct list list; 544428d7b3dSmrg}; 545428d7b3dSmrg 546428d7b3dSmrgstatic struct i830_dri2_resource * 547428d7b3dSmrgget_resource(XID id, RESTYPE type) 548428d7b3dSmrg{ 549428d7b3dSmrg struct i830_dri2_resource *resource; 550428d7b3dSmrg void *ptr; 551428d7b3dSmrg 552428d7b3dSmrg ptr = NULL; 553428d7b3dSmrg dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess); 554428d7b3dSmrg if (ptr) 555428d7b3dSmrg return ptr; 556428d7b3dSmrg 557428d7b3dSmrg resource = malloc(sizeof(*resource)); 558428d7b3dSmrg if (resource == NULL) 559428d7b3dSmrg return NULL; 560428d7b3dSmrg 561428d7b3dSmrg if (!AddResource(id, type, resource)) { 562428d7b3dSmrg free(resource); 563428d7b3dSmrg return NULL; 564428d7b3dSmrg } 565428d7b3dSmrg 566428d7b3dSmrg resource->id = id; 567428d7b3dSmrg resource->type = type; 568428d7b3dSmrg list_init(&resource->list); 569428d7b3dSmrg return resource; 570428d7b3dSmrg} 571428d7b3dSmrg 572428d7b3dSmrgstatic int 573428d7b3dSmrgi830_dri2_frame_event_client_gone(void *data, XID id) 574428d7b3dSmrg{ 575428d7b3dSmrg struct i830_dri2_resource *resource = data; 576428d7b3dSmrg 577428d7b3dSmrg while (!list_is_empty(&resource->list)) { 578428d7b3dSmrg DRI2FrameEventPtr info = 579428d7b3dSmrg list_first_entry(&resource->list, 580428d7b3dSmrg DRI2FrameEventRec, 581428d7b3dSmrg client_resource); 582428d7b3dSmrg 583428d7b3dSmrg list_del(&info->client_resource); 584428d7b3dSmrg info->client = NULL; 585428d7b3dSmrg } 586428d7b3dSmrg free(resource); 587428d7b3dSmrg 588428d7b3dSmrg return Success; 589428d7b3dSmrg} 590428d7b3dSmrg 591428d7b3dSmrgstatic int 592428d7b3dSmrgi830_dri2_frame_event_drawable_gone(void *data, XID id) 593428d7b3dSmrg{ 594428d7b3dSmrg struct i830_dri2_resource *resource = data; 595428d7b3dSmrg 596428d7b3dSmrg while (!list_is_empty(&resource->list)) { 597428d7b3dSmrg DRI2FrameEventPtr info = 598428d7b3dSmrg list_first_entry(&resource->list, 599428d7b3dSmrg DRI2FrameEventRec, 600428d7b3dSmrg drawable_resource); 601428d7b3dSmrg 602428d7b3dSmrg list_del(&info->drawable_resource); 603428d7b3dSmrg info->drawable_id = None; 604428d7b3dSmrg } 605428d7b3dSmrg free(resource); 606428d7b3dSmrg 607428d7b3dSmrg return Success; 608428d7b3dSmrg} 609428d7b3dSmrg 610428d7b3dSmrgstatic Bool 611428d7b3dSmrgi830_dri2_register_frame_event_resource_types(void) 612428d7b3dSmrg{ 613428d7b3dSmrg frame_event_client_type = CreateNewResourceType(i830_dri2_frame_event_client_gone, "Frame Event Client"); 614428d7b3dSmrg if (!frame_event_client_type) 615428d7b3dSmrg return FALSE; 616428d7b3dSmrg 617428d7b3dSmrg frame_event_drawable_type = CreateNewResourceType(i830_dri2_frame_event_drawable_gone, "Frame Event Drawable"); 618428d7b3dSmrg if (!frame_event_drawable_type) 619428d7b3dSmrg return FALSE; 620428d7b3dSmrg 621428d7b3dSmrg return TRUE; 622428d7b3dSmrg} 623428d7b3dSmrg 624428d7b3dSmrgstatic XID 625428d7b3dSmrgget_client_id(ClientPtr client) 626428d7b3dSmrg{ 627428d7b3dSmrg#if HAS_DIXREGISTERPRIVATEKEY 628428d7b3dSmrg XID *ptr = dixGetPrivateAddr(&client->devPrivates, &i830_client_key); 629428d7b3dSmrg#else 630428d7b3dSmrg XID *ptr = dixLookupPrivate(&client->devPrivates, &i830_client_key); 631428d7b3dSmrg#endif 632428d7b3dSmrg if (*ptr == 0) 633428d7b3dSmrg *ptr = FakeClientID(client->index); 634428d7b3dSmrg return *ptr; 635428d7b3dSmrg} 636428d7b3dSmrg 637428d7b3dSmrg/* 638428d7b3dSmrg * Hook this frame event into the server resource 639428d7b3dSmrg * database so we can clean it up if the drawable or 640428d7b3dSmrg * client exits while the swap is pending 641428d7b3dSmrg */ 642428d7b3dSmrgstatic Bool 643428d7b3dSmrgi830_dri2_add_frame_event(DRI2FrameEventPtr info) 644428d7b3dSmrg{ 645428d7b3dSmrg struct i830_dri2_resource *resource; 646428d7b3dSmrg 647428d7b3dSmrg resource = get_resource(get_client_id(info->client), 648428d7b3dSmrg frame_event_client_type); 649428d7b3dSmrg if (resource == NULL) 650428d7b3dSmrg return FALSE; 651428d7b3dSmrg 652428d7b3dSmrg list_add(&info->client_resource, &resource->list); 653428d7b3dSmrg 654428d7b3dSmrg resource = get_resource(info->drawable_id, frame_event_drawable_type); 655428d7b3dSmrg if (resource == NULL) { 656428d7b3dSmrg list_del(&info->client_resource); 657428d7b3dSmrg return FALSE; 658428d7b3dSmrg } 659428d7b3dSmrg 660428d7b3dSmrg list_add(&info->drawable_resource, &resource->list); 661428d7b3dSmrg 662428d7b3dSmrg return TRUE; 663428d7b3dSmrg} 664428d7b3dSmrg 665428d7b3dSmrgstatic void 666428d7b3dSmrgi830_dri2_del_frame_event(DRI2FrameEventPtr info) 667428d7b3dSmrg{ 668428d7b3dSmrg list_del(&info->client_resource); 669428d7b3dSmrg list_del(&info->drawable_resource); 670428d7b3dSmrg 671428d7b3dSmrg if (info->front) 672428d7b3dSmrg I830DRI2DestroyBuffer(NULL, info->front); 673428d7b3dSmrg if (info->back) 674428d7b3dSmrg I830DRI2DestroyBuffer(NULL, info->back); 675428d7b3dSmrg 676428d7b3dSmrg free(info); 677428d7b3dSmrg} 678428d7b3dSmrg 679428d7b3dSmrgstatic struct intel_uxa_pixmap * 680428d7b3dSmrgintel_exchange_pixmap_buffers(struct intel_screen_private *intel, PixmapPtr front, PixmapPtr back) 681428d7b3dSmrg{ 682428d7b3dSmrg struct intel_uxa_pixmap *new_front = NULL, *new_back; 683428d7b3dSmrg RegionRec region; 684428d7b3dSmrg 685428d7b3dSmrg /* Post damage on the front buffer so that listeners, such 686428d7b3dSmrg * as DisplayLink know take a copy and shove it over the USB. 687428d7b3dSmrg * also for sw cursors. 688428d7b3dSmrg */ 689428d7b3dSmrg region.extents.x1 = region.extents.y1 = 0; 690428d7b3dSmrg region.extents.x2 = front->drawable.width; 691428d7b3dSmrg region.extents.y2 = front->drawable.height; 692428d7b3dSmrg region.data = NULL; 693428d7b3dSmrg DamageRegionAppend(&front->drawable, ®ion); 694428d7b3dSmrg 695428d7b3dSmrg new_front = intel_uxa_get_pixmap_private(back); 696428d7b3dSmrg new_back = intel_uxa_get_pixmap_private(front); 697428d7b3dSmrg intel_uxa_set_pixmap_private(front, new_front); 698428d7b3dSmrg intel_uxa_set_pixmap_private(back, new_back); 699428d7b3dSmrg new_front->busy = 1; 700428d7b3dSmrg new_back->busy = -1; 701428d7b3dSmrg 702428d7b3dSmrg DamageRegionProcessPending(&front->drawable); 703428d7b3dSmrg 704428d7b3dSmrg return new_front; 705428d7b3dSmrg} 706428d7b3dSmrg 707428d7b3dSmrgstatic void 708428d7b3dSmrgI830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back) 709428d7b3dSmrg{ 710428d7b3dSmrg I830DRI2BufferPrivatePtr front_priv, back_priv; 711428d7b3dSmrg int tmp; 712428d7b3dSmrg struct intel_uxa_pixmap *new_front; 713428d7b3dSmrg 714428d7b3dSmrg front_priv = front->driverPrivate; 715428d7b3dSmrg back_priv = back->driverPrivate; 716428d7b3dSmrg 717428d7b3dSmrg /* Swap BO names so DRI works */ 718428d7b3dSmrg tmp = front->name; 719428d7b3dSmrg front->name = back->name; 720428d7b3dSmrg back->name = tmp; 721428d7b3dSmrg 722428d7b3dSmrg /* Swap pixmap bos */ 723428d7b3dSmrg new_front = intel_exchange_pixmap_buffers(intel, 724428d7b3dSmrg front_priv->pixmap, 725428d7b3dSmrg back_priv->pixmap); 726428d7b3dSmrg dri_bo_unreference (intel->front_buffer); 727428d7b3dSmrg intel->front_buffer = new_front->bo; 728428d7b3dSmrg dri_bo_reference (intel->front_buffer); 729428d7b3dSmrg} 730428d7b3dSmrg 731428d7b3dSmrgstatic drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv) 732428d7b3dSmrg{ 733428d7b3dSmrg drm_intel_bo *bo = intel_get_pixmap_bo(priv->pixmap); 734428d7b3dSmrg assert(bo != NULL); /* guaranteed by construction of the DRI2 buffer */ 735428d7b3dSmrg return bo; 736428d7b3dSmrg} 737428d7b3dSmrg 738428d7b3dSmrgstatic void 739428d7b3dSmrgI830DRI2FlipComplete(uint64_t frame, uint64_t usec, void *pageflip_data) 740428d7b3dSmrg{ 741428d7b3dSmrg DRI2FrameEventPtr info = pageflip_data; 742428d7b3dSmrg 743428d7b3dSmrg I830DRI2FlipEventHandler((uint32_t) frame, usec / 1000000, 744428d7b3dSmrg usec % 1000000, 745428d7b3dSmrg info); 746428d7b3dSmrg} 747428d7b3dSmrg 748428d7b3dSmrgstatic void 749428d7b3dSmrgI830DRI2FlipAbort(void *pageflip_data) 750428d7b3dSmrg{ 751428d7b3dSmrg DRI2FrameEventPtr info = pageflip_data; 752428d7b3dSmrg 753428d7b3dSmrg i830_dri2_del_frame_event(info); 754428d7b3dSmrg} 755428d7b3dSmrg 756428d7b3dSmrg/* 757428d7b3dSmrg * Our internal swap routine takes care of actually exchanging, blitting, or 758428d7b3dSmrg * flipping buffers as necessary. 759428d7b3dSmrg */ 760428d7b3dSmrgstatic Bool 761428d7b3dSmrgI830DRI2ScheduleFlip(struct intel_screen_private *intel, 762428d7b3dSmrg DrawablePtr draw, 763428d7b3dSmrg DRI2FrameEventPtr info) 764428d7b3dSmrg{ 765428d7b3dSmrg I830DRI2BufferPrivatePtr priv = info->back->driverPrivate; 766428d7b3dSmrg drm_intel_bo *new_back, *old_back; 767428d7b3dSmrg int tmp_name; 768428d7b3dSmrg 769428d7b3dSmrg if (!intel->use_triple_buffer) { 770428d7b3dSmrg info->type = DRI2_SWAP; 771428d7b3dSmrg if (!intel_do_pageflip(intel, 772428d7b3dSmrg get_pixmap_bo(priv), 773428d7b3dSmrg info->pipe, FALSE, info, 774428d7b3dSmrg I830DRI2FlipComplete, 775428d7b3dSmrg I830DRI2FlipAbort)) 776428d7b3dSmrg return FALSE; 777428d7b3dSmrg 778428d7b3dSmrg I830DRI2ExchangeBuffers(intel, info->front, info->back); 779428d7b3dSmrg return TRUE; 780428d7b3dSmrg } 781428d7b3dSmrg 782428d7b3dSmrg if (intel->pending_flip[info->pipe]) { 783428d7b3dSmrg assert(intel->pending_flip[info->pipe]->chain == NULL); 784428d7b3dSmrg intel->pending_flip[info->pipe]->chain = info; 785428d7b3dSmrg return TRUE; 786428d7b3dSmrg } 787428d7b3dSmrg 788428d7b3dSmrg if (intel->back_buffer == NULL) { 789428d7b3dSmrg new_back = drm_intel_bo_alloc(intel->bufmgr, "front buffer", 790428d7b3dSmrg intel->front_buffer->size, 0); 791428d7b3dSmrg if (new_back == NULL) 792428d7b3dSmrg return FALSE; 793428d7b3dSmrg 794428d7b3dSmrg if (intel->front_tiling != I915_TILING_NONE) { 795428d7b3dSmrg uint32_t tiling = intel->front_tiling; 796428d7b3dSmrg drm_intel_bo_set_tiling(new_back, &tiling, intel->front_pitch); 797428d7b3dSmrg if (tiling != intel->front_tiling) { 798428d7b3dSmrg drm_intel_bo_unreference(new_back); 799428d7b3dSmrg return FALSE; 800428d7b3dSmrg } 801428d7b3dSmrg } 802428d7b3dSmrg 803428d7b3dSmrg drm_intel_bo_disable_reuse(new_back); 804428d7b3dSmrg dri_bo_flink(new_back, &intel->back_name); 805428d7b3dSmrg } else { 806428d7b3dSmrg new_back = intel->back_buffer; 807428d7b3dSmrg intel->back_buffer = NULL; 808428d7b3dSmrg } 809428d7b3dSmrg 810428d7b3dSmrg old_back = get_pixmap_bo(priv); 811428d7b3dSmrg if (!intel_do_pageflip(intel, old_back, info->pipe, FALSE, info, I830DRI2FlipComplete, I830DRI2FlipAbort)) { 812428d7b3dSmrg intel->back_buffer = new_back; 813428d7b3dSmrg return FALSE; 814428d7b3dSmrg } 815428d7b3dSmrg info->type = DRI2_SWAP_CHAIN; 816428d7b3dSmrg intel->pending_flip[info->pipe] = info; 817428d7b3dSmrg 818428d7b3dSmrg priv = info->front->driverPrivate; 819428d7b3dSmrg 820428d7b3dSmrg /* Exchange the current front-buffer with the fresh bo */ 821428d7b3dSmrg 822428d7b3dSmrg intel->back_buffer = intel->front_buffer; 823428d7b3dSmrg drm_intel_bo_reference(intel->back_buffer); 824428d7b3dSmrg intel_set_pixmap_bo(priv->pixmap, new_back); 825428d7b3dSmrg drm_intel_bo_unreference(new_back); 826428d7b3dSmrg 827428d7b3dSmrg tmp_name = info->front->name; 828428d7b3dSmrg info->front->name = intel->back_name; 829428d7b3dSmrg intel->back_name = tmp_name; 830428d7b3dSmrg 831428d7b3dSmrg /* Then flip DRI2 pointers and update the screen pixmap */ 832428d7b3dSmrg I830DRI2ExchangeBuffers(intel, info->front, info->back); 833428d7b3dSmrg DRI2SwapComplete(info->client, draw, 0, 0, 0, 834428d7b3dSmrg DRI2_EXCHANGE_COMPLETE, 835428d7b3dSmrg info->event_complete, 836428d7b3dSmrg info->event_data); 837428d7b3dSmrg return TRUE; 838428d7b3dSmrg} 839428d7b3dSmrg 840428d7b3dSmrgstatic Bool 841428d7b3dSmrgcan_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back) 842428d7b3dSmrg{ 843428d7b3dSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(drawable->pScreen); 844428d7b3dSmrg struct intel_screen_private *intel = intel_get_screen_private(pScrn); 845428d7b3dSmrg I830DRI2BufferPrivatePtr front_priv = front->driverPrivate; 846428d7b3dSmrg I830DRI2BufferPrivatePtr back_priv = back->driverPrivate; 847428d7b3dSmrg PixmapPtr front_pixmap = front_priv->pixmap; 848428d7b3dSmrg PixmapPtr back_pixmap = back_priv->pixmap; 849428d7b3dSmrg struct intel_uxa_pixmap *front_intel = intel_uxa_get_pixmap_private(front_pixmap); 850428d7b3dSmrg struct intel_uxa_pixmap *back_intel = intel_uxa_get_pixmap_private(back_pixmap); 851428d7b3dSmrg 852428d7b3dSmrg if (!pScrn->vtSema) 853428d7b3dSmrg return FALSE; 854428d7b3dSmrg 855428d7b3dSmrg if (I830DRI2DrawableCrtc(drawable) == NULL) 856428d7b3dSmrg return FALSE; 857428d7b3dSmrg 858428d7b3dSmrg if (!DRI2CanFlip(drawable)) 859428d7b3dSmrg return FALSE; 860428d7b3dSmrg 861428d7b3dSmrg if (intel->shadow_present) 862428d7b3dSmrg return FALSE; 863428d7b3dSmrg 864428d7b3dSmrg if (!intel->use_pageflipping) 865428d7b3dSmrg return FALSE; 866428d7b3dSmrg 867428d7b3dSmrg if (front_pixmap->drawable.width != back_pixmap->drawable.width) 868428d7b3dSmrg return FALSE; 869428d7b3dSmrg 870428d7b3dSmrg if (front_pixmap->drawable.height != back_pixmap->drawable.height) 871428d7b3dSmrg return FALSE; 872428d7b3dSmrg 873428d7b3dSmrg /* XXX should we be checking depth instead of bpp? */ 874428d7b3dSmrg#if 0 875428d7b3dSmrg if (front_pixmap->drawable.depth != back_pixmap->drawable.depth) 876428d7b3dSmrg return FALSE; 877428d7b3dSmrg#else 878428d7b3dSmrg if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) 879428d7b3dSmrg return FALSE; 880428d7b3dSmrg#endif 881428d7b3dSmrg 882428d7b3dSmrg /* prevent an implicit tiling mode change */ 883428d7b3dSmrg if (front_intel->tiling != back_intel->tiling) 884428d7b3dSmrg return FALSE; 885428d7b3dSmrg 886428d7b3dSmrg if (front_intel->pinned & ~(PIN_SCANOUT | PIN_DRI2)) 887428d7b3dSmrg return FALSE; 888428d7b3dSmrg 889428d7b3dSmrg return TRUE; 890428d7b3dSmrg} 891428d7b3dSmrg 892428d7b3dSmrgvoid I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec, 893428d7b3dSmrg unsigned int tv_usec, DRI2FrameEventPtr swap_info) 894428d7b3dSmrg{ 895428d7b3dSmrg intel_screen_private *intel = swap_info->intel; 896428d7b3dSmrg DrawablePtr drawable; 897428d7b3dSmrg int status; 898428d7b3dSmrg 899428d7b3dSmrg if (!swap_info->drawable_id) 900428d7b3dSmrg status = BadDrawable; 901428d7b3dSmrg else 902428d7b3dSmrg status = dixLookupDrawable(&drawable, swap_info->drawable_id, serverClient, 903428d7b3dSmrg M_ANY, DixWriteAccess); 904428d7b3dSmrg if (status != Success) { 905428d7b3dSmrg i830_dri2_del_frame_event(swap_info); 906428d7b3dSmrg return; 907428d7b3dSmrg } 908428d7b3dSmrg 909428d7b3dSmrg 910428d7b3dSmrg switch (swap_info->type) { 911428d7b3dSmrg case DRI2_FLIP: 912428d7b3dSmrg /* If we can still flip... */ 913428d7b3dSmrg if (can_exchange(drawable, swap_info->front, swap_info->back) && 914428d7b3dSmrg I830DRI2ScheduleFlip(intel, drawable, swap_info)) 915428d7b3dSmrg return; 916428d7b3dSmrg 917428d7b3dSmrg /* else fall through to exchange/blit */ 918428d7b3dSmrg case DRI2_SWAP: { 919428d7b3dSmrg I830DRI2FallbackBlitSwap(drawable, 920428d7b3dSmrg swap_info->front, swap_info->back); 921428d7b3dSmrg DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec, 922428d7b3dSmrg DRI2_BLIT_COMPLETE, 923428d7b3dSmrg swap_info->client ? swap_info->event_complete : NULL, 924428d7b3dSmrg swap_info->event_data); 925428d7b3dSmrg break; 926428d7b3dSmrg } 927428d7b3dSmrg case DRI2_WAITMSC: 928428d7b3dSmrg if (swap_info->client) 929428d7b3dSmrg DRI2WaitMSCComplete(swap_info->client, drawable, 930428d7b3dSmrg frame, tv_sec, tv_usec); 931428d7b3dSmrg break; 932428d7b3dSmrg default: 933428d7b3dSmrg xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 934428d7b3dSmrg "%s: unknown vblank event received\n", __func__); 935428d7b3dSmrg /* Unknown type */ 936428d7b3dSmrg break; 937428d7b3dSmrg } 938428d7b3dSmrg 939428d7b3dSmrg i830_dri2_del_frame_event(swap_info); 940428d7b3dSmrg} 941428d7b3dSmrg 942428d7b3dSmrgvoid I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec, 943428d7b3dSmrg unsigned int tv_usec, DRI2FrameEventPtr flip_info) 944428d7b3dSmrg{ 945428d7b3dSmrg struct intel_screen_private *intel = flip_info->intel; 946428d7b3dSmrg DrawablePtr drawable; 947428d7b3dSmrg DRI2FrameEventPtr chain; 948428d7b3dSmrg 949428d7b3dSmrg drawable = NULL; 950428d7b3dSmrg if (flip_info->drawable_id) 951428d7b3dSmrg dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient, 952428d7b3dSmrg M_ANY, DixWriteAccess); 953428d7b3dSmrg 954428d7b3dSmrg 955428d7b3dSmrg /* We assume our flips arrive in order, so we don't check the frame */ 956428d7b3dSmrg switch (flip_info->type) { 957428d7b3dSmrg case DRI2_SWAP: 958428d7b3dSmrg if (!drawable) 959428d7b3dSmrg break; 960428d7b3dSmrg 961428d7b3dSmrg /* Check for too small vblank count of pageflip completion, taking wraparound 962428d7b3dSmrg * into account. This usually means some defective kms pageflip completion, 963428d7b3dSmrg * causing wrong (msc, ust) return values and possible visual corruption. 964428d7b3dSmrg */ 965428d7b3dSmrg if ((frame < flip_info->frame) && (flip_info->frame - frame < 5)) { 966428d7b3dSmrg static int limit = 5; 967428d7b3dSmrg 968428d7b3dSmrg /* XXX we are currently hitting this path with older 969428d7b3dSmrg * kernels, so make it quieter. 970428d7b3dSmrg */ 971428d7b3dSmrg if (limit) { 972428d7b3dSmrg xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 973428d7b3dSmrg "%s: Pageflip completion has impossible msc %d < target_msc %d\n", 974428d7b3dSmrg __func__, frame, flip_info->frame); 975428d7b3dSmrg limit--; 976428d7b3dSmrg } 977428d7b3dSmrg 978428d7b3dSmrg /* All-0 values signal timestamping failure. */ 979428d7b3dSmrg frame = tv_sec = tv_usec = 0; 980428d7b3dSmrg } 981428d7b3dSmrg 982428d7b3dSmrg DRI2SwapComplete(flip_info->client, drawable, frame, tv_sec, tv_usec, 983428d7b3dSmrg DRI2_FLIP_COMPLETE, flip_info->client ? flip_info->event_complete : NULL, 984428d7b3dSmrg flip_info->event_data); 985428d7b3dSmrg break; 986428d7b3dSmrg 987428d7b3dSmrg case DRI2_SWAP_CHAIN: 988428d7b3dSmrg assert(intel->pending_flip[flip_info->pipe] == flip_info); 989428d7b3dSmrg intel->pending_flip[flip_info->pipe] = NULL; 990428d7b3dSmrg 991428d7b3dSmrg chain = flip_info->chain; 992428d7b3dSmrg if (chain) { 993428d7b3dSmrg DrawablePtr chain_drawable = NULL; 994428d7b3dSmrg if (chain->drawable_id) 995428d7b3dSmrg dixLookupDrawable(&chain_drawable, 996428d7b3dSmrg chain->drawable_id, 997428d7b3dSmrg serverClient, 998428d7b3dSmrg M_ANY, DixWriteAccess); 999428d7b3dSmrg if (chain_drawable == NULL) { 1000428d7b3dSmrg i830_dri2_del_frame_event(chain); 1001428d7b3dSmrg } else if (!can_exchange(chain_drawable, chain->front, chain->back) || 1002428d7b3dSmrg !I830DRI2ScheduleFlip(intel, chain_drawable, chain)) { 1003428d7b3dSmrg I830DRI2FallbackBlitSwap(chain_drawable, 1004428d7b3dSmrg chain->front, 1005428d7b3dSmrg chain->back); 1006428d7b3dSmrg 1007428d7b3dSmrg DRI2SwapComplete(chain->client, chain_drawable, frame, tv_sec, tv_usec, 1008428d7b3dSmrg DRI2_BLIT_COMPLETE, 1009428d7b3dSmrg chain->client ? chain->event_complete : NULL, 1010428d7b3dSmrg chain->event_data); 1011428d7b3dSmrg i830_dri2_del_frame_event(chain); 1012428d7b3dSmrg } 1013428d7b3dSmrg } 1014428d7b3dSmrg break; 1015428d7b3dSmrg 1016428d7b3dSmrg default: 1017428d7b3dSmrg xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 1018428d7b3dSmrg "%s: unknown vblank event received\n", __func__); 1019428d7b3dSmrg /* Unknown type */ 1020428d7b3dSmrg break; 1021428d7b3dSmrg } 1022428d7b3dSmrg 1023428d7b3dSmrg i830_dri2_del_frame_event(flip_info); 1024428d7b3dSmrg} 1025428d7b3dSmrg 1026428d7b3dSmrgstatic uint32_t pipe_select(int pipe) 1027428d7b3dSmrg{ 1028428d7b3dSmrg if (pipe > 1) 1029428d7b3dSmrg return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; 1030428d7b3dSmrg else if (pipe > 0) 1031428d7b3dSmrg return DRM_VBLANK_SECONDARY; 1032428d7b3dSmrg else 1033428d7b3dSmrg return 0; 1034428d7b3dSmrg} 1035428d7b3dSmrg 1036428d7b3dSmrgstatic void 1037428d7b3dSmrgintel_dri2_vblank_handler(ScrnInfoPtr scrn, 1038428d7b3dSmrg xf86CrtcPtr crtc, 1039428d7b3dSmrg uint64_t msc, 1040428d7b3dSmrg uint64_t usec, 1041428d7b3dSmrg void *data) 1042428d7b3dSmrg{ 1043428d7b3dSmrg DRI2FrameEventPtr swap_info = data; 1044428d7b3dSmrg 1045428d7b3dSmrg I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, swap_info); 1046428d7b3dSmrg} 1047428d7b3dSmrg 1048428d7b3dSmrgstatic void 1049428d7b3dSmrgintel_dri2_vblank_abort(ScrnInfoPtr scrn, 1050428d7b3dSmrg xf86CrtcPtr crtc, 1051428d7b3dSmrg void *data) 1052428d7b3dSmrg{ 1053428d7b3dSmrg DRI2FrameEventPtr swap_info = data; 1054428d7b3dSmrg 1055428d7b3dSmrg i830_dri2_del_frame_event(swap_info); 1056428d7b3dSmrg} 1057428d7b3dSmrg 1058428d7b3dSmrg/* 1059428d7b3dSmrg * ScheduleSwap is responsible for requesting a DRM vblank event for the 1060428d7b3dSmrg * appropriate frame. 1061428d7b3dSmrg * 1062428d7b3dSmrg * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 1063428d7b3dSmrg * the vblank requested can simply be the last queued swap frame + the swap 1064428d7b3dSmrg * interval for the drawable. 1065428d7b3dSmrg * 1066428d7b3dSmrg * In the case of a page flip, we request an event for the last queued swap 1067428d7b3dSmrg * frame + swap interval - 1, since we'll need to queue the flip for the frame 1068428d7b3dSmrg * immediately following the received event. 1069428d7b3dSmrg * 1070428d7b3dSmrg * The client will be blocked if it tries to perform further GL commands 1071428d7b3dSmrg * after queueing a swap, though in the Intel case after queueing a flip, the 1072428d7b3dSmrg * client is free to queue more commands; they'll block in the kernel if 1073428d7b3dSmrg * they access buffers busy with the flip. 1074428d7b3dSmrg * 1075428d7b3dSmrg * When the swap is complete, the driver should call into the server so it 1076428d7b3dSmrg * can send any swap complete events that have been requested. 1077428d7b3dSmrg */ 1078428d7b3dSmrgstatic int 1079428d7b3dSmrgI830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, 1080428d7b3dSmrg DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor, 1081428d7b3dSmrg CARD64 remainder, DRI2SwapEventPtr func, void *data) 1082428d7b3dSmrg{ 1083428d7b3dSmrg ScreenPtr screen = draw->pScreen; 1084428d7b3dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1085428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 1086428d7b3dSmrg drmVBlank vbl; 1087428d7b3dSmrg int ret; 1088428d7b3dSmrg xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 1089428d7b3dSmrg int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1; 1090428d7b3dSmrg int flip = 0; 1091428d7b3dSmrg DRI2FrameEventPtr swap_info = NULL; 1092428d7b3dSmrg enum DRI2FrameEventType swap_type = DRI2_SWAP; 1093428d7b3dSmrg uint64_t current_msc, current_ust; 1094428d7b3dSmrg uint64_t request_msc; 1095428d7b3dSmrg uint32_t seq; 1096428d7b3dSmrg 1097428d7b3dSmrg /* Drawable not displayed... just complete the swap */ 1098428d7b3dSmrg if (pipe == -1) 1099428d7b3dSmrg goto blit_fallback; 1100428d7b3dSmrg 1101428d7b3dSmrg swap_info = calloc(1, sizeof(DRI2FrameEventRec)); 1102428d7b3dSmrg if (!swap_info) 1103428d7b3dSmrg goto blit_fallback; 1104428d7b3dSmrg 1105428d7b3dSmrg swap_info->intel = intel; 1106428d7b3dSmrg swap_info->drawable_id = draw->id; 1107428d7b3dSmrg swap_info->client = client; 1108428d7b3dSmrg swap_info->event_complete = func; 1109428d7b3dSmrg swap_info->event_data = data; 1110428d7b3dSmrg swap_info->front = front; 1111428d7b3dSmrg swap_info->back = back; 1112428d7b3dSmrg swap_info->pipe = pipe; 1113428d7b3dSmrg 1114428d7b3dSmrg if (!i830_dri2_add_frame_event(swap_info)) { 1115428d7b3dSmrg free(swap_info); 1116428d7b3dSmrg swap_info = NULL; 1117428d7b3dSmrg goto blit_fallback; 1118428d7b3dSmrg } 1119428d7b3dSmrg 1120428d7b3dSmrg I830DRI2ReferenceBuffer(front); 1121428d7b3dSmrg I830DRI2ReferenceBuffer(back); 1122428d7b3dSmrg 1123428d7b3dSmrg ret = intel_get_crtc_msc_ust(scrn, crtc, ¤t_msc, ¤t_ust); 1124428d7b3dSmrg if (ret) 1125428d7b3dSmrg goto blit_fallback; 1126428d7b3dSmrg 1127428d7b3dSmrg /* Flips need to be submitted one frame before */ 1128428d7b3dSmrg if (can_exchange(draw, front, back)) { 1129428d7b3dSmrg swap_type = DRI2_FLIP; 1130428d7b3dSmrg flip = 1; 1131428d7b3dSmrg } 1132428d7b3dSmrg 1133428d7b3dSmrg swap_info->type = swap_type; 1134428d7b3dSmrg 1135428d7b3dSmrg /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP. 1136428d7b3dSmrg * Do it early, so handling of different timing constraints 1137428d7b3dSmrg * for divisor, remainder and msc vs. target_msc works. 1138428d7b3dSmrg */ 1139428d7b3dSmrg if (*target_msc > 0) 1140428d7b3dSmrg *target_msc -= flip; 1141428d7b3dSmrg 1142428d7b3dSmrg /* 1143428d7b3dSmrg * If divisor is zero, or current_msc is smaller than target_msc 1144428d7b3dSmrg * we just need to make sure target_msc passes before initiating 1145428d7b3dSmrg * the swap. 1146428d7b3dSmrg */ 1147428d7b3dSmrg if (divisor == 0 || current_msc < *target_msc) { 1148428d7b3dSmrg /* 1149428d7b3dSmrg * If we can, schedule the flip directly from here rather 1150428d7b3dSmrg * than waiting for an event from the kernel for the current 1151428d7b3dSmrg * (or a past) MSC. 1152428d7b3dSmrg */ 1153428d7b3dSmrg if (flip && divisor == 0 && current_msc >= *target_msc && 1154428d7b3dSmrg I830DRI2ScheduleFlip(intel, draw, swap_info)) 1155428d7b3dSmrg return TRUE; 1156428d7b3dSmrg 1157428d7b3dSmrg vbl.request.type = 1158428d7b3dSmrg DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 1159428d7b3dSmrg 1160428d7b3dSmrg /* If non-pageflipping, but blitting/exchanging, we need to use 1161428d7b3dSmrg * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later 1162428d7b3dSmrg * on. 1163428d7b3dSmrg */ 1164428d7b3dSmrg if (flip == 0) 1165428d7b3dSmrg vbl.request.type |= DRM_VBLANK_NEXTONMISS; 1166428d7b3dSmrg 1167428d7b3dSmrg /* If target_msc already reached or passed, set it to 1168428d7b3dSmrg * current_msc to ensure we return a reasonable value back 1169428d7b3dSmrg * to the caller. This makes swap_interval logic more robust. 1170428d7b3dSmrg */ 1171428d7b3dSmrg if (current_msc >= *target_msc) 1172428d7b3dSmrg *target_msc = current_msc; 1173428d7b3dSmrg 1174428d7b3dSmrg seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 1175428d7b3dSmrg if (!seq) 1176428d7b3dSmrg goto blit_fallback; 1177428d7b3dSmrg 1178428d7b3dSmrg vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, *target_msc); 1179428d7b3dSmrg vbl.request.signal = seq; 1180428d7b3dSmrg 1181428d7b3dSmrg ret = drmWaitVBlank(intel->drmSubFD, &vbl); 1182428d7b3dSmrg if (ret) { 1183428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1184428d7b3dSmrg "divisor 0 get vblank counter failed: %s\n", 1185428d7b3dSmrg strerror(errno)); 1186428d7b3dSmrg goto blit_fallback; 1187428d7b3dSmrg } 1188428d7b3dSmrg 1189428d7b3dSmrg *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip); 1190428d7b3dSmrg swap_info->frame = *target_msc; 1191428d7b3dSmrg 1192428d7b3dSmrg return TRUE; 1193428d7b3dSmrg } 1194428d7b3dSmrg 1195428d7b3dSmrg /* 1196428d7b3dSmrg * If we get here, target_msc has already passed or we don't have one, 1197428d7b3dSmrg * and we need to queue an event that will satisfy the divisor/remainder 1198428d7b3dSmrg * equation. 1199428d7b3dSmrg */ 1200428d7b3dSmrg vbl.request.type = 1201428d7b3dSmrg DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 1202428d7b3dSmrg if (flip == 0) 1203428d7b3dSmrg vbl.request.type |= DRM_VBLANK_NEXTONMISS; 1204428d7b3dSmrg 1205428d7b3dSmrg request_msc = current_msc - (current_msc % divisor) + 1206428d7b3dSmrg remainder; 1207428d7b3dSmrg 1208428d7b3dSmrg /* 1209428d7b3dSmrg * If the calculated deadline vbl.request.sequence is smaller than 1210428d7b3dSmrg * or equal to current_msc, it means we've passed the last point 1211428d7b3dSmrg * when effective onset frame seq could satisfy 1212428d7b3dSmrg * seq % divisor == remainder, so we need to wait for the next time 1213428d7b3dSmrg * this will happen. 1214428d7b3dSmrg 1215428d7b3dSmrg * This comparison takes the 1 frame swap delay in pageflipping mode 1216428d7b3dSmrg * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay 1217428d7b3dSmrg * if we are blitting/exchanging instead of flipping. 1218428d7b3dSmrg */ 1219428d7b3dSmrg if (request_msc <= current_msc) 1220428d7b3dSmrg request_msc += divisor; 1221428d7b3dSmrg 1222428d7b3dSmrg seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 1223428d7b3dSmrg if (!seq) 1224428d7b3dSmrg goto blit_fallback; 1225428d7b3dSmrg 1226428d7b3dSmrg /* Account for 1 frame extra pageflip delay if flip > 0 */ 1227428d7b3dSmrg vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc) - flip; 1228428d7b3dSmrg vbl.request.signal = seq; 1229428d7b3dSmrg 1230428d7b3dSmrg ret = drmWaitVBlank(intel->drmSubFD, &vbl); 1231428d7b3dSmrg if (ret) { 1232428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1233428d7b3dSmrg "final get vblank counter failed: %s\n", 1234428d7b3dSmrg strerror(errno)); 1235428d7b3dSmrg goto blit_fallback; 1236428d7b3dSmrg } 1237428d7b3dSmrg 1238428d7b3dSmrg /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ 1239428d7b3dSmrg *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip); 1240428d7b3dSmrg swap_info->frame = *target_msc; 1241428d7b3dSmrg 1242428d7b3dSmrg return TRUE; 1243428d7b3dSmrg 1244428d7b3dSmrgblit_fallback: 1245428d7b3dSmrg I830DRI2FallbackBlitSwap(draw, front, back); 1246428d7b3dSmrg DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); 1247428d7b3dSmrg if (swap_info) 1248428d7b3dSmrg i830_dri2_del_frame_event(swap_info); 1249428d7b3dSmrg *target_msc = 0; /* offscreen, so zero out target vblank count */ 1250428d7b3dSmrg return TRUE; 1251428d7b3dSmrg} 1252428d7b3dSmrg 1253428d7b3dSmrgstatic uint64_t gettime_us(void) 1254428d7b3dSmrg{ 1255428d7b3dSmrg struct timespec tv; 1256428d7b3dSmrg 1257428d7b3dSmrg if (clock_gettime(CLOCK_MONOTONIC, &tv)) 1258428d7b3dSmrg return 0; 1259428d7b3dSmrg 1260428d7b3dSmrg return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000; 1261428d7b3dSmrg} 1262428d7b3dSmrg 1263428d7b3dSmrg/* 1264428d7b3dSmrg * Get current frame count and frame count timestamp, based on drawable's 1265428d7b3dSmrg * crtc. 1266428d7b3dSmrg */ 1267428d7b3dSmrgstatic int 1268428d7b3dSmrgI830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 1269428d7b3dSmrg{ 1270428d7b3dSmrg ScreenPtr screen = draw->pScreen; 1271428d7b3dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1272428d7b3dSmrg int ret; 1273428d7b3dSmrg xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 1274428d7b3dSmrg 1275428d7b3dSmrg /* Drawable not displayed, make up a *monotonic* value */ 1276428d7b3dSmrg if (crtc == NULL) { 1277428d7b3dSmrgfail: 1278428d7b3dSmrg *ust = gettime_us(); 1279428d7b3dSmrg *msc = 0; 1280428d7b3dSmrg return TRUE; 1281428d7b3dSmrg } 1282428d7b3dSmrg 1283428d7b3dSmrg ret = intel_get_crtc_msc_ust(scrn, crtc, msc, ust); 1284428d7b3dSmrg if (ret) { 1285428d7b3dSmrg static int limit = 5; 1286428d7b3dSmrg if (limit) { 1287428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1288428d7b3dSmrg "%s:%d get vblank counter failed: %s\n", 1289428d7b3dSmrg __FUNCTION__, __LINE__, 1290428d7b3dSmrg strerror(errno)); 1291428d7b3dSmrg limit--; 1292428d7b3dSmrg } 1293428d7b3dSmrg goto fail; 1294428d7b3dSmrg } 1295428d7b3dSmrg 1296428d7b3dSmrg return TRUE; 1297428d7b3dSmrg} 1298428d7b3dSmrg 1299428d7b3dSmrg/* 1300428d7b3dSmrg * Request a DRM event when the requested conditions will be satisfied. 1301428d7b3dSmrg * 1302428d7b3dSmrg * We need to handle the event and ask the server to wake up the client when 1303428d7b3dSmrg * we receive it. 1304428d7b3dSmrg */ 1305428d7b3dSmrgstatic int 1306428d7b3dSmrgI830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, 1307428d7b3dSmrg CARD64 divisor, CARD64 remainder) 1308428d7b3dSmrg{ 1309428d7b3dSmrg ScreenPtr screen = draw->pScreen; 1310428d7b3dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1311428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 1312428d7b3dSmrg DRI2FrameEventPtr wait_info; 1313428d7b3dSmrg drmVBlank vbl; 1314428d7b3dSmrg int ret; 1315428d7b3dSmrg xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 1316428d7b3dSmrg int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1; 1317428d7b3dSmrg CARD64 current_msc, current_ust, request_msc; 1318428d7b3dSmrg uint32_t seq; 1319428d7b3dSmrg 1320428d7b3dSmrg /* Drawable not visible, return immediately */ 1321428d7b3dSmrg if (pipe == -1) 1322428d7b3dSmrg goto out_complete; 1323428d7b3dSmrg 1324428d7b3dSmrg wait_info = calloc(1, sizeof(DRI2FrameEventRec)); 1325428d7b3dSmrg if (!wait_info) 1326428d7b3dSmrg goto out_complete; 1327428d7b3dSmrg 1328428d7b3dSmrg wait_info->intel = intel; 1329428d7b3dSmrg wait_info->drawable_id = draw->id; 1330428d7b3dSmrg wait_info->client = client; 1331428d7b3dSmrg wait_info->type = DRI2_WAITMSC; 1332428d7b3dSmrg 1333428d7b3dSmrg if (!i830_dri2_add_frame_event(wait_info)) { 1334428d7b3dSmrg free(wait_info); 1335428d7b3dSmrg wait_info = NULL; 1336428d7b3dSmrg goto out_complete; 1337428d7b3dSmrg } 1338428d7b3dSmrg 1339428d7b3dSmrg /* Get current count */ 1340428d7b3dSmrg ret = intel_get_crtc_msc_ust(scrn, crtc, ¤t_msc, ¤t_ust); 1341428d7b3dSmrg if (ret) 1342428d7b3dSmrg goto out_free; 1343428d7b3dSmrg 1344428d7b3dSmrg /* 1345428d7b3dSmrg * If divisor is zero, or current_msc is smaller than target_msc, 1346428d7b3dSmrg * we just need to make sure target_msc passes before waking up the 1347428d7b3dSmrg * client. 1348428d7b3dSmrg */ 1349428d7b3dSmrg if (divisor == 0 || current_msc < target_msc) { 1350428d7b3dSmrg /* If target_msc already reached or passed, set it to 1351428d7b3dSmrg * current_msc to ensure we return a reasonable value back 1352428d7b3dSmrg * to the caller. This keeps the client from continually 1353428d7b3dSmrg * sending us MSC targets from the past by forcibly updating 1354428d7b3dSmrg * their count on this call. 1355428d7b3dSmrg */ 1356428d7b3dSmrg seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 1357428d7b3dSmrg if (!seq) 1358428d7b3dSmrg goto out_free; 1359428d7b3dSmrg 1360428d7b3dSmrg if (current_msc >= target_msc) 1361428d7b3dSmrg target_msc = current_msc; 1362428d7b3dSmrg vbl.request.type = 1363428d7b3dSmrg DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 1364428d7b3dSmrg vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, target_msc); 1365428d7b3dSmrg vbl.request.signal = seq; 1366428d7b3dSmrg 1367428d7b3dSmrg ret = drmWaitVBlank(intel->drmSubFD, &vbl); 1368428d7b3dSmrg if (ret) { 1369428d7b3dSmrg static int limit = 5; 1370428d7b3dSmrg if (limit) { 1371428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1372428d7b3dSmrg "%s:%d get vblank counter failed: %s\n", 1373428d7b3dSmrg __FUNCTION__, __LINE__, 1374428d7b3dSmrg strerror(errno)); 1375428d7b3dSmrg limit--; 1376428d7b3dSmrg } 1377428d7b3dSmrg goto out_free; 1378428d7b3dSmrg } 1379428d7b3dSmrg 1380428d7b3dSmrg wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence); 1381428d7b3dSmrg DRI2BlockClient(client, draw); 1382428d7b3dSmrg return TRUE; 1383428d7b3dSmrg } 1384428d7b3dSmrg 1385428d7b3dSmrg /* 1386428d7b3dSmrg * If we get here, target_msc has already passed or we don't have one, 1387428d7b3dSmrg * so we queue an event that will satisfy the divisor/remainder equation. 1388428d7b3dSmrg */ 1389428d7b3dSmrg vbl.request.type = 1390428d7b3dSmrg DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 1391428d7b3dSmrg 1392428d7b3dSmrg request_msc = current_msc - (current_msc % divisor) + 1393428d7b3dSmrg remainder; 1394428d7b3dSmrg /* 1395428d7b3dSmrg * If calculated remainder is larger than requested remainder, 1396428d7b3dSmrg * it means we've passed the last point where 1397428d7b3dSmrg * seq % divisor == remainder, so we need to wait for the next time 1398428d7b3dSmrg * that will happen. 1399428d7b3dSmrg */ 1400428d7b3dSmrg if ((current_msc % divisor) >= remainder) 1401428d7b3dSmrg request_msc += divisor; 1402428d7b3dSmrg 1403428d7b3dSmrg seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 1404428d7b3dSmrg if (!seq) 1405428d7b3dSmrg goto out_free; 1406428d7b3dSmrg 1407428d7b3dSmrg vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc); 1408428d7b3dSmrg vbl.request.signal = seq; 1409428d7b3dSmrg 1410428d7b3dSmrg ret = drmWaitVBlank(intel->drmSubFD, &vbl); 1411428d7b3dSmrg if (ret) { 1412428d7b3dSmrg static int limit = 5; 1413428d7b3dSmrg if (limit) { 1414428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1415428d7b3dSmrg "%s:%d get vblank counter failed: %s\n", 1416428d7b3dSmrg __FUNCTION__, __LINE__, 1417428d7b3dSmrg strerror(errno)); 1418428d7b3dSmrg limit--; 1419428d7b3dSmrg } 1420428d7b3dSmrg goto out_free; 1421428d7b3dSmrg } 1422428d7b3dSmrg 1423428d7b3dSmrg wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence); 1424428d7b3dSmrg DRI2BlockClient(client, draw); 1425428d7b3dSmrg 1426428d7b3dSmrg return TRUE; 1427428d7b3dSmrg 1428428d7b3dSmrgout_free: 1429428d7b3dSmrg i830_dri2_del_frame_event(wait_info); 1430428d7b3dSmrgout_complete: 1431428d7b3dSmrg DRI2WaitMSCComplete(client, draw, target_msc, 0, 0); 1432428d7b3dSmrg return TRUE; 1433428d7b3dSmrg} 1434428d7b3dSmrg 1435428d7b3dSmrgstatic int dri2_server_generation; 1436428d7b3dSmrg#endif 1437428d7b3dSmrg 1438428d7b3dSmrgstatic int has_i830_dri(void) 1439428d7b3dSmrg{ 1440428d7b3dSmrg return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0; 1441428d7b3dSmrg} 1442428d7b3dSmrg 1443428d7b3dSmrgstatic const char *dri_driver_name(intel_screen_private *intel) 1444428d7b3dSmrg{ 1445428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0) 1446428d7b3dSmrg const char *s = xf86GetOptValString(intel->Options, OPTION_DRI); 1447428d7b3dSmrg Bool dummy; 1448428d7b3dSmrg 1449428d7b3dSmrg if (s == NULL || xf86getBoolValue(&dummy, s)) { 1450428d7b3dSmrg if (INTEL_INFO(intel)->gen < 030) 1451428d7b3dSmrg return has_i830_dri() ? "i830" : "i915"; 1452428d7b3dSmrg else if (INTEL_INFO(intel)->gen < 040) 1453428d7b3dSmrg return "i915"; 1454428d7b3dSmrg else 1455428d7b3dSmrg return "i965"; 1456428d7b3dSmrg } 1457428d7b3dSmrg 1458428d7b3dSmrg return s; 1459428d7b3dSmrg#else 1460428d7b3dSmrg if (INTEL_INFO(intel)->gen < 030) 1461428d7b3dSmrg return has_i830_dri() ? "i830" : "i915"; 1462428d7b3dSmrg else if (INTEL_INFO(intel)->gen < 040) 1463428d7b3dSmrg return "i915"; 1464428d7b3dSmrg else 1465428d7b3dSmrg return "i965"; 1466428d7b3dSmrg#endif 1467428d7b3dSmrg} 1468428d7b3dSmrg 1469428d7b3dSmrgBool I830DRI2ScreenInit(ScreenPtr screen) 1470428d7b3dSmrg{ 1471428d7b3dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1472428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 1473428d7b3dSmrg DRI2InfoRec info; 1474428d7b3dSmrg int dri2scr_major = 1; 1475428d7b3dSmrg int dri2scr_minor = 0; 1476428d7b3dSmrg#if DRI2INFOREC_VERSION >= 4 1477428d7b3dSmrg const char *driverNames[2]; 1478428d7b3dSmrg#endif 1479428d7b3dSmrg 1480428d7b3dSmrg if (intel->force_fallback) { 1481428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1482428d7b3dSmrg "cannot enable DRI2 whilst forcing software fallbacks\n"); 1483428d7b3dSmrg return FALSE; 1484428d7b3dSmrg } 1485428d7b3dSmrg 1486428d7b3dSmrg if (xf86LoaderCheckSymbol("DRI2Version")) 1487428d7b3dSmrg DRI2Version(&dri2scr_major, &dri2scr_minor); 1488428d7b3dSmrg 1489428d7b3dSmrg if (dri2scr_minor < 1) { 1490428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1491428d7b3dSmrg "DRI2 requires DRI2 module version 1.1.0 or later\n"); 1492428d7b3dSmrg return FALSE; 1493428d7b3dSmrg } 1494428d7b3dSmrg 1495428d7b3dSmrg#if HAS_DIXREGISTERPRIVATEKEY 1496428d7b3dSmrg if (!dixRegisterPrivateKey(&i830_client_key, PRIVATE_CLIENT, sizeof(XID))) 1497428d7b3dSmrg return FALSE; 1498428d7b3dSmrg#else 1499428d7b3dSmrg if (!dixRequestPrivate(&i830_client_key, sizeof(XID))) 1500428d7b3dSmrg return FALSE; 1501428d7b3dSmrg#endif 1502428d7b3dSmrg 1503428d7b3dSmrg 1504428d7b3dSmrg#if DRI2INFOREC_VERSION >= 4 1505428d7b3dSmrg if (serverGeneration != dri2_server_generation) { 1506428d7b3dSmrg dri2_server_generation = serverGeneration; 1507428d7b3dSmrg if (!i830_dri2_register_frame_event_resource_types()) { 1508428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1509428d7b3dSmrg "Cannot register DRI2 frame event resources\n"); 1510428d7b3dSmrg return FALSE; 1511428d7b3dSmrg } 1512428d7b3dSmrg } 1513428d7b3dSmrg#endif 1514428d7b3dSmrg 1515428d7b3dSmrg intel->deviceName = drmGetDeviceNameFromFd(intel->drmSubFD); 1516428d7b3dSmrg memset(&info, '\0', sizeof(info)); 1517428d7b3dSmrg info.fd = intel->drmSubFD; 1518428d7b3dSmrg info.driverName = dri_driver_name(intel); 1519428d7b3dSmrg info.deviceName = intel->deviceName; 1520428d7b3dSmrg 1521428d7b3dSmrg#if DRI2INFOREC_VERSION == 1 1522428d7b3dSmrg info.version = 1; 1523428d7b3dSmrg info.CreateBuffers = I830DRI2CreateBuffers; 1524428d7b3dSmrg info.DestroyBuffers = I830DRI2DestroyBuffers; 1525428d7b3dSmrg#elif DRI2INFOREC_VERSION == 2 1526428d7b3dSmrg /* The ABI between 2 and 3 was broken so we could get rid of 1527428d7b3dSmrg * the multi-buffer alloc functions. Make sure we indicate the 1528428d7b3dSmrg * right version so DRI2 can reject us if it's version 3 or above. */ 1529428d7b3dSmrg info.version = 2; 1530428d7b3dSmrg info.CreateBuffer = I830DRI2CreateBuffer; 1531428d7b3dSmrg info.DestroyBuffer = I830DRI2DestroyBuffer; 1532428d7b3dSmrg#else 1533428d7b3dSmrg info.version = 3; 1534428d7b3dSmrg info.CreateBuffer = I830DRI2CreateBuffer; 1535428d7b3dSmrg info.DestroyBuffer = I830DRI2DestroyBuffer; 1536428d7b3dSmrg#endif 1537428d7b3dSmrg 1538428d7b3dSmrg info.CopyRegion = I830DRI2CopyRegion; 1539428d7b3dSmrg#if DRI2INFOREC_VERSION >= 4 1540428d7b3dSmrg info.version = 4; 1541428d7b3dSmrg info.ScheduleSwap = I830DRI2ScheduleSwap; 1542428d7b3dSmrg info.GetMSC = I830DRI2GetMSC; 1543428d7b3dSmrg info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC; 1544428d7b3dSmrg info.numDrivers = 2; 1545428d7b3dSmrg info.driverNames = driverNames; 1546428d7b3dSmrg driverNames[0] = info.driverName; 1547428d7b3dSmrg driverNames[1] = info.driverName; 1548428d7b3dSmrg#endif 1549428d7b3dSmrg 1550428d7b3dSmrg return DRI2ScreenInit(screen, &info); 1551428d7b3dSmrg} 1552428d7b3dSmrg 1553428d7b3dSmrgvoid I830DRI2CloseScreen(ScreenPtr screen) 1554428d7b3dSmrg{ 1555428d7b3dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1556428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 1557428d7b3dSmrg 1558428d7b3dSmrg DRI2CloseScreen(screen); 1559428d7b3dSmrg drmFree(intel->deviceName); 1560428d7b3dSmrg} 1561