1 /* 2 * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. 3 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. 4 * Copyright 2006 Thomas Hellstrm. All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sub license, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 */ 25 26 /* 27 * 2D acceleration functions for the VIA/S3G UniChrome IGPs. 28 * 29 * Mostly rewritten, and modified for EXA support, by Thomas Hellstrm. 30 */ 31 32 #ifdef HAVE_CONFIG_H 33 #include "config.h" 34 #endif 35 36 #include <X11/Xarch.h> 37 #include "miline.h" 38 39 #include "via_driver.h" 40 #include "via_regs.h" 41 #include "via_dmabuffer.h" 42 #include "via_rop.h" 43 44 /* 45 * Emit clipping borders to the command buffer and update the 2D context 46 * current command with clipping info. 47 */ 48 static int 49 viaAccelClippingHelper_H2(VIAPtr pVia, int refY) 50 { 51 ViaTwodContext *tdc = &pVia->td; 52 53 RING_VARS; 54 55 if (tdc->clipping) { 56 refY = (refY < tdc->clipY1) ? refY : tdc->clipY1; 57 tdc->cmd |= VIA_GEC_CLIP_ENABLE; 58 BEGIN_RING(4); 59 OUT_RING_H1(VIA_REG_CLIPTL, 60 ((tdc->clipY1 - refY) << 16) | tdc->clipX1); 61 OUT_RING_H1(VIA_REG_CLIPBR, 62 ((tdc->clipY2 - refY) << 16) | tdc->clipX2); 63 } else { 64 tdc->cmd &= ~VIA_GEC_CLIP_ENABLE; 65 } 66 return refY; 67 } 68 69 /* 70 * Check if we can use a planeMask and update the 2D context accordingly. 71 */ 72 static Bool 73 viaAccelPlaneMaskHelper_H2(ViaTwodContext * tdc, CARD32 planeMask) 74 { 75 CARD32 modeMask = (1 << ((1 << tdc->bytesPPShift) << 3)) - 1; 76 CARD32 curMask = 0x00000000; 77 CARD32 curByteMask; 78 int i; 79 80 if ((planeMask & modeMask) != modeMask) { 81 82 /* Masking doesn't work in 8bpp. */ 83 if (modeMask == 0xFF) { 84 tdc->keyControl &= 0x0FFFFFFF; 85 return FALSE; 86 } 87 88 /* Translate the bit planemask to a byte planemask. */ 89 for (i = 0; i < (1 << tdc->bytesPPShift); ++i) { 90 curByteMask = (0xFF << (i << 3)); 91 92 if ((planeMask & curByteMask) == 0) { 93 curMask |= (1 << i); 94 } else if ((planeMask & curByteMask) != curByteMask) { 95 tdc->keyControl &= 0x0FFFFFFF; 96 return FALSE; 97 } 98 } 99 ErrorF("DEBUG: planeMask 0x%08x, curMask 0%02x\n", 100 (unsigned)planeMask, (unsigned)curMask); 101 102 tdc->keyControl = (tdc->keyControl & 0x0FFFFFFF) | (curMask << 28); 103 } 104 105 return TRUE; 106 } 107 108 /* 109 * Emit transparency state and color to the command buffer. 110 */ 111 static void 112 viaAccelTransparentHelper_H2(VIAPtr pVia, CARD32 keyControl, 113 CARD32 transColor, Bool usePlaneMask) 114 { 115 ViaTwodContext *tdc = &pVia->td; 116 117 RING_VARS; 118 119 tdc->keyControl &= ((usePlaneMask) ? 0xF0000000 : 0x00000000); 120 tdc->keyControl |= (keyControl & 0x0FFFFFFF); 121 BEGIN_RING(4); 122 OUT_RING_H1(VIA_REG_KEYCONTROL, tdc->keyControl); 123 if (keyControl) { 124 OUT_RING_H1(VIA_REG_SRCCOLORKEY, transColor); 125 } 126 } 127 128 /* 129 * Mark Sync using the 2D blitter for AGP. NoOp for PCI. 130 * In the future one could even launch a NULL PCI DMA command 131 * to have an interrupt generated, provided it is possible to 132 * write to the PCI DMA engines from the AGP command stream. 133 */ 134 int 135 viaAccelMarkSync_H2(ScreenPtr pScreen) 136 { 137 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 138 VIAPtr pVia = VIAPTR(pScrn); 139 140 RING_VARS; 141 142 ++pVia->curMarker; 143 144 /* Wrap around without affecting the sign bit. */ 145 pVia->curMarker &= 0x7FFFFFFF; 146 147 if (pVia->agpDMA) { 148 BEGIN_RING(16); 149 OUT_RING_H1(VIA_REG_KEYCONTROL, 0x00); 150 OUT_RING_H1(VIA_REG_GEMODE, VIA_GEM_32bpp); 151 OUT_RING_H1(VIA_REG_DSTBASE, pVia->markerOffset >> 3); 152 OUT_RING_H1(VIA_REG_PITCH, VIA_PITCH_ENABLE); 153 OUT_RING_H1(VIA_REG_DSTPOS, 0); 154 OUT_RING_H1(VIA_REG_DIMENSION, 0); 155 OUT_RING_H1(VIA_REG_FGCOLOR, pVia->curMarker); 156 OUT_RING_H1(VIA_REG_GECMD, (0xF0 << 24) | VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT); 157 158 ADVANCE_RING; 159 } 160 return pVia->curMarker; 161 } 162 163 /* 164 * Exa functions. It is assumed that EXA does not exceed the blitter limits. 165 */ 166 Bool 167 viaExaPrepareSolid_H2(PixmapPtr pPixmap, int alu, Pixel planeMask, Pixel fg) 168 { 169 ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen); 170 VIAPtr pVia = VIAPTR(pScrn); 171 ViaTwodContext *tdc = &pVia->td; 172 173 if (exaGetPixmapPitch(pPixmap) & 7) 174 return FALSE; 175 176 if (!viaAccelSetMode(pPixmap->drawable.depth, tdc)) 177 return FALSE; 178 179 if (!viaAccelPlaneMaskHelper_H2(tdc, planeMask)) 180 return FALSE; 181 182 viaAccelTransparentHelper_H2(pVia, 0x0, 0x0, TRUE); 183 184 tdc->cmd = VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT | VIAACCELPATTERNROP(alu); 185 186 tdc->fgColor = fg; 187 188 return TRUE; 189 } 190 191 void 192 viaExaSolid_H2(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) 193 { 194 ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen); 195 CARD32 dstOffset = exaGetPixmapOffset(pPixmap); 196 CARD32 dstPitch = exaGetPixmapPitch(pPixmap); 197 int w = x2 - x1, h = y2 - y1; 198 VIAPtr pVia = VIAPTR(pScrn); 199 ViaTwodContext *tdc = &pVia->td; 200 201 RING_VARS; 202 203 BEGIN_RING(14); 204 OUT_RING_H1(VIA_REG_GEMODE, tdc->mode); 205 OUT_RING_H1(VIA_REG_DSTBASE, dstOffset >> 3); 206 OUT_RING_H1(VIA_REG_PITCH, VIA_PITCH_ENABLE | (dstPitch >> 3) << 16); 207 OUT_RING_H1(VIA_REG_DSTPOS, (y1 << 16) | (x1 & 0xFFFF)); 208 OUT_RING_H1(VIA_REG_DIMENSION, ((h - 1) << 16) | (w - 1)); 209 OUT_RING_H1(VIA_REG_FGCOLOR, tdc->fgColor); 210 OUT_RING_H1(VIA_REG_GECMD, tdc->cmd); 211 212 ADVANCE_RING; 213 } 214 215 void 216 viaExaDoneSolidCopy_H2(PixmapPtr pPixmap) 217 { 218 } 219 220 Bool 221 viaExaPrepareCopy_H2(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, 222 int ydir, int alu, Pixel planeMask) 223 { 224 ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen); 225 VIAPtr pVia = VIAPTR(pScrn); 226 ViaTwodContext *tdc = &pVia->td; 227 228 if (pSrcPixmap->drawable.bitsPerPixel != pDstPixmap->drawable.bitsPerPixel) 229 return FALSE; 230 231 if ((tdc->srcPitch = exaGetPixmapPitch(pSrcPixmap)) & 3) 232 return FALSE; 233 234 if (exaGetPixmapPitch(pDstPixmap) & 7) 235 return FALSE; 236 237 tdc->srcOffset = exaGetPixmapOffset(pSrcPixmap); 238 239 tdc->cmd = VIA_GEC_BLT | VIAACCELCOPYROP(alu); 240 if (xdir < 0) 241 tdc->cmd |= VIA_GEC_DECX; 242 if (ydir < 0) 243 tdc->cmd |= VIA_GEC_DECY; 244 245 if (!viaAccelSetMode(pDstPixmap->drawable.bitsPerPixel, tdc)) 246 return FALSE; 247 248 if (!viaAccelPlaneMaskHelper_H2(tdc, planeMask)) 249 return FALSE; 250 viaAccelTransparentHelper_H2(pVia, 0x0, 0x0, TRUE); 251 252 return TRUE; 253 } 254 255 void 256 viaExaCopy_H2(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, 257 int width, int height) 258 { 259 ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen); 260 CARD32 dstOffset = exaGetPixmapOffset(pDstPixmap), val; 261 CARD32 dstPitch = exaGetPixmapPitch(pDstPixmap); 262 VIAPtr pVia = VIAPTR(pScrn); 263 ViaTwodContext *tdc = &pVia->td; 264 265 if (!width || !height) 266 return; 267 268 if (tdc->cmd & VIA_GEC_DECY) { 269 srcY += height - 1; 270 dstY += height - 1; 271 } 272 273 if (tdc->cmd & VIA_GEC_DECX) { 274 srcX += width - 1; 275 dstX += width - 1; 276 } 277 val = VIA_PITCH_ENABLE | (dstPitch >> 3) << 16 | (tdc->srcPitch >> 3); 278 279 RING_VARS; 280 281 BEGIN_RING(16); 282 OUT_RING_H1(VIA_REG_GEMODE, tdc->mode); 283 OUT_RING_H1(VIA_REG_SRCBASE, tdc->srcOffset >> 3); 284 OUT_RING_H1(VIA_REG_DSTBASE, dstOffset >> 3); 285 OUT_RING_H1(VIA_REG_PITCH, val); 286 OUT_RING_H1(VIA_REG_SRCPOS, (srcY << 16) | (srcX & 0xFFFF)); 287 OUT_RING_H1(VIA_REG_DSTPOS, (dstY << 16) | (dstX & 0xFFFF)); 288 OUT_RING_H1(VIA_REG_DIMENSION, ((height - 1) << 16) | (width - 1)); 289 OUT_RING_H1(VIA_REG_GECMD, tdc->cmd); 290 291 ADVANCE_RING; 292 } 293 294 Bool 295 viaExaCheckComposite_H2(int op, PicturePtr pSrcPicture, 296 PicturePtr pMaskPicture, PicturePtr pDstPicture) 297 { 298 ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPicture->pDrawable->pScreen); 299 VIAPtr pVia = VIAPTR(pScrn); 300 Via3DState *v3d = &pVia->v3d; 301 302 if (!pSrcPicture->pDrawable) 303 return FALSE; 304 305 /* Reject small composites early. They are done much faster in software. */ 306 if (!pSrcPicture->repeat && 307 pSrcPicture->pDrawable->width * 308 pSrcPicture->pDrawable->height < VIA_MIN_COMPOSITE) 309 return FALSE; 310 311 if (pMaskPicture && pMaskPicture->pDrawable && 312 !pMaskPicture->repeat && 313 pMaskPicture->pDrawable->width * 314 pMaskPicture->pDrawable->height < VIA_MIN_COMPOSITE) 315 return FALSE; 316 317 if (pMaskPicture && pMaskPicture->repeat && 318 pMaskPicture->repeatType != RepeatNormal) 319 return FALSE; 320 321 if (pMaskPicture && pMaskPicture->componentAlpha) { 322 #ifdef VIA_DEBUG_COMPOSITE 323 viaExaPrintCompositeInfo("Component Alpha operation", op, pSrcPicture, pMaskPicture, pDstPicture); 324 #endif 325 return FALSE; 326 } 327 328 if (!v3d->opSupported(op)) { 329 #ifdef VIA_DEBUG_COMPOSITE 330 viaExaPrintCompositeInfo("Operator not supported", op, pSrcPicture, pMaskPicture, pDstPicture); 331 #endif 332 return FALSE; 333 } 334 335 /* 336 * FIXME: A8 destination formats are currently not supported and do not 337 * seem supported by the hardware, although there are some leftover 338 * register settings apparent in the via_3d_reg.h file. We need to fix this 339 * (if important), by using component ARGB8888 operations with bitmask. 340 */ 341 342 if (!v3d->dstSupported(pDstPicture->format)) { 343 #ifdef VIA_DEBUG_COMPOSITE 344 viaExaPrintCompositeInfo(" Destination format not supported", op, pSrcPicture, pMaskPicture, pDstPicture); 345 #endif 346 return FALSE; 347 } 348 349 if (v3d->texSupported(pSrcPicture->format)) { 350 if (pMaskPicture && (PICT_FORMAT_A(pMaskPicture->format) == 0 || 351 !v3d->texSupported(pMaskPicture->format))) { 352 #ifdef VIA_DEBUG_COMPOSITE 353 viaExaPrintCompositeInfo("Mask format not supported", op, pSrcPicture, pMaskPicture, pDstPicture); 354 #endif 355 return FALSE; 356 } 357 return TRUE; 358 } 359 #ifdef VIA_DEBUG_COMPOSITE 360 viaExaPrintCompositeInfo("Src format not supported", op, pSrcPicture, pMaskPicture, pDstPicture); 361 #endif 362 return FALSE; 363 } 364 365 static Bool 366 viaIsAGP(VIAPtr pVia, PixmapPtr pPix, unsigned long *offset) 367 { 368 #ifdef HAVE_DRI 369 unsigned long offs; 370 371 if (pVia->directRenderingType && !pVia->IsPCI) { 372 offs = ((unsigned long)pPix->devPrivate.ptr 373 - (unsigned long)pVia->agpMappedAddr); 374 375 if ((offs - pVia->scratchOffset) < pVia->agpSize) { 376 *offset = offs + pVia->agpAddr; 377 return TRUE; 378 } 379 } 380 #endif 381 return FALSE; 382 } 383 384 static Bool 385 viaExaIsOffscreen(PixmapPtr pPix) 386 { 387 ScrnInfoPtr pScrn = xf86ScreenToScrn(pPix->drawable.pScreen); 388 VIAPtr pVia = VIAPTR(pScrn); 389 390 return ((unsigned long)pPix->devPrivate.ptr - 391 (unsigned long) drm_bo_map(pScrn, pVia->drmmode.front_bo)) < pVia->drmmode.front_bo->size; 392 } 393 394 Bool 395 viaExaPrepareComposite_H2(int op, PicturePtr pSrcPicture, 396 PicturePtr pMaskPicture, PicturePtr pDstPicture, 397 PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) 398 { 399 CARD32 height, width; 400 ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen); 401 VIAPtr pVia = VIAPTR(pScrn); 402 Via3DState *v3d = &pVia->v3d; 403 int curTex = 0; 404 ViaTexBlendingModes srcMode; 405 Bool isAGP; 406 unsigned long offset; 407 408 /* Workaround: EXA crash with new libcairo2 on a VIA VX800 (#298) */ 409 /* TODO Add real source only pictures */ 410 if (!pSrc) { 411 ErrorF("pSrc is NULL\n"); 412 return FALSE; 413 } 414 415 v3d->setDestination(v3d, exaGetPixmapOffset(pDst), 416 exaGetPixmapPitch(pDst), pDstPicture->format); 417 v3d->setCompositeOperator(v3d, op); 418 v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, 0x000000FF, 0xFF); 419 420 viaOrder(pSrc->drawable.width, &width); 421 viaOrder(pSrc->drawable.height, &height); 422 423 /* 424 * For one-pixel repeat mask pictures we avoid using multitexturing by 425 * modifying the src's texture blending equation and feed the pixel 426 * value as a constant alpha for the src's texture. Multitexturing on the 427 * Unichromes seems somewhat slow, so this speeds up translucent windows. 428 */ 429 430 srcMode = via_src; 431 pVia->maskP = NULL; 432 if (pMaskPicture && 433 (pMaskPicture->pDrawable->height == 1) && 434 (pMaskPicture->pDrawable->width == 1) && 435 pMaskPicture->repeat && viaExpandablePixel(pMaskPicture->format)) { 436 pVia->maskP = pMask->devPrivate.ptr; 437 pVia->maskFormat = pMaskPicture->format; 438 pVia->componentAlpha = pMaskPicture->componentAlpha; 439 srcMode = ((pMaskPicture->componentAlpha) 440 ? via_src_onepix_comp_mask : via_src_onepix_mask); 441 } 442 443 /* 444 * One-Pixel repeat src pictures go as solid color instead of textures. 445 * Speeds up window shadows. 446 */ 447 448 pVia->srcP = NULL; 449 if (pSrcPicture && pSrcPicture->repeat 450 && (pSrcPicture->pDrawable->height == 1) 451 && (pSrcPicture->pDrawable->width == 1) 452 && viaExpandablePixel(pSrcPicture->format)) { 453 pVia->srcP = pSrc->devPrivate.ptr; 454 pVia->srcFormat = pSrcPicture->format; 455 } 456 457 /* Exa should be smart enough to eliminate this IN operation. */ 458 if (pVia->srcP && pVia->maskP) { 459 ErrorF("Bad one-pixel IN composite operation. " 460 "EXA needs to be smarter.\n"); 461 return FALSE; 462 } 463 464 if (!pVia->srcP) { 465 offset = exaGetPixmapOffset(pSrc); 466 isAGP = viaIsAGP(pVia, pSrc, &offset); 467 if (!isAGP && !viaExaIsOffscreen(pSrc)) 468 return FALSE; 469 if (!v3d->setTexture(v3d, curTex, offset, 470 exaGetPixmapPitch(pSrc), pVia->nPOT[curTex], 471 1 << width, 1 << height, pSrcPicture->format, 472 via_repeat, via_repeat, srcMode, isAGP)) { 473 return FALSE; 474 } 475 curTex++; 476 } 477 478 if (pMaskPicture && !pVia->maskP) { 479 offset = exaGetPixmapOffset(pMask); 480 isAGP = viaIsAGP(pVia, pMask, &offset); 481 if (!isAGP && !viaExaIsOffscreen(pMask)) 482 return FALSE; 483 viaOrder(pMask->drawable.width, &width); 484 viaOrder(pMask->drawable.height, &height); 485 if (!v3d->setTexture(v3d, curTex, offset, 486 exaGetPixmapPitch(pMask), pVia->nPOT[curTex], 487 1 << width, 1 << height, pMaskPicture->format, 488 via_repeat, via_repeat, 489 ((pMaskPicture->componentAlpha) 490 ? via_comp_mask : via_mask), isAGP)) { 491 return FALSE; 492 } 493 curTex++; 494 } 495 496 v3d->setFlags(v3d, curTex, FALSE, TRUE, TRUE); 497 v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d)); 498 v3d->emitClipRect(v3d, &pVia->cb, 0, 0, pDst->drawable.width, 499 pDst->drawable.height); 500 501 return TRUE; 502 } 503 504 void 505 viaExaComposite_H2(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, 506 int dstX, int dstY, int width, int height) 507 { 508 ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen); 509 VIAPtr pVia = VIAPTR(pScrn); 510 Via3DState *v3d = &pVia->v3d; 511 CARD32 col; 512 513 if (pVia->maskP) { 514 viaPixelARGB8888(pVia->maskFormat, pVia->maskP, &col); 515 v3d->setTexBlendCol(v3d, 0, pVia->componentAlpha, col); 516 } 517 if (pVia->srcP) { 518 viaPixelARGB8888(pVia->srcFormat, pVia->srcP, &col); 519 v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, col & 0x00FFFFFF, col >> 24); 520 srcX = maskX; 521 srcY = maskY; 522 } 523 524 if (pVia->maskP || pVia->srcP) 525 v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d)); 526 527 v3d->emitQuad(v3d, &pVia->cb, dstX, dstY, srcX, srcY, maskX, maskY, 528 width, height); 529 } 530 531 void 532 viaAccelTextureBlit(ScrnInfoPtr pScrn, unsigned long srcOffset, 533 unsigned srcPitch, unsigned w, unsigned h, unsigned srcX, 534 unsigned srcY, unsigned srcFormat, unsigned long dstOffset, 535 unsigned dstPitch, unsigned dstX, unsigned dstY, 536 unsigned dstFormat, int rotate) 537 { 538 VIAPtr pVia = VIAPTR(pScrn); 539 CARD32 wOrder, hOrder; 540 Via3DState *v3d = &pVia->v3d; 541 542 viaOrder(w, &wOrder); 543 viaOrder(h, &hOrder); 544 545 v3d->setDestination(v3d, dstOffset, dstPitch, dstFormat); 546 v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, 0x000000FF, 0x00); 547 v3d->setFlags(v3d, 1, TRUE, TRUE, FALSE); 548 v3d->setTexture(v3d, 0, srcOffset, srcPitch, TRUE, 549 1 << wOrder, 1 << hOrder, srcFormat, 550 via_single, via_single, via_src, FALSE); 551 v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d)); 552 v3d->emitClipRect(v3d, &pVia->cb, dstX, dstY, w, h); 553 v3d->emitQuad(v3d, &pVia->cb, dstX, dstY, srcX, srcY, 0, 0, w, h); 554 } 555