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