r128_exa_render.c revision cd241713
1/* 2 * Copyright 2003 Eric Anholt 3 * Copyright 2003 Anders Carlsson 4 * Copyright 2012 Connor Behan 5 * Copyright 2012 Michel Dänzer 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the next 16 * paragraph) shall be included in all copies or substantial portions of the 17 * Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 * SOFTWARE. 26 * 27 * Authors: 28 * Anders Carlsson <andersca@gnome.org> 29 * Eric Anholt <anholt@FreeBSD.org> 30 * Connor Behan <connor.behan@gmail.com> 31 * Michel Dänzer <michel.daenzer@amd.com> 32 * 33 */ 34 35/* The following is based on the kdrive ATI driver. */ 36 37#ifdef HAVE_CONFIG_H 38#include "config.h" 39#endif 40 41#if defined(R128DRI) && defined(RENDER) 42#include "xf86.h" 43#include "exa.h" 44 45#include "r128.h" 46#include "r128_reg.h" 47#include "r128_rop.h" 48 49 50static struct { 51 Bool dst_alpha; 52 Bool src_alpha; 53 uint32_t sblend; 54 uint32_t dblend; 55} R128BlendOp[] = { 56 /* Clear */ 57 {0, 0, R128_ALPHA_BLEND_ZERO , R128_ALPHA_BLEND_ZERO}, 58 /* Src */ 59 {0, 0, R128_ALPHA_BLEND_ONE , R128_ALPHA_BLEND_ZERO}, 60 /* Dst */ 61 {0, 0, R128_ALPHA_BLEND_ZERO , R128_ALPHA_BLEND_ONE}, 62 /* Over */ 63 {0, 1, R128_ALPHA_BLEND_ONE , R128_ALPHA_BLEND_INVSRCALPHA}, 64 /* OverReverse */ 65 {1, 0, R128_ALPHA_BLEND_INVDSTALPHA , R128_ALPHA_BLEND_ONE}, 66 /* In */ 67 {1, 0, R128_ALPHA_BLEND_DSTALPHA , R128_ALPHA_BLEND_ZERO}, 68 /* InReverse */ 69 {0, 1, R128_ALPHA_BLEND_ZERO , R128_ALPHA_BLEND_SRCALPHA}, 70 /* Out */ 71 {1, 0, R128_ALPHA_BLEND_INVDSTALPHA , R128_ALPHA_BLEND_ZERO}, 72 /* OutReverse */ 73 {0, 1, R128_ALPHA_BLEND_ZERO , R128_ALPHA_BLEND_INVSRCALPHA}, 74 /* Atop */ 75 {1, 1, R128_ALPHA_BLEND_DSTALPHA , R128_ALPHA_BLEND_INVSRCALPHA}, 76 /* AtopReverse */ 77 {1, 1, R128_ALPHA_BLEND_INVDSTALPHA , R128_ALPHA_BLEND_SRCALPHA}, 78 /* Xor */ 79 {1, 1, R128_ALPHA_BLEND_INVDSTALPHA , R128_ALPHA_BLEND_INVSRCALPHA}, 80 /* Add */ 81 {0, 0, R128_ALPHA_BLEND_ONE , R128_ALPHA_BLEND_ONE}, 82}; 83 84static Bool 85R128TransformAffineOrScaled(PictTransformPtr t) 86{ 87 if (t == NULL) return TRUE; 88 89 /* the shaders don't handle scaling either */ 90 return t->matrix[2][0] == 0 && t->matrix[2][1] == 0 && t->matrix[2][2] == IntToxFixed(1); 91} 92 93static PixmapPtr 94R128GetDrawablePixmap(DrawablePtr pDrawable) 95{ 96 if (pDrawable->type == DRAWABLE_WINDOW) 97 return pDrawable->pScreen->GetWindowPixmap((WindowPtr)pDrawable); 98 else 99 return (PixmapPtr)pDrawable; 100} 101 102static PixmapPtr 103R128SolidPixmap(ScreenPtr pScreen, uint32_t solid) 104{ 105 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 106 R128InfoPtr info = R128PTR(pScrn); 107 PixmapPtr pPix = pScreen->CreatePixmap(pScreen, 1, 1, 32, 0); 108 109 exaMoveInPixmap(pPix); 110 if (!exaDrawableIsOffscreen(&pPix->drawable)) { 111 pScreen->DestroyPixmap(pPix); 112 return NULL; 113 } 114 info->ExaDriver->WaitMarker(pScreen, 0); 115 116#if X_BYTE_ORDER == X_BIG_ENDIAN 117 if (pScrn->bitsPerPixel == 32) 118 R128CopySwap(info->ExaDriver->memoryBase + exaGetPixmapOffset(pPix), (uint8_t*)&solid, 4, 119 APER_0_BIG_ENDIAN_32BPP_SWAP); 120 else if (pScrn->bitsPerPixel == 16) 121 R128CopySwap(info->ExaDriver->memoryBase + exaGetPixmapOffset(pPix), (uint8_t*)&solid, 4, 122 APER_0_BIG_ENDIAN_16BPP_SWAP); 123 else 124 /* Fall through for 8 bpp */ 125#endif 126 memcpy(info->ExaDriver->memoryBase + exaGetPixmapOffset(pPix), &solid, 4); 127 128 return pPix; 129} 130 131static Bool 132R128GetDatatypePict1(uint32_t format, uint32_t *type) 133{ 134 switch(format) { 135 case PICT_r5g6b5: 136 *type = R128_DATATYPE_RGB565; 137 return TRUE; 138 case PICT_x1r5g5b5: 139 *type = R128_DATATYPE_ARGB1555; 140 return TRUE; 141 case PICT_x8r8g8b8: 142 *type = R128_DATATYPE_ARGB8888; 143 return TRUE; 144 default: 145 return FALSE; 146 } 147} 148 149static Bool 150R128GetDatatypePict2(uint32_t format, uint32_t *type) 151{ 152 switch(format) { 153 case PICT_a8: 154 *type = R128_DATATYPE_RGB8; 155 return TRUE; 156 case PICT_r5g6b5: 157 *type = R128_DATATYPE_RGB565; 158 return TRUE; 159 case PICT_a8r8g8b8: 160 *type = R128_DATATYPE_ARGB8888; 161 return TRUE; 162 default: 163 return FALSE; 164 } 165} 166 167static Bool 168R128CheckCompositeTexture(PicturePtr pPict, PicturePtr pDstPict, int op) 169{ 170#if R128_DEBUG 171 ScreenPtr pScreen = pDstPict->pDrawable->pScreen; 172 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 173#endif 174 175 unsigned int repeatType = pPict->repeat ? pPict->repeatType : RepeatNone; 176 uint32_t tmp1; 177 178 if (!R128GetDatatypePict2(pPict->format, &tmp1)) return FALSE; 179 180 if (pPict->pDrawable) { 181 int w = pPict->pDrawable->width; 182 int h = pPict->pDrawable->height; 183 184 if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0)) { 185 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 186 "NPOT repeat unsupported (%dx%d)\n", w, h)); 187 return FALSE; 188 } 189 } 190 191 if (pPict->filter != PictFilterNearest && pPict->filter != PictFilterBilinear) { 192 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 193 "Unsupported filter 0x%x\n", 194 pPict->filter)); 195 return FALSE; 196 } 197 198 /* The radeon driver has a long explanation about this part that I don't really understand */ 199 if (pPict->transform != 0 && repeatType == RepeatNone && PICT_FORMAT_A(pPict->format) == 0) { 200 if (!(((op == PictOpSrc) || (op == PictOpClear)) && (PICT_FORMAT_A(pDstPict->format) == 0))) { 201 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 202 "REPEAT_NONE unsupported for " 203 "transformed xRGB source\n")); 204 return FALSE; 205 } 206 } 207 if (!R128TransformAffineOrScaled(pPict->transform)) { 208 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 209 "Non-affine transforms not supported\n")); 210 return FALSE; 211 } 212 213 return TRUE; 214} 215 216Bool 217R128CCECheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture) 218{ 219#if R128_DEBUG 220 ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; 221 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 222#endif 223 224 PixmapPtr pSrcPixmap, pDstPixmap; 225 uint32_t tmp1; 226 227 /* Check for unsupported compositing operations. */ 228 if (op >= sizeof(R128BlendOp) / sizeof(R128BlendOp[0])) { 229 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 230 "Unsupported Composite op 0x%x\n", op)); 231 return FALSE; 232 } 233 234 pDstPixmap = R128GetDrawablePixmap(pDstPicture->pDrawable); 235 if (pDstPixmap->drawable.width > 1024 || pDstPixmap->drawable.height > 1024) { 236 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 237 "Dest w/h too large (%d,%d).\n", 238 pDstPixmap->drawable.width, 239 pDstPixmap->drawable.height)); 240 return FALSE; 241 } 242 243 if (pSrcPicture->pDrawable) { 244 pSrcPixmap = R128GetDrawablePixmap(pSrcPicture->pDrawable); 245 if (pSrcPixmap->drawable.width > 1024 || pSrcPixmap->drawable.height > 1024) { 246 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 247 "Source w/h too large (%d,%d).\n", 248 pSrcPixmap->drawable.width, 249 pSrcPixmap->drawable.height)); 250 return FALSE; 251 } 252 } else if (pSrcPicture->pSourcePict->type != SourcePictTypeSolidFill) { 253 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 254 "Gradient pictures not supported yet\n")); 255 return FALSE; 256 } 257 258 if (pDstPicture->format == PICT_a8) { 259 if (R128BlendOp[op].src_alpha || R128BlendOp[op].dst_alpha || pMaskPicture != NULL) { 260 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 261 "Alpha blending unsupported with " 262 "A8 dst?\n")); 263 return FALSE; 264 } 265 } else { 266 if (!R128GetDatatypePict1(pDstPicture->format, &tmp1)) return FALSE; 267 } 268 269 if (pMaskPicture) { 270 PixmapPtr pMaskPixmap; 271 272 if (pMaskPicture->pDrawable) { 273 pMaskPixmap = R128GetDrawablePixmap(pMaskPicture->pDrawable); 274 if (pMaskPixmap->drawable.width > 1024 || pMaskPixmap->drawable.height > 1024) { 275 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 276 "Mask w/h too large (%d,%d).\n", 277 pMaskPixmap->drawable.width, 278 pMaskPixmap->drawable.height)); 279 return FALSE; 280 } 281 } else if (pMaskPicture->pSourcePict->type != SourcePictTypeSolidFill) { 282 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 283 "Gradient pictures not supported yet\n")); 284 return FALSE; 285 } 286 287 if (pMaskPicture->componentAlpha && R128BlendOp[op].src_alpha) { 288 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 289 "Component alpha not supported with " 290 "source alpha blending\n")); 291 return FALSE; 292 } 293 294 if (!R128CheckCompositeTexture(pMaskPicture, pDstPicture, op)) return FALSE; 295 } 296 297 if (!R128CheckCompositeTexture(pSrcPicture, pDstPicture, op)) return FALSE; 298 return TRUE; 299} 300 301static Bool 302R128TextureSetup(PicturePtr pPict, PixmapPtr pPix, int unit, uint32_t *txsize, uint32_t *tex_cntl_c, Bool trying_solid) 303{ 304 ScreenPtr pScreen = pPix->drawable.pScreen; 305 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 306 R128InfoPtr info = R128PTR(pScrn); 307 308 int w, h, bytepp, shift, l2w, l2h, l2p, pitch; 309 310 if (pPict->pDrawable) { 311 w = pPict->pDrawable->width; 312 h = pPict->pDrawable->height; 313 } else { 314 w = h = 1; 315 } 316 317 pitch = exaGetPixmapPitch(pPix); 318 if ((pitch & (pitch - 1)) != 0) { 319 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 320 "NPOT pitch 0x%x unsupported\n", pitch)); 321 return FALSE; 322 } 323 324 if (!R128GetDatatypePict2(pPict->format, tex_cntl_c)) return FALSE; 325 326 bytepp = PICT_FORMAT_BPP(pPict->format) / 8; 327 *tex_cntl_c |= R128_MIP_MAP_DISABLE; 328 329 if (pPict->filter == PictFilterBilinear) { 330 *tex_cntl_c |= R128_MIN_BLEND_LINEAR | R128_MAG_BLEND_LINEAR; 331 } else if (pPict->filter == PictFilterNearest) { 332 *tex_cntl_c |= R128_MIN_BLEND_NEAREST | R128_MAG_BLEND_NEAREST; 333 } else { 334 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 335 "Bad filter 0x%x\n", pPict->filter)); 336 return FALSE; 337 } 338 339 if (unit == 0) { 340 shift = 0; 341 } else { 342 shift = 16; 343 *tex_cntl_c |= R128_SEC_SELECT_SEC_ST; 344 } 345 346 l2w = R128MinBits(w) - 1; 347 l2h = R128MinBits(h) - 1; 348 l2p = R128MinBits(pitch / bytepp) - 1; 349 350 if (pPict->repeat && w == 1 && h == 1) { 351 l2p = 0; 352 } else if (pPict->repeat && l2p != l2w) { 353 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 354 "Repeat not supported for pitch != " 355 "width\n")); 356 return FALSE; 357 } 358 359 l2w = l2p; 360 /* This is required to handle NPOT height */ 361 if ((unit == 1) || (unit == 0 && !pPict->repeat && !trying_solid)) l2h++; 362 363 info->state_2d.widths[unit] = 1 << l2w; 364 info->state_2d.heights[unit] = 1 << l2h; 365 *txsize |= l2p << (R128_TEX_PITCH_SHIFT + shift); 366 *txsize |= ((w > h) ? l2w : l2h) << (R128_TEX_SIZE_SHIFT + shift); 367 *txsize |= l2h << (R128_TEX_HEIGHT_SHIFT + shift); 368 369 if (pPict->transform != 0) { 370 info->state_2d.is_transform[unit] = TRUE; 371 info->state_2d.transform[unit] = pPict->transform; 372 } else { 373 info->state_2d.is_transform[unit] = FALSE; 374 } 375 376 return TRUE; 377} 378 379/* The composite preparation commands that are the same every time can 380 * just be written once. 381 */ 382#define COMPOSITE_SETUP() \ 383do { \ 384 BEGIN_RING( 10 ); \ 385 \ 386 OUT_RING_REG(R128_SCALE_3D_CNTL, \ 387 R128_SCALE_3D_TEXMAP_SHADE | \ 388 R128_SCALE_PIX_REPLICATE | \ 389 R128_TEX_CACHE_SPLIT | \ 390 R128_TEX_MAP_ALPHA_IN_TEXTURE | \ 391 R128_TEX_CACHE_LINE_SIZE_4QW); \ 392 OUT_RING_REG(R128_SETUP_CNTL, \ 393 R128_COLOR_GOURAUD | \ 394 R128_PRIM_TYPE_TRI | \ 395 R128_TEXTURE_ST_MULT_W | \ 396 R128_STARTING_VERTEX_1 | \ 397 R128_ENDING_VERTEX_3 | \ 398 R128_SUB_PIX_4BITS); \ 399 OUT_RING_REG(R128_PM4_VC_FPU_SETUP, \ 400 R128_FRONT_DIR_CCW | \ 401 R128_BACKFACE_SOLID | \ 402 R128_FRONTFACE_SOLID | \ 403 R128_FPU_COLOR_GOURAUD | \ 404 R128_FPU_SUB_PIX_4BITS | \ 405 R128_FPU_MODE_3D | \ 406 R128_TRAP_BITS_DISABLE | \ 407 R128_XFACTOR_2 | \ 408 R128_YFACTOR_2 | \ 409 R128_FLAT_SHADE_VERTEX_OGL | \ 410 R128_FPU_ROUND_TRUNCATE | \ 411 R128_WM_SEL_8DW); \ 412 OUT_RING_REG(R128_PLANE_3D_MASK_C, 0xffffffff); \ 413 OUT_RING_REG(R128_CONSTANT_COLOR_C, 0xff000000); \ 414 \ 415 ADVANCE_RING(); \ 416} while(0) 417 418Bool 419R128CCEPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, 420 PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) 421{ 422 ScreenPtr pScreen = pDst->drawable.pScreen; 423 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 424 R128InfoPtr info = R128PTR(pScrn); 425 unsigned char *R128MMIO = info->MMIO; 426 RING_LOCALS; 427 428 Bool add_src = FALSE; 429 Bool add_msk = FALSE; 430 uint32_t txsize = 0, prim_tex_cntl_c, sec_tex_cntl_c = 0, dstDatatype; 431 uint32_t src_pitch_offset, dst_pitch_offset, color_factor, in_color_factor, alpha_comb; 432 uint32_t sblend, dblend, blend_cntl, window_offset; 433 int i; 434 435 if (pDstPicture->format == PICT_a8) { 436 if (R128BlendOp[op].dst_alpha) { 437 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 438 "Can't dst alpha blend A8\n")); 439 return FALSE; 440 } 441 dstDatatype = R128_DATATYPE_Y8; 442 } else { 443 if (!R128GetDatatypePict1(pDstPicture->format, &dstDatatype)) return FALSE; 444 } 445 446 if (!pSrc) { 447 pSrc = R128SolidPixmap(pScreen, cpu_to_le32(pSrcPicture->pSourcePict->solidFill.color)); 448 if (!pSrc) { 449 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 450 "Failed to create solid scratch " 451 "pixmap\n")); 452 return FALSE; 453 } 454 add_src = TRUE; 455 } 456 if (pMaskPicture) { 457 info->state_2d.has_mask = TRUE; 458 if (!pMask) { 459 pMask = R128SolidPixmap(pScreen, cpu_to_le32(pMaskPicture->pSourcePict->solidFill.color)); 460 if (!pMask) { 461 if (!pSrcPicture->pDrawable) 462 pScreen->DestroyPixmap(pSrc); 463 info->state_2d.has_mask = FALSE; 464 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 465 "Failed to create " 466 "solid scratch pixmap\n")); 467 return FALSE; 468 } 469 add_msk = TRUE; 470 } 471 } else { 472 info->state_2d.has_mask = FALSE; 473 } 474 475 if (!R128TextureSetup(pSrcPicture, pSrc, 0, &txsize, &prim_tex_cntl_c, (add_src || add_msk))) return FALSE; 476 477 if (pMask != NULL) { 478 info->state_2d.has_mask = TRUE; 479 if (!R128TextureSetup(pMaskPicture, pMask, 1, &txsize, &sec_tex_cntl_c, (add_src || add_msk))) return FALSE; 480 } else { 481 info->state_2d.has_mask = FALSE; 482 info->state_2d.is_transform[1] = FALSE; 483 } 484 485 if (!R128GetPixmapOffsetPitch(pDst, &dst_pitch_offset)) return FALSE; 486 if (!R128GetPixmapOffsetPitch(pSrc, &src_pitch_offset)) return FALSE; 487 488 info->state_2d.in_use = TRUE; 489 if (add_src) info->state_2d.src_pix = pSrc; 490 if (add_msk) info->state_2d.msk_pix = pMask; 491 sblend = R128BlendOp[op].sblend; 492 dblend = R128BlendOp[op].dblend; 493 if (PICT_FORMAT_A(pDstPicture->format) == 0 && R128BlendOp[op].dst_alpha) { 494 if (sblend == R128_ALPHA_BLEND_DSTALPHA) 495 sblend = R128_ALPHA_BLEND_ONE; 496 else if (sblend == R128_ALPHA_BLEND_INVDSTALPHA) 497 sblend = R128_ALPHA_BLEND_ZERO; 498 } 499 blend_cntl = (sblend << R128_ALPHA_BLEND_SRC_SHIFT) | 500 (dblend << R128_ALPHA_BLEND_DST_SHIFT); 501 502 R128CCE_REFRESH( pScrn, info ); 503 504 if (!info->state_2d.composite_setup) { 505 COMPOSITE_SETUP(); 506 info->state_2d.composite_setup = TRUE; 507 } 508 509 /* We cannot guarantee that this register will stay zero - DRI needs it too. */ 510 if (info->have3DWindows) 511 info->ExaDriver->WaitMarker(pScreen, 0); 512 window_offset = INREG(R128_WINDOW_XY_OFFSET); 513 info->state_2d.x_offset = (window_offset & 0xfff00000) >> R128_WINDOW_X_SHIFT; 514 info->state_2d.y_offset = (window_offset & 0x000fffff) >> R128_WINDOW_Y_SHIFT; 515 516 info->state_2d.dp_gui_master_cntl = (R128_GMC_DST_PITCH_OFFSET_CNTL | 517 R128_GMC_BRUSH_SOLID_COLOR | 518 (dstDatatype >> 8) | 519 R128_GMC_SRC_DATATYPE_COLOR | 520 R128_ROP[3].rop | 521 R128_DP_SRC_SOURCE_MEMORY | 522 R128_GMC_3D_FCN_EN | 523 R128_GMC_CLR_CMP_CNTL_DIS | 524 R128_GMC_AUX_CLIP_DIS | 525 R128_GMC_WR_MSK_DIS); 526 info->state_2d.dp_cntl = (R128_DST_X_LEFT_TO_RIGHT | R128_DST_Y_TOP_TO_BOTTOM); 527 info->state_2d.dp_brush_frgd_clr = 0xffffffff; 528 info->state_2d.dp_brush_bkgd_clr = 0x00000000; 529 info->state_2d.dp_src_frgd_clr = 0xffffffff; 530 info->state_2d.dp_src_bkgd_clr = 0x00000000; 531 info->state_2d.dp_write_mask = 0xffffffff; 532 info->state_2d.dst_pitch_offset = dst_pitch_offset; 533 info->state_2d.src_pitch_offset = src_pitch_offset; 534 info->state_2d.default_sc_bottom_right = (R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX); 535 EmitCCE2DState(pScrn); 536 537 BEGIN_RING( 6 ); 538 OUT_RING_REG(R128_MISC_3D_STATE_CNTL_REG, 539 R128_MISC_SCALE_3D_TEXMAP_SHADE | 540 R128_MISC_SCALE_PIX_REPLICATE | 541 R128_ALPHA_COMB_ADD_CLAMP | 542 blend_cntl); 543 OUT_RING_REG(R128_TEX_CNTL_C, 544 R128_TEXMAP_ENABLE | 545 ((pMask != NULL) ? R128_SEC_TEXMAP_ENABLE : 0) | 546 R128_ALPHA_ENABLE | 547 R128_TEX_CACHE_FLUSH); 548 OUT_RING_REG(R128_PC_GUI_CTLSTAT, R128_PC_FLUSH_GUI); 549 ADVANCE_RING(); 550 551 /* IN operator: Without a mask, only the first texture unit is enabled. 552 * With a mask, we put the source in the first unit and have it pass 553 * through as input to the 2nd. The 2nd unit takes the incoming source 554 * pixel and modulates it with either the alpha or each of the channels 555 * in the mask, depending on componentAlpha. 556 */ 557 BEGIN_RING( 15 ); 558 /* R128_PRIM_TEX_CNTL_C, 559 * R128_PRIM_TEXTURE_COMBINE_CNTL_C, 560 * R128_TEX_SIZE_PITCH_C, 561 * R128_PRIM_TEX_0_OFFSET_C - R128_PRIM_TEX_10_OFFSET_C 562 */ 563 OUT_RING(CCE_PACKET0(R128_PRIM_TEX_CNTL_C, 13)); 564 OUT_RING(prim_tex_cntl_c); 565 566 /* If this is the only stage and the dest is a8, route the alpha result 567 * to the color (red channel, in particular), too. Otherwise, be sure 568 * to zero out color channels of an a8 source. 569 */ 570 if (pMaskPicture == NULL && pDstPicture->format == PICT_a8) 571 color_factor = R128_COLOR_FACTOR_ALPHA; 572 else if (pSrcPicture->format == PICT_a8) 573 color_factor = R128_COLOR_FACTOR_CONST_COLOR; 574 else 575 color_factor = R128_COLOR_FACTOR_TEX; 576 577 if (PICT_FORMAT_A(pSrcPicture->format) == 0) 578 alpha_comb = R128_COMB_ALPHA_COPY_INP; 579 else 580 alpha_comb = R128_COMB_ALPHA_DIS; 581 582 OUT_RING(R128_COMB_COPY | 583 color_factor | 584 R128_INPUT_FACTOR_INT_COLOR | 585 alpha_comb | 586 R128_ALPHA_FACTOR_TEX_ALPHA | 587 R128_INP_FACTOR_A_CONST_ALPHA); 588 OUT_RING(txsize); 589 /* We could save some output by only writing the offset register that 590 * will actually be used. On the other hand, this is easy. 591 */ 592 for (i = 0; i <= 10; i++) 593 OUT_RING(exaGetPixmapOffset(pSrc)); 594 ADVANCE_RING(); 595 596 if (pMask != NULL) { 597 BEGIN_RING( 14 ); 598 /* R128_SEC_TEX_CNTL_C, 599 * R128_SEC_TEXTURE_COMBINE_CNTL_C, 600 * R128_SEC_TEX_0_OFFSET_C - R128_SEC_TEX_10_OFFSET_C 601 */ 602 OUT_RING(CCE_PACKET0(R128_SEC_TEX_CNTL_C, 12)); 603 OUT_RING(sec_tex_cntl_c); 604 605 if (pDstPicture->format == PICT_a8) { 606 color_factor = R128_COLOR_FACTOR_ALPHA; 607 in_color_factor = R128_INPUT_FACTOR_PREV_ALPHA; 608 } else if (pMaskPicture->componentAlpha) { 609 color_factor = R128_COLOR_FACTOR_TEX; 610 in_color_factor = R128_INPUT_FACTOR_PREV_COLOR; 611 } else { 612 color_factor = R128_COLOR_FACTOR_ALPHA; 613 in_color_factor = R128_INPUT_FACTOR_PREV_COLOR; 614 } 615 616 OUT_RING(R128_COMB_MODULATE | 617 color_factor | 618 in_color_factor | 619 R128_COMB_ALPHA_MODULATE | 620 R128_ALPHA_FACTOR_TEX_ALPHA | 621 R128_INP_FACTOR_A_PREV_ALPHA); 622 for (i = 0; i <= 10; i++) 623 OUT_RING(exaGetPixmapOffset(pMask)); 624 ADVANCE_RING(); 625 } 626 627 return TRUE; 628} 629 630typedef union { float f; uint32_t i; } fi_type; 631 632static inline uint32_t 633R128FloatAsInt(float val) 634{ 635 fi_type fi; 636 637 fi.f = val; 638 return fi.i; 639} 640 641#define VTX_OUT_MASK(_dstX, _dstY, _srcX, _srcY, _maskX, _maskY) \ 642do { \ 643 OUT_RING(R128FloatAsInt((_dstX))); \ 644 OUT_RING(R128FloatAsInt(((float)(_dstY)) + 0.125)); \ 645 OUT_RING(R128FloatAsInt(0.0)); \ 646 OUT_RING(R128FloatAsInt(1.0)); \ 647 OUT_RING(R128FloatAsInt((((float)(_srcX)) + 0.5) / (info->state_2d.widths[0]))); \ 648 OUT_RING(R128FloatAsInt((((float)(_srcY)) + 0.5) / (info->state_2d.heights[0]))); \ 649 OUT_RING(R128FloatAsInt((((float)(_maskX)) + 0.5) / (info->state_2d.widths[1]))); \ 650 OUT_RING(R128FloatAsInt((((float)(_maskY)) + 0.5) / (info->state_2d.heights[1]))); \ 651} while (0) 652 653#define VTX_OUT(_dstX, _dstY, _srcX, _srcY) \ 654do { \ 655 OUT_RING(R128FloatAsInt((_dstX))); \ 656 OUT_RING(R128FloatAsInt(((float)(_dstY)) + 0.125)); \ 657 OUT_RING(R128FloatAsInt(0.0)); \ 658 OUT_RING(R128FloatAsInt(1.0)); \ 659 OUT_RING(R128FloatAsInt((((float)(_srcX)) + 0.5) / (info->state_2d.widths[0]))); \ 660 OUT_RING(R128FloatAsInt((((float)(_srcY)) + 0.5) / (info->state_2d.heights[0]))); \ 661} while (0) 662 663void 664R128CCEComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, int dstX, int dstY, int w, int h) 665{ 666 ScreenPtr pScreen = pDst->drawable.pScreen; 667 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 668 R128InfoPtr info = R128PTR(pScrn); 669 RING_LOCALS; 670 671 int srcXend, srcYend, maskXend, maskYend; 672 PictVector v; 673 674 srcXend = srcX + w; 675 srcYend = srcY + h; 676 maskXend = maskX + w; 677 maskYend = maskY + h; 678 if (info->state_2d.is_transform[0]) { 679 v.vector[0] = IntToxFixed(srcX); 680 v.vector[1] = IntToxFixed(srcY); 681 v.vector[2] = xFixed1; 682 PictureTransformPoint(info->state_2d.transform[0], &v); 683 srcX = xFixedToInt(v.vector[0]); 684 srcY = xFixedToInt(v.vector[1]); 685 v.vector[0] = IntToxFixed(srcXend); 686 v.vector[1] = IntToxFixed(srcYend); 687 v.vector[2] = xFixed1; 688 PictureTransformPoint(info->state_2d.transform[0], &v); 689 srcXend = xFixedToInt(v.vector[0]); 690 srcYend = xFixedToInt(v.vector[1]); 691 } 692 if (info->state_2d.is_transform[1]) { 693 v.vector[0] = IntToxFixed(maskX); 694 v.vector[1] = IntToxFixed(maskY); 695 v.vector[2] = xFixed1; 696 PictureTransformPoint(info->state_2d.transform[1], &v); 697 maskX = xFixedToInt(v.vector[0]); 698 maskY = xFixedToInt(v.vector[1]); 699 v.vector[0] = IntToxFixed(maskXend); 700 v.vector[1] = IntToxFixed(maskYend); 701 v.vector[2] = xFixed1; 702 PictureTransformPoint(info->state_2d.transform[1], &v); 703 maskXend = xFixedToInt(v.vector[0]); 704 maskYend = xFixedToInt(v.vector[1]); 705 } 706 707 dstX -= info->state_2d.x_offset; 708 dstY -= info->state_2d.y_offset; 709 710 R128CCE_REFRESH( pScrn, info ); 711 712 if (info->state_2d.has_mask) { 713 BEGIN_RING( 3 + 4 * 8 ); 714 OUT_RING(CCE_PACKET3(R128_CCE_PACKET3_3D_RNDR_GEN_PRIM, 1 + 4 * 8)); 715 716 OUT_RING(R128_CCE_VC_FRMT_RHW | 717 R128_CCE_VC_FRMT_S_T | 718 R128_CCE_VC_FRMT_S2_T2); 719 } else { 720 BEGIN_RING( 3 + 4 * 6 ); 721 OUT_RING(CCE_PACKET3(R128_CCE_PACKET3_3D_RNDR_GEN_PRIM, 1 + 4 * 6)); 722 723 OUT_RING(R128_CCE_VC_FRMT_RHW | 724 R128_CCE_VC_FRMT_S_T); 725 } 726 727 OUT_RING(R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN | 728 R128_CCE_VC_CNTL_PRIM_WALK_RING | 729 (4 << R128_CCE_VC_CNTL_NUM_SHIFT)); 730 731 if (info->state_2d.has_mask) { 732 VTX_OUT_MASK(dstX, dstY, srcX, srcY, maskX, maskY); 733 VTX_OUT_MASK(dstX, dstY + h, srcX, srcYend, maskX, maskYend); 734 VTX_OUT_MASK(dstX + w, dstY + h, srcXend, srcYend, maskXend, maskYend); 735 VTX_OUT_MASK(dstX + w, dstY, srcXend, srcY, maskXend, maskY); 736 } else { 737 VTX_OUT(dstX, dstY, srcX, srcY); 738 VTX_OUT(dstX, dstY + h, srcX, srcYend); 739 VTX_OUT(dstX + w, dstY + h, srcXend, srcYend); 740 VTX_OUT(dstX + w, dstY, srcXend, srcY); 741 } 742 743 ADVANCE_RING(); 744} 745 746#endif 747