via_exa_h2.c revision 90b17f1b
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 Hellström. 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 Hellström. 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 */ 48static int 49viaAccelClippingHelper_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 */ 72static Bool 73viaAccelPlaneMaskHelper_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 */ 111static void 112viaAccelTransparentHelper_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 */ 134int 135viaAccelMarkSync_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 */ 166Bool 167viaExaPrepareSolid_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 RING_VARS; 174 175 if (exaGetPixmapPitch(pPixmap) & 7) 176 return FALSE; 177 178 if (!viaAccelSetMode(pPixmap->drawable.depth, tdc)) 179 return FALSE; 180 181 if (!viaAccelPlaneMaskHelper_H2(tdc, planeMask)) 182 return FALSE; 183 184 viaAccelTransparentHelper_H2(pVia, 0x0, 0x0, TRUE); 185 186 tdc->cmd = VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT | VIAACCELPATTERNROP(alu); 187 188 tdc->fgColor = fg; 189 190 return TRUE; 191} 192 193void 194viaExaSolid_H2(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) 195{ 196 ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen); 197 CARD32 dstOffset = exaGetPixmapOffset(pPixmap); 198 CARD32 dstPitch = exaGetPixmapPitch(pPixmap); 199 int w = x2 - x1, h = y2 - y1; 200 VIAPtr pVia = VIAPTR(pScrn); 201 ViaTwodContext *tdc = &pVia->td; 202 203 RING_VARS; 204 205 BEGIN_RING(14); 206 OUT_RING_H1(VIA_REG_GEMODE, tdc->mode); 207 OUT_RING_H1(VIA_REG_DSTBASE, dstOffset >> 3); 208 OUT_RING_H1(VIA_REG_PITCH, VIA_PITCH_ENABLE | (dstPitch >> 3) << 16); 209 OUT_RING_H1(VIA_REG_DSTPOS, (y1 << 16) | (x1 & 0xFFFF)); 210 OUT_RING_H1(VIA_REG_DIMENSION, ((h - 1) << 16) | (w - 1)); 211 OUT_RING_H1(VIA_REG_FGCOLOR, tdc->fgColor); 212 OUT_RING_H1(VIA_REG_GECMD, tdc->cmd); 213 214 ADVANCE_RING; 215} 216 217void 218viaExaDoneSolidCopy_H2(PixmapPtr pPixmap) 219{ 220} 221 222Bool 223viaExaPrepareCopy_H2(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, 224 int ydir, int alu, Pixel planeMask) 225{ 226 ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen); 227 VIAPtr pVia = VIAPTR(pScrn); 228 ViaTwodContext *tdc = &pVia->td; 229 230 RING_VARS; 231 232 if (pSrcPixmap->drawable.bitsPerPixel != pDstPixmap->drawable.bitsPerPixel) 233 return FALSE; 234 235 if ((tdc->srcPitch = exaGetPixmapPitch(pSrcPixmap)) & 3) 236 return FALSE; 237 238 if (exaGetPixmapPitch(pDstPixmap) & 7) 239 return FALSE; 240 241 tdc->srcOffset = exaGetPixmapOffset(pSrcPixmap); 242 243 tdc->cmd = VIA_GEC_BLT | VIAACCELCOPYROP(alu); 244 if (xdir < 0) 245 tdc->cmd |= VIA_GEC_DECX; 246 if (ydir < 0) 247 tdc->cmd |= VIA_GEC_DECY; 248 249 if (!viaAccelSetMode(pDstPixmap->drawable.bitsPerPixel, tdc)) 250 return FALSE; 251 252 if (!viaAccelPlaneMaskHelper_H2(tdc, planeMask)) 253 return FALSE; 254 viaAccelTransparentHelper_H2(pVia, 0x0, 0x0, TRUE); 255 256 return TRUE; 257} 258 259void 260viaExaCopy_H2(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, 261 int width, int height) 262{ 263 ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen); 264 CARD32 dstOffset = exaGetPixmapOffset(pDstPixmap), val; 265 CARD32 dstPitch = exaGetPixmapPitch(pDstPixmap); 266 VIAPtr pVia = VIAPTR(pScrn); 267 ViaTwodContext *tdc = &pVia->td; 268 269 if (!width || !height) 270 return; 271 272 if (tdc->cmd & VIA_GEC_DECY) { 273 srcY += height - 1; 274 dstY += height - 1; 275 } 276 277 if (tdc->cmd & VIA_GEC_DECX) { 278 srcX += width - 1; 279 dstX += width - 1; 280 } 281 val = VIA_PITCH_ENABLE | (dstPitch >> 3) << 16 | (tdc->srcPitch >> 3); 282 283 RING_VARS; 284 285 BEGIN_RING(16); 286 OUT_RING_H1(VIA_REG_GEMODE, tdc->mode); 287 OUT_RING_H1(VIA_REG_SRCBASE, tdc->srcOffset >> 3); 288 OUT_RING_H1(VIA_REG_DSTBASE, dstOffset >> 3); 289 OUT_RING_H1(VIA_REG_PITCH, val); 290 OUT_RING_H1(VIA_REG_SRCPOS, (srcY << 16) | (srcX & 0xFFFF)); 291 OUT_RING_H1(VIA_REG_DSTPOS, (dstY << 16) | (dstX & 0xFFFF)); 292 OUT_RING_H1(VIA_REG_DIMENSION, ((height - 1) << 16) | (width - 1)); 293 OUT_RING_H1(VIA_REG_GECMD, tdc->cmd); 294 295 ADVANCE_RING; 296} 297 298Bool 299viaExaCheckComposite_H2(int op, PicturePtr pSrcPicture, 300 PicturePtr pMaskPicture, PicturePtr pDstPicture) 301{ 302 ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPicture->pDrawable->pScreen); 303 VIAPtr pVia = VIAPTR(pScrn); 304 Via3DState *v3d = &pVia->v3d; 305 306 if (!pSrcPicture->pDrawable) 307 return FALSE; 308 309 /* Reject small composites early. They are done much faster in software. */ 310 if (!pSrcPicture->repeat && 311 pSrcPicture->pDrawable->width * 312 pSrcPicture->pDrawable->height < VIA_MIN_COMPOSITE) 313 return FALSE; 314 315 if (pMaskPicture && pMaskPicture->pDrawable && 316 !pMaskPicture->repeat && 317 pMaskPicture->pDrawable->width * 318 pMaskPicture->pDrawable->height < VIA_MIN_COMPOSITE) 319 return FALSE; 320 321 if (pMaskPicture && pMaskPicture->repeat && 322 pMaskPicture->repeatType != RepeatNormal) 323 return FALSE; 324 325 if (pMaskPicture && pMaskPicture->componentAlpha) { 326#ifdef VIA_DEBUG_COMPOSITE 327 viaExaPrintCompositeInfo("Component Alpha operation", op, pSrcPicture, pMaskPicture, pDstPicture); 328#endif 329 return FALSE; 330 } 331 332 if (!v3d->opSupported(op)) { 333#ifdef VIA_DEBUG_COMPOSITE 334 viaExaPrintCompositeInfo("Operator not supported", op, pSrcPicture, pMaskPicture, pDstPicture); 335#endif 336 return FALSE; 337 } 338 339 /* 340 * FIXME: A8 destination formats are currently not supported and do not 341 * seem supported by the hardware, although there are some leftover 342 * register settings apparent in the via_3d_reg.h file. We need to fix this 343 * (if important), by using component ARGB8888 operations with bitmask. 344 */ 345 346 if (!v3d->dstSupported(pDstPicture->format)) { 347#ifdef VIA_DEBUG_COMPOSITE 348 viaExaPrintCompositeInfo(" Destination format not supported", op, pSrcPicture, pMaskPicture, pDstPicture); 349#endif 350 return FALSE; 351 } 352 353 if (v3d->texSupported(pSrcPicture->format)) { 354 if (pMaskPicture && (PICT_FORMAT_A(pMaskPicture->format) == 0 || 355 !v3d->texSupported(pMaskPicture->format))) { 356#ifdef VIA_DEBUG_COMPOSITE 357 viaExaPrintCompositeInfo("Mask format not supported", op, pSrcPicture, pMaskPicture, pDstPicture); 358#endif 359 return FALSE; 360 } 361 return TRUE; 362 } 363#ifdef VIA_DEBUG_COMPOSITE 364 viaExaPrintCompositeInfo("Src format not supported", op, pSrcPicture, pMaskPicture, pDstPicture); 365#endif 366 return FALSE; 367} 368 369static Bool 370viaIsAGP(VIAPtr pVia, PixmapPtr pPix, unsigned long *offset) 371{ 372#ifdef HAVE_DRI 373 unsigned long offs; 374 375 if (pVia->directRenderingType && !pVia->IsPCI) { 376 offs = ((unsigned long)pPix->devPrivate.ptr 377 - (unsigned long)pVia->agpMappedAddr); 378 379 if ((offs - pVia->scratchOffset) < pVia->agpSize) { 380 *offset = offs + pVia->agpAddr; 381 return TRUE; 382 } 383 } 384#endif 385 return FALSE; 386} 387 388static Bool 389viaExaIsOffscreen(PixmapPtr pPix) 390{ 391 ScrnInfoPtr pScrn = xf86ScreenToScrn(pPix->drawable.pScreen); 392 VIAPtr pVia = VIAPTR(pScrn); 393 394 return ((unsigned long)pPix->devPrivate.ptr - 395 (unsigned long) drm_bo_map(pScrn, pVia->drmmode.front_bo)) < pVia->drmmode.front_bo->size; 396} 397 398Bool 399viaExaPrepareComposite_H2(int op, PicturePtr pSrcPicture, 400 PicturePtr pMaskPicture, PicturePtr pDstPicture, 401 PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) 402{ 403 CARD32 height, width; 404 ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen); 405 VIAPtr pVia = VIAPTR(pScrn); 406 Via3DState *v3d = &pVia->v3d; 407 int curTex = 0; 408 ViaTexBlendingModes srcMode; 409 Bool isAGP; 410 unsigned long offset; 411 412 /* Workaround: EXA crash with new libcairo2 on a VIA VX800 (#298) */ 413 /* TODO Add real source only pictures */ 414 if (!pSrc) { 415 ErrorF("pSrc is NULL\n"); 416 return FALSE; 417 } 418 419 v3d->setDestination(v3d, exaGetPixmapOffset(pDst), 420 exaGetPixmapPitch(pDst), pDstPicture->format); 421 v3d->setCompositeOperator(v3d, op); 422 v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, 0x000000FF, 0xFF); 423 424 viaOrder(pSrc->drawable.width, &width); 425 viaOrder(pSrc->drawable.height, &height); 426 427 /* 428 * For one-pixel repeat mask pictures we avoid using multitexturing by 429 * modifying the src's texture blending equation and feed the pixel 430 * value as a constant alpha for the src's texture. Multitexturing on the 431 * Unichromes seems somewhat slow, so this speeds up translucent windows. 432 */ 433 434 srcMode = via_src; 435 pVia->maskP = NULL; 436 if (pMaskPicture && 437 (pMaskPicture->pDrawable->height == 1) && 438 (pMaskPicture->pDrawable->width == 1) && 439 pMaskPicture->repeat && viaExpandablePixel(pMaskPicture->format)) { 440 pVia->maskP = pMask->devPrivate.ptr; 441 pVia->maskFormat = pMaskPicture->format; 442 pVia->componentAlpha = pMaskPicture->componentAlpha; 443 srcMode = ((pMaskPicture->componentAlpha) 444 ? via_src_onepix_comp_mask : via_src_onepix_mask); 445 } 446 447 /* 448 * One-Pixel repeat src pictures go as solid color instead of textures. 449 * Speeds up window shadows. 450 */ 451 452 pVia->srcP = NULL; 453 if (pSrcPicture && pSrcPicture->repeat 454 && (pSrcPicture->pDrawable->height == 1) 455 && (pSrcPicture->pDrawable->width == 1) 456 && viaExpandablePixel(pSrcPicture->format)) { 457 pVia->srcP = pSrc->devPrivate.ptr; 458 pVia->srcFormat = pSrcPicture->format; 459 } 460 461 /* Exa should be smart enough to eliminate this IN operation. */ 462 if (pVia->srcP && pVia->maskP) { 463 ErrorF("Bad one-pixel IN composite operation. " 464 "EXA needs to be smarter.\n"); 465 return FALSE; 466 } 467 468 if (!pVia->srcP) { 469 offset = exaGetPixmapOffset(pSrc); 470 isAGP = viaIsAGP(pVia, pSrc, &offset); 471 if (!isAGP && !viaExaIsOffscreen(pSrc)) 472 return FALSE; 473 if (!v3d->setTexture(v3d, curTex, offset, 474 exaGetPixmapPitch(pSrc), pVia->nPOT[curTex], 475 1 << width, 1 << height, pSrcPicture->format, 476 via_repeat, via_repeat, srcMode, isAGP)) { 477 return FALSE; 478 } 479 curTex++; 480 } 481 482 if (pMaskPicture && !pVia->maskP) { 483 offset = exaGetPixmapOffset(pMask); 484 isAGP = viaIsAGP(pVia, pMask, &offset); 485 if (!isAGP && !viaExaIsOffscreen(pMask)) 486 return FALSE; 487 viaOrder(pMask->drawable.width, &width); 488 viaOrder(pMask->drawable.height, &height); 489 if (!v3d->setTexture(v3d, curTex, offset, 490 exaGetPixmapPitch(pMask), pVia->nPOT[curTex], 491 1 << width, 1 << height, pMaskPicture->format, 492 via_repeat, via_repeat, 493 ((pMaskPicture->componentAlpha) 494 ? via_comp_mask : via_mask), isAGP)) { 495 return FALSE; 496 } 497 curTex++; 498 } 499 500 v3d->setFlags(v3d, curTex, FALSE, TRUE, TRUE); 501 v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d)); 502 v3d->emitClipRect(v3d, &pVia->cb, 0, 0, pDst->drawable.width, 503 pDst->drawable.height); 504 505 return TRUE; 506} 507 508void 509viaExaComposite_H2(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, 510 int dstX, int dstY, int width, int height) 511{ 512 ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen); 513 VIAPtr pVia = VIAPTR(pScrn); 514 Via3DState *v3d = &pVia->v3d; 515 CARD32 col; 516 517 if (pVia->maskP) { 518 viaPixelARGB8888(pVia->maskFormat, pVia->maskP, &col); 519 v3d->setTexBlendCol(v3d, 0, pVia->componentAlpha, col); 520 } 521 if (pVia->srcP) { 522 viaPixelARGB8888(pVia->srcFormat, pVia->srcP, &col); 523 v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, col & 0x00FFFFFF, col >> 24); 524 srcX = maskX; 525 srcY = maskY; 526 } 527 528 if (pVia->maskP || pVia->srcP) 529 v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d)); 530 531 v3d->emitQuad(v3d, &pVia->cb, dstX, dstY, srcX, srcY, maskX, maskY, 532 width, height); 533} 534 535void 536viaAccelTextureBlit(ScrnInfoPtr pScrn, unsigned long srcOffset, 537 unsigned srcPitch, unsigned w, unsigned h, unsigned srcX, 538 unsigned srcY, unsigned srcFormat, unsigned long dstOffset, 539 unsigned dstPitch, unsigned dstX, unsigned dstY, 540 unsigned dstFormat, int rotate) 541{ 542 VIAPtr pVia = VIAPTR(pScrn); 543 CARD32 wOrder, hOrder; 544 Via3DState *v3d = &pVia->v3d; 545 546 viaOrder(w, &wOrder); 547 viaOrder(h, &hOrder); 548 549 v3d->setDestination(v3d, dstOffset, dstPitch, dstFormat); 550 v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, 0x000000FF, 0x00); 551 v3d->setFlags(v3d, 1, TRUE, TRUE, FALSE); 552 v3d->setTexture(v3d, 0, srcOffset, srcPitch, TRUE, 553 1 << wOrder, 1 << hOrder, srcFormat, 554 via_single, via_single, via_src, FALSE); 555 v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d)); 556 v3d->emitClipRect(v3d, &pVia->cb, dstX, dstY, w, h); 557 v3d->emitQuad(v3d, &pVia->cb, dstX, dstY, srcX, srcY, 0, 0, w, h); 558} 559