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 */ 55static void 56ephyrPreparePipelinedAccess(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 */ 76static void 77ephyrFinishPipelinedAccess(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 */ 92static Bool 93ephyrPrepareSolid(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 */ 124static void 125ephyrSolid(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 */ 140static void 141ephyrDoneSolid(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 */ 159static Bool 160ephyrPrepareCopy(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 */ 192static void 193ephyrCopy(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 */ 209static void 210ephyrDoneCopy(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 */ 230static Bool 231ephyrCheckComposite(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 */ 246static Bool 247ephyrPrepareComposite(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 */ 278static void 279ephyrComposite(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 292static void 293ephyrDoneComposite(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 */ 310static Bool 311ephyrDownloadFromScreen(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 */ 347static Bool 348ephyrUploadToScreen(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 381static Bool 382ephyrPrepareAccess(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 */ 397static int 398ephyrMarkSync(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 */ 417static void 418ephyrWaitMarker(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 */ 433Bool 434ephyrDrawInit(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 506void 507ephyrDrawEnable(ScreenPtr pScreen) 508{ 509} 510 511void 512ephyrDrawDisable(ScreenPtr pScreen) 513{ 514} 515 516void 517ephyrDrawFini(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 */ 526void 527exaDDXDriverInit(ScreenPtr pScreen) 528{ 529 ExaScreenPriv(pScreen); 530 531 pExaScr->migration = ExaMigrationSmart; 532 pExaScr->checkDirtyCorrectness = TRUE; 533} 534