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