ephyr_draw.c (14915B)
1 /* 2 * Copyright © 2006 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Eric Anholt <eric@anholt.net> 25 * 26 */ 27 28 #ifdef HAVE_DIX_CONFIG_H 29 #include <dix-config.h> 30 #endif 31 32 #include "ephyr.h" 33 #include "exa_priv.h" 34 #include "fbpict.h" 35 36 #define EPHYR_TRACE_DRAW 0 37 38 #if EPHYR_TRACE_DRAW 39 #define TRACE_DRAW() ErrorF("%s\n", __FUNCTION__); 40 #else 41 #define TRACE_DRAW() do { } while (0) 42 #endif 43 44 /* Use some oddball alignments, to expose issues in alignment handling in EXA. */ 45 #define EPHYR_OFFSET_ALIGN 24 46 #define EPHYR_PITCH_ALIGN 24 47 48 #define EPHYR_OFFSCREEN_SIZE (16 * 1024 * 1024) 49 #define EPHYR_OFFSCREEN_BASE (1 * 1024 * 1024) 50 51 /** 52 * Forces a real devPrivate.ptr for hidden pixmaps, so that we can call down to 53 * fb functions. 54 */ 55 static void 56 ephyrPreparePipelinedAccess(PixmapPtr pPix, int index) 57 { 58 KdScreenPriv(pPix->drawable.pScreen); 59 KdScreenInfo *screen = pScreenPriv->screen; 60 EphyrScrPriv *scrpriv = screen->driver; 61 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 62 63 assert(fakexa->saved_ptrs[index] == NULL); 64 fakexa->saved_ptrs[index] = pPix->devPrivate.ptr; 65 66 if (pPix->devPrivate.ptr != NULL) 67 return; 68 69 pPix->devPrivate.ptr = fakexa->exa->memoryBase + exaGetPixmapOffset(pPix); 70 } 71 72 /** 73 * Restores the original devPrivate.ptr of the pixmap from before we messed with 74 * it. 75 */ 76 static void 77 ephyrFinishPipelinedAccess(PixmapPtr pPix, int index) 78 { 79 KdScreenPriv(pPix->drawable.pScreen); 80 KdScreenInfo *screen = pScreenPriv->screen; 81 EphyrScrPriv *scrpriv = screen->driver; 82 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 83 84 pPix->devPrivate.ptr = fakexa->saved_ptrs[index]; 85 fakexa->saved_ptrs[index] = NULL; 86 } 87 88 /** 89 * Sets up a scratch GC for fbFill, and saves other parameters for the 90 * ephyrSolid implementation. 91 */ 92 static Bool 93 ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg) 94 { 95 ScreenPtr pScreen = pPix->drawable.pScreen; 96 97 KdScreenPriv(pScreen); 98 KdScreenInfo *screen = pScreenPriv->screen; 99 EphyrScrPriv *scrpriv = screen->driver; 100 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 101 ChangeGCVal tmpval[3]; 102 103 ephyrPreparePipelinedAccess(pPix, EXA_PREPARE_DEST); 104 105 fakexa->pDst = pPix; 106 fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen); 107 108 tmpval[0].val = alu; 109 tmpval[1].val = pm; 110 tmpval[2].val = fg; 111 ChangeGC(NullClient, fakexa->pGC, GCFunction | GCPlaneMask | GCForeground, 112 tmpval); 113 114 ValidateGC(&pPix->drawable, fakexa->pGC); 115 116 TRACE_DRAW(); 117 118 return TRUE; 119 } 120 121 /** 122 * Does an fbFill of the rectangle to be drawn. 123 */ 124 static void 125 ephyrSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2) 126 { 127 ScreenPtr pScreen = pPix->drawable.pScreen; 128 129 KdScreenPriv(pScreen); 130 KdScreenInfo *screen = pScreenPriv->screen; 131 EphyrScrPriv *scrpriv = screen->driver; 132 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 133 134 fbFill(&fakexa->pDst->drawable, fakexa->pGC, x1, y1, x2 - x1, y2 - y1); 135 } 136 137 /** 138 * Cleans up the scratch GC created in ephyrPrepareSolid. 139 */ 140 static void 141 ephyrDoneSolid(PixmapPtr pPix) 142 { 143 ScreenPtr pScreen = pPix->drawable.pScreen; 144 145 KdScreenPriv(pScreen); 146 KdScreenInfo *screen = pScreenPriv->screen; 147 EphyrScrPriv *scrpriv = screen->driver; 148 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 149 150 FreeScratchGC(fakexa->pGC); 151 152 ephyrFinishPipelinedAccess(pPix, EXA_PREPARE_DEST); 153 } 154 155 /** 156 * Sets up a scratch GC for fbCopyArea, and saves other parameters for the 157 * ephyrCopy implementation. 158 */ 159 static Bool 160 ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu, 161 Pixel pm) 162 { 163 ScreenPtr pScreen = pDst->drawable.pScreen; 164 165 KdScreenPriv(pScreen); 166 KdScreenInfo *screen = pScreenPriv->screen; 167 EphyrScrPriv *scrpriv = screen->driver; 168 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 169 ChangeGCVal tmpval[2]; 170 171 ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); 172 ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); 173 174 fakexa->pSrc = pSrc; 175 fakexa->pDst = pDst; 176 fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen); 177 178 tmpval[0].val = alu; 179 tmpval[1].val = pm; 180 ChangeGC(NullClient, fakexa->pGC, GCFunction | GCPlaneMask, tmpval); 181 182 ValidateGC(&pDst->drawable, fakexa->pGC); 183 184 TRACE_DRAW(); 185 186 return TRUE; 187 } 188 189 /** 190 * Does an fbCopyArea to take care of the requested copy. 191 */ 192 static void 193 ephyrCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h) 194 { 195 ScreenPtr pScreen = pDst->drawable.pScreen; 196 197 KdScreenPriv(pScreen); 198 KdScreenInfo *screen = pScreenPriv->screen; 199 EphyrScrPriv *scrpriv = screen->driver; 200 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 201 202 fbCopyArea(&fakexa->pSrc->drawable, &fakexa->pDst->drawable, fakexa->pGC, 203 srcX, srcY, w, h, dstX, dstY); 204 } 205 206 /** 207 * Cleans up the scratch GC created in ephyrPrepareCopy. 208 */ 209 static void 210 ephyrDoneCopy(PixmapPtr pDst) 211 { 212 ScreenPtr pScreen = pDst->drawable.pScreen; 213 214 KdScreenPriv(pScreen); 215 KdScreenInfo *screen = pScreenPriv->screen; 216 EphyrScrPriv *scrpriv = screen->driver; 217 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 218 219 FreeScratchGC(fakexa->pGC); 220 221 ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC); 222 ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST); 223 } 224 225 /** 226 * Reports that we can always accelerate the given operation. This may not be 227 * desirable from an EXA testing standpoint -- testing the fallback paths would 228 * be useful, too. 229 */ 230 static Bool 231 ephyrCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, 232 PicturePtr pDstPicture) 233 { 234 /* Exercise the component alpha helper, so fail on this case like a normal 235 * driver 236 */ 237 if (pMaskPicture && pMaskPicture->componentAlpha && op == PictOpOver) 238 return FALSE; 239 240 return TRUE; 241 } 242 243 /** 244 * Saves off the parameters for ephyrComposite. 245 */ 246 static Bool 247 ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, 248 PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, 249 PixmapPtr pDst) 250 { 251 KdScreenPriv(pDst->drawable.pScreen); 252 KdScreenInfo *screen = pScreenPriv->screen; 253 EphyrScrPriv *scrpriv = screen->driver; 254 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 255 256 ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); 257 if (pSrc != NULL) 258 ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); 259 if (pMask != NULL) 260 ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK); 261 262 fakexa->op = op; 263 fakexa->pSrcPicture = pSrcPicture; 264 fakexa->pMaskPicture = pMaskPicture; 265 fakexa->pDstPicture = pDstPicture; 266 fakexa->pSrc = pSrc; 267 fakexa->pMask = pMask; 268 fakexa->pDst = pDst; 269 270 TRACE_DRAW(); 271 272 return TRUE; 273 } 274 275 /** 276 * Does an fbComposite to complete the requested drawing operation. 277 */ 278 static void 279 ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, 280 int dstX, int dstY, int w, int h) 281 { 282 KdScreenPriv(pDst->drawable.pScreen); 283 KdScreenInfo *screen = pScreenPriv->screen; 284 EphyrScrPriv *scrpriv = screen->driver; 285 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 286 287 fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture, 288 fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY, 289 w, h); 290 } 291 292 static void 293 ephyrDoneComposite(PixmapPtr pDst) 294 { 295 KdScreenPriv(pDst->drawable.pScreen); 296 KdScreenInfo *screen = pScreenPriv->screen; 297 EphyrScrPriv *scrpriv = screen->driver; 298 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 299 300 if (fakexa->pMask != NULL) 301 ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK); 302 if (fakexa->pSrc != NULL) 303 ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC); 304 ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST); 305 } 306 307 /** 308 * Does fake acceleration of DownloadFromScren using memcpy. 309 */ 310 static Bool 311 ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst, 312 int dst_pitch) 313 { 314 KdScreenPriv(pSrc->drawable.pScreen); 315 KdScreenInfo *screen = pScreenPriv->screen; 316 EphyrScrPriv *scrpriv = screen->driver; 317 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 318 unsigned char *src; 319 int src_pitch, cpp; 320 321 if (pSrc->drawable.bitsPerPixel < 8) 322 return FALSE; 323 324 ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); 325 326 cpp = pSrc->drawable.bitsPerPixel / 8; 327 src_pitch = exaGetPixmapPitch(pSrc); 328 src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc); 329 src += y * src_pitch + x * cpp; 330 331 for (; h > 0; h--) { 332 memcpy(dst, src, w * cpp); 333 dst += dst_pitch; 334 src += src_pitch; 335 } 336 337 exaMarkSync(pSrc->drawable.pScreen); 338 339 ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC); 340 341 return TRUE; 342 } 343 344 /** 345 * Does fake acceleration of UploadToScreen using memcpy. 346 */ 347 static Bool 348 ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src, 349 int src_pitch) 350 { 351 KdScreenPriv(pDst->drawable.pScreen); 352 KdScreenInfo *screen = pScreenPriv->screen; 353 EphyrScrPriv *scrpriv = screen->driver; 354 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 355 unsigned char *dst; 356 int dst_pitch, cpp; 357 358 if (pDst->drawable.bitsPerPixel < 8) 359 return FALSE; 360 361 ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); 362 363 cpp = pDst->drawable.bitsPerPixel / 8; 364 dst_pitch = exaGetPixmapPitch(pDst); 365 dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst); 366 dst += y * dst_pitch + x * cpp; 367 368 for (; h > 0; h--) { 369 memcpy(dst, src, w * cpp); 370 dst += dst_pitch; 371 src += src_pitch; 372 } 373 374 exaMarkSync(pDst->drawable.pScreen); 375 376 ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST); 377 378 return TRUE; 379 } 380 381 static Bool 382 ephyrPrepareAccess(PixmapPtr pPix, int index) 383 { 384 /* Make sure we don't somehow end up with a pointer that is in framebuffer 385 * and hasn't been readied for us. 386 */ 387 assert(pPix->devPrivate.ptr != NULL); 388 389 return TRUE; 390 } 391 392 /** 393 * In fakexa, we currently only track whether we have synced to the latest 394 * "accelerated" drawing that has happened or not. It's not used for anything 395 * yet. 396 */ 397 static int 398 ephyrMarkSync(ScreenPtr pScreen) 399 { 400 KdScreenPriv(pScreen); 401 KdScreenInfo *screen = pScreenPriv->screen; 402 EphyrScrPriv *scrpriv = screen->driver; 403 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 404 405 fakexa->is_synced = FALSE; 406 407 return 0; 408 } 409 410 /** 411 * Assumes that we're waiting on the latest marker. When EXA gets smarter and 412 * starts using markers in a fine-grained way (for example, waiting on drawing 413 * to required pixmaps to complete, rather than waiting for all drawing to 414 * complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker 415 * implementation fine-grained as well. 416 */ 417 static void 418 ephyrWaitMarker(ScreenPtr pScreen, int marker) 419 { 420 KdScreenPriv(pScreen); 421 KdScreenInfo *screen = pScreenPriv->screen; 422 EphyrScrPriv *scrpriv = screen->driver; 423 EphyrFakexaPriv *fakexa = scrpriv->fakexa; 424 425 fakexa->is_synced = TRUE; 426 } 427 428 /** 429 * This function initializes EXA to use the fake acceleration implementation 430 * which just falls through to software. The purpose is to have a reliable, 431 * correct driver with which to test changes to the EXA core. 432 */ 433 Bool 434 ephyrDrawInit(ScreenPtr pScreen) 435 { 436 KdScreenPriv(pScreen); 437 KdScreenInfo *screen = pScreenPriv->screen; 438 EphyrScrPriv *scrpriv = screen->driver; 439 EphyrPriv *priv = screen->card->driver; 440 EphyrFakexaPriv *fakexa; 441 Bool success; 442 443 fakexa = calloc(1, sizeof(*fakexa)); 444 if (fakexa == NULL) 445 return FALSE; 446 447 fakexa->exa = exaDriverAlloc(); 448 if (fakexa->exa == NULL) { 449 free(fakexa); 450 return FALSE; 451 } 452 453 fakexa->exa->memoryBase = (CARD8 *) (priv->base); 454 fakexa->exa->memorySize = priv->bytes_per_line * ephyrBufferHeight(screen); 455 fakexa->exa->offScreenBase = priv->bytes_per_line * screen->height; 456 457 /* Since we statically link against EXA, we shouldn't have to be smart about 458 * versioning. 459 */ 460 fakexa->exa->exa_major = 2; 461 fakexa->exa->exa_minor = 0; 462 463 fakexa->exa->PrepareSolid = ephyrPrepareSolid; 464 fakexa->exa->Solid = ephyrSolid; 465 fakexa->exa->DoneSolid = ephyrDoneSolid; 466 467 fakexa->exa->PrepareCopy = ephyrPrepareCopy; 468 fakexa->exa->Copy = ephyrCopy; 469 fakexa->exa->DoneCopy = ephyrDoneCopy; 470 471 fakexa->exa->CheckComposite = ephyrCheckComposite; 472 fakexa->exa->PrepareComposite = ephyrPrepareComposite; 473 fakexa->exa->Composite = ephyrComposite; 474 fakexa->exa->DoneComposite = ephyrDoneComposite; 475 476 fakexa->exa->DownloadFromScreen = ephyrDownloadFromScreen; 477 fakexa->exa->UploadToScreen = ephyrUploadToScreen; 478 479 fakexa->exa->MarkSync = ephyrMarkSync; 480 fakexa->exa->WaitMarker = ephyrWaitMarker; 481 482 fakexa->exa->PrepareAccess = ephyrPrepareAccess; 483 484 fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN; 485 fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN; 486 487 fakexa->exa->maxX = 1023; 488 fakexa->exa->maxY = 1023; 489 490 fakexa->exa->flags = EXA_OFFSCREEN_PIXMAPS; 491 492 success = exaDriverInit(pScreen, fakexa->exa); 493 if (success) { 494 ErrorF("Initialized fake EXA acceleration\n"); 495 scrpriv->fakexa = fakexa; 496 } 497 else { 498 ErrorF("Failed to initialize EXA\n"); 499 free(fakexa->exa); 500 free(fakexa); 501 } 502 503 return success; 504 } 505 506 void 507 ephyrDrawEnable(ScreenPtr pScreen) 508 { 509 } 510 511 void 512 ephyrDrawDisable(ScreenPtr pScreen) 513 { 514 } 515 516 void 517 ephyrDrawFini(ScreenPtr pScreen) 518 { 519 } 520 521 /** 522 * exaDDXDriverInit is required by the top-level EXA module, and is used by 523 * the xorg DDX to hook in its EnableDisableFB wrapper. We don't need it, since 524 * we won't be enabling/disabling the FB. 525 */ 526 void 527 exaDDXDriverInit(ScreenPtr pScreen) 528 { 529 ExaScreenPriv(pScreen); 530 531 pExaScr->migration = ExaMigrationSmart; 532 pExaScr->checkDirtyCorrectness = TRUE; 533 }