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