1/************************************************************************** 2 3Copyright 2001 VA Linux Systems Inc., Fremont, California. 4Copyright © 2002 by David Dawes 5 6All Rights Reserved. 7 8Permission is hereby granted, free of charge, to any person obtaining a 9copy of this software and associated documentation files (the "Software"), 10to deal in the Software without restriction, including without limitation 11on the rights to use, copy, modify, merge, publish, distribute, sub 12license, and/or sell copies of the Software, and to permit persons to whom 13the Software is furnished to do so, subject to the following conditions: 14 15The above copyright notice and this permission notice (including the next 16paragraph) shall be included in all copies or substantial portions of the 17Software. 18 19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 23DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25USE OR OTHER DEALINGS IN THE SOFTWARE. 26 27**************************************************************************/ 28 29/* 30 * Authors: Jeff Hartmann <jhartmann@valinux.com> 31 * David Dawes <dawes@xfree86.org> 32 * Keith Whitwell <keith@tungstengraphics.com> 33 */ 34 35#ifdef HAVE_CONFIG_H 36#include "config.h" 37#endif 38 39#include <stdio.h> 40#include <string.h> 41#include <assert.h> 42#include <sys/types.h> 43#include <sys/stat.h> 44#include <sys/ioctl.h> 45#include <errno.h> 46#include <unistd.h> 47#include <fcntl.h> 48 49#include "xf86.h" 50#include "xf86_OSproc.h" 51#include "xf86Priv.h" 52 53#include "xf86PciInfo.h" 54#include "xf86Pci.h" 55 56#include "windowstr.h" 57#include "shadow.h" 58 59#include "GL/glxtokens.h" 60 61#include "i830.h" 62#include "i830_dri.h" 63 64#include "i915_drm.h" 65 66#include "dri2.h" 67 68#ifdef DRI2 69#if DRI2INFOREC_VERSION >= 1 70#define USE_DRI2_1_1_0 71#endif 72 73extern XF86ModuleData dri2ModuleData; 74#endif 75 76typedef struct { 77 PixmapPtr pPixmap; 78 unsigned int attachment; 79} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr; 80 81#ifndef USE_DRI2_1_1_0 82static DRI2BufferPtr 83I830DRI2CreateBuffers(DrawablePtr pDraw, unsigned int *attachments, int count) 84{ 85 ScreenPtr pScreen = pDraw->pScreen; 86 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 87 I830Ptr pI830 = I830PTR(pScrn); 88 DRI2BufferPtr buffers; 89 dri_bo *bo; 90 int i; 91 I830DRI2BufferPrivatePtr privates; 92 PixmapPtr pPixmap, pDepthPixmap; 93 94 buffers = xcalloc(count, sizeof *buffers); 95 if (buffers == NULL) 96 return NULL; 97 privates = xcalloc(count, sizeof *privates); 98 if (privates == NULL) { 99 xfree(buffers); 100 return NULL; 101 } 102 103 pDepthPixmap = NULL; 104 for (i = 0; i < count; i++) { 105 if (attachments[i] == DRI2BufferFrontLeft) { 106 pPixmap = get_drawable_pixmap(pDraw); 107 pPixmap->refcnt++; 108 } else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) { 109 pPixmap = pDepthPixmap; 110 pPixmap->refcnt++; 111 } else { 112 unsigned int hint = 0; 113 114 switch (attachments[i]) { 115 case DRI2BufferDepth: 116 if (SUPPORTS_YTILING(pI830)) 117 hint = INTEL_CREATE_PIXMAP_TILING_Y; 118 else 119 hint = INTEL_CREATE_PIXMAP_TILING_X; 120 break; 121 case DRI2BufferFakeFrontLeft: 122 case DRI2BufferFakeFrontRight: 123 case DRI2BufferBackLeft: 124 case DRI2BufferBackRight: 125 hint = INTEL_CREATE_PIXMAP_TILING_X; 126 break; 127 } 128 129 if (!pI830->tiling || 130 (!IS_I965G(pI830) && !pI830->kernel_exec_fencing)) 131 hint = 0; 132 133 pPixmap = (*pScreen->CreatePixmap)(pScreen, 134 pDraw->width, 135 pDraw->height, 136 pDraw->depth, 137 hint); 138 139 } 140 141 if (attachments[i] == DRI2BufferDepth) 142 pDepthPixmap = pPixmap; 143 144 buffers[i].attachment = attachments[i]; 145 buffers[i].pitch = pPixmap->devKind; 146 buffers[i].cpp = pPixmap->drawable.bitsPerPixel / 8; 147 buffers[i].driverPrivate = &privates[i]; 148 buffers[i].flags = 0; /* not tiled */ 149 privates[i].pPixmap = pPixmap; 150 privates[i].attachment = attachments[i]; 151 152 bo = i830_get_pixmap_bo (pPixmap); 153 if (dri_bo_flink(bo, &buffers[i].name) != 0) { 154 /* failed to name buffer */ 155 } 156 157 } 158 159 return buffers; 160} 161 162#else 163 164static DRI2Buffer2Ptr 165I830DRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment, 166 unsigned int format) 167{ 168 ScreenPtr pScreen = pDraw->pScreen; 169 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 170 I830Ptr pI830 = I830PTR(pScrn); 171 DRI2Buffer2Ptr buffer; 172 dri_bo *bo; 173 I830DRI2BufferPrivatePtr privates; 174 PixmapPtr pPixmap; 175 176 buffer = xcalloc(1, sizeof *buffer); 177 if (buffer == NULL) 178 return NULL; 179 privates = xcalloc(1, sizeof *privates); 180 if (privates == NULL) { 181 xfree(buffer); 182 return NULL; 183 } 184 185 if (attachment == DRI2BufferFrontLeft) { 186 pPixmap = get_drawable_pixmap(pDraw); 187 pPixmap->refcnt++; 188 } else { 189 unsigned int hint = 0; 190 191 switch (attachment) { 192 case DRI2BufferDepth: 193 case DRI2BufferDepthStencil: 194 if (SUPPORTS_YTILING(pI830)) 195 hint = INTEL_CREATE_PIXMAP_TILING_Y; 196 else 197 hint = INTEL_CREATE_PIXMAP_TILING_X; 198 break; 199 case DRI2BufferFakeFrontLeft: 200 case DRI2BufferFakeFrontRight: 201 case DRI2BufferBackLeft: 202 case DRI2BufferBackRight: 203 hint = INTEL_CREATE_PIXMAP_TILING_X; 204 break; 205 } 206 207 if (!pI830->tiling || 208 (!IS_I965G(pI830) && !pI830->kernel_exec_fencing)) 209 hint = 0; 210 211 pPixmap = (*pScreen->CreatePixmap)(pScreen, 212 pDraw->width, 213 pDraw->height, 214 (format != 0)?format:pDraw->depth, 215 hint); 216 217 } 218 219 220 buffer->attachment = attachment; 221 buffer->pitch = pPixmap->devKind; 222 buffer->cpp = pPixmap->drawable.bitsPerPixel / 8; 223 buffer->driverPrivate = privates; 224 buffer->format = format; 225 buffer->flags = 0; /* not tiled */ 226 privates->pPixmap = pPixmap; 227 privates->attachment = attachment; 228 229 bo = i830_get_pixmap_bo (pPixmap); 230 if (dri_bo_flink(bo, &buffer->name) != 0) { 231 /* failed to name buffer */ 232 } 233 234 return buffer; 235} 236 237#endif 238 239#ifndef USE_DRI2_1_1_0 240 241static void 242I830DRI2DestroyBuffers(DrawablePtr pDraw, DRI2BufferPtr buffers, int count) 243{ 244 ScreenPtr pScreen = pDraw->pScreen; 245 I830DRI2BufferPrivatePtr private; 246 int i; 247 248 for (i = 0; i < count; i++) 249 { 250 private = buffers[i].driverPrivate; 251 (*pScreen->DestroyPixmap)(private->pPixmap); 252 } 253 254 if (buffers) 255 { 256 xfree(buffers[0].driverPrivate); 257 xfree(buffers); 258 } 259} 260 261#else 262 263static void 264I830DRI2DestroyBuffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer) 265{ 266 if (buffer) { 267 I830DRI2BufferPrivatePtr private = buffer->driverPrivate; 268 ScreenPtr pScreen = pDraw->pScreen; 269 270 (*pScreen->DestroyPixmap)(private->pPixmap); 271 272 xfree(private); 273 xfree(buffer); 274 } 275} 276 277#endif 278 279static void 280I830DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, 281 DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer) 282{ 283 I830DRI2BufferPrivatePtr srcPrivate = pSrcBuffer->driverPrivate; 284 I830DRI2BufferPrivatePtr dstPrivate = pDstBuffer->driverPrivate; 285 ScreenPtr pScreen = pDraw->pScreen; 286 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 287 I830Ptr pI830 = I830PTR(pScrn); 288 DrawablePtr src = (srcPrivate->attachment == DRI2BufferFrontLeft) 289 ? pDraw : &srcPrivate->pPixmap->drawable; 290 DrawablePtr dst = (dstPrivate->attachment == DRI2BufferFrontLeft) 291 ? pDraw : &dstPrivate->pPixmap->drawable; 292 RegionPtr pCopyClip; 293 GCPtr pGC; 294 295 pGC = GetScratchGC(pDraw->depth, pScreen); 296 pCopyClip = REGION_CREATE(pScreen, NULL, 0); 297 REGION_COPY(pScreen, pCopyClip, pRegion); 298 (*pGC->funcs->ChangeClip) (pGC, CT_REGION, pCopyClip, 0); 299 ValidateGC(dst, pGC); 300 301 /* Wait for the scanline to be outside the region to be copied */ 302 if (pixmap_is_scanout(get_drawable_pixmap(dst)) && pI830->swapbuffers_wait) { 303 BoxPtr box; 304 BoxRec crtcbox; 305 int y1, y2; 306 int pipe = -1, event, load_scan_lines_pipe; 307 xf86CrtcPtr crtc; 308 309 box = REGION_EXTENTS(unused, pGC->pCompositeClip); 310 crtc = i830_covering_crtc(pScrn, box, NULL, &crtcbox); 311 312 /* Make sure the CRTC is valid and this is the real front buffer */ 313 if (crtc != NULL && !crtc->rotatedData) { 314 pipe = i830_crtc_to_pipe(crtc); 315 316 if (pipe == 0) { 317 event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; 318 load_scan_lines_pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA; 319 } else { 320 event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW; 321 load_scan_lines_pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB; 322 } 323 324 /* Make sure we don't wait for a scanline that will never occur */ 325 y1 = (crtcbox.y1 <= box->y1) ? box->y1 - crtcbox.y1 : 0; 326 y2 = (box->y2 <= crtcbox.y2) ? 327 box->y2 - crtcbox.y1 : crtcbox.y2 - crtcbox.y1; 328 329 BEGIN_BATCH(5); 330 /* The documentation says that the LOAD_SCAN_LINES command 331 * always comes in pairs. Don't ask me why. */ 332 OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | load_scan_lines_pipe); 333 OUT_BATCH((y1 << 16) | y2); 334 OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | load_scan_lines_pipe); 335 OUT_BATCH((y1 << 16) | y2); 336 OUT_BATCH(MI_WAIT_FOR_EVENT | event); 337 ADVANCE_BATCH(); 338 } 339 } 340 341 (*pGC->ops->CopyArea)(src, dst, 342 pGC, 0, 0, pDraw->width, pDraw->height, 0, 0); 343 FreeScratchGC(pGC); 344 345 /* Emit a flush of the rendering cache, or on the 965 and beyond 346 * rendering results may not hit the framebuffer until significantly 347 * later. 348 */ 349 I830EmitFlush(pScrn); 350 pI830->need_mi_flush = FALSE; 351 352 /* We can't rely on getting into the block handler before the DRI 353 * client gets to run again so flush now. */ 354 intel_batch_flush(pScrn, TRUE); 355#if ALWAYS_SYNC 356 I830Sync(pScrn); 357#endif 358 drmCommandNone(pI830->drmSubFD, DRM_I915_GEM_THROTTLE); 359 360} 361 362Bool I830DRI2ScreenInit(ScreenPtr pScreen) 363{ 364 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 365 I830Ptr pI830 = I830PTR(pScrn); 366 DRI2InfoRec info; 367 char *p; 368 int i; 369 struct stat sbuf; 370 dev_t d; 371#ifdef USE_DRI2_1_1_0 372 int dri2_major = 1; 373 int dri2_minor = 0; 374#endif 375 376#ifdef USE_DRI2_1_1_0 377 if (xf86LoaderCheckSymbol("DRI2Version")) { 378 DRI2Version(& dri2_major, & dri2_minor); 379 } 380 381 if (dri2_minor < 1) { 382 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 383 "DRI2 requires DRI2 module version 1.1.0 or later\n"); 384 return FALSE; 385 } 386#endif 387 388 info.fd = pI830->drmSubFD; 389 390 /* The whole drmOpen thing is a fiasco and we need to find a way 391 * back to just using open(2). For now, however, lets just make 392 * things worse with even more ad hoc directory walking code to 393 * discover the device file name. */ 394 395 fstat(info.fd, &sbuf); 396 d = sbuf.st_rdev; 397 398 p = pI830->deviceName; 399 for (i = 0; i < DRM_MAX_MINOR; i++) { 400 sprintf(p, DRM_DEV_NAME, DRM_DIR_NAME, i); 401 if (stat(p, &sbuf) == 0 && sbuf.st_rdev == d) 402 break; 403 } 404 if (i == DRM_MAX_MINOR) { 405 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 406 "DRI2: failed to open drm device\n"); 407 return FALSE; 408 } 409 410 info.driverName = IS_I965G(pI830) ? "i965" : "i915"; 411 info.deviceName = p; 412 413#if DRI2INFOREC_VERSION >= 3 414 info.version = 3; 415 info.CreateBuffer = I830DRI2CreateBuffer; 416 info.DestroyBuffer = I830DRI2DestroyBuffer; 417#else 418# ifdef USE_DRI2_1_1_0 419 info.version = 2; 420 info.CreateBuffers = NULL; 421 info.DestroyBuffers = NULL; 422 info.CreateBuffer = I830DRI2CreateBuffer; 423 info.DestroyBuffer = I830DRI2DestroyBuffer; 424# else 425 info.version = 1; 426 info.CreateBuffers = I830DRI2CreateBuffers; 427 info.DestroyBuffers = I830DRI2DestroyBuffers; 428# endif 429#endif 430 431 info.CopyRegion = I830DRI2CopyRegion; 432 433 return DRI2ScreenInit(pScreen, &info); 434} 435 436void I830DRI2CloseScreen(ScreenPtr pScreen) 437{ 438 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 439 I830Ptr pI830 = I830PTR(pScrn); 440 441 DRI2CloseScreen(pScreen); 442 pI830->directRenderingType = DRI_NONE; 443} 444