1/* 2 * Copyright © 2001 Keith Packard 3 * Copyright 2011 VMWare, Inc. All Rights Reserved. 4 * May partly be based on code that is Copyright © The XFree86 Project Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 * Author: Eric Anholt <eric@anholt.net> 27 * Author: Michel Dänzer <michel@tungstengraphics.com> 28 * Author: Thomas Hellstrom <thellstrom@vmware.com> 29 */ 30#include "saa.h" 31#include "saa_priv.h" 32 33#ifdef RENDER 34#include <mipict.h> 35 36/** 37 * Same as miCreateAlphaPicture, except it uses 38 * saa_check_poly_fill_rect instead 39 */ 40 41static PicturePtr 42saa_create_alpha_picture(ScreenPtr pScreen, 43 PicturePtr pDst, 44 PictFormatPtr pPictFormat, CARD16 width, CARD16 height) 45{ 46 PixmapPtr pPixmap; 47 PicturePtr pPicture; 48 GCPtr pGC; 49 int error; 50 xRectangle rect; 51 52 if (width > 32767 || height > 32767) 53 return 0; 54 55 if (!pPictFormat) { 56 if (pDst->polyEdge == PolyEdgeSharp) 57 pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 58 else 59 pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 60 if (!pPictFormat) 61 return 0; 62 } 63 64 pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 65 pPictFormat->depth, 0); 66 if (!pPixmap) 67 return 0; 68 pGC = GetScratchGC(pPixmap->drawable.depth, pScreen); 69 if (!pGC) { 70 (*pScreen->DestroyPixmap) (pPixmap); 71 return 0; 72 } 73 ValidateGC(&pPixmap->drawable, pGC); 74 rect.x = 0; 75 rect.y = 0; 76 rect.width = width; 77 rect.height = height; 78 saa_check_poly_fill_rect(&pPixmap->drawable, pGC, 1, &rect); 79 FreeScratchGC(pGC); 80 pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, 81 0, 0, serverClient, &error); 82 (*pScreen->DestroyPixmap) (pPixmap); 83 return pPicture; 84} 85 86/** 87 * saa_trapezoids is essentially a copy of miTrapezoids that uses 88 * saa_create_alpha_picture instead of miCreateAlphaPicture. 89 * 90 * The problem with miCreateAlphaPicture is that it calls PolyFillRect 91 * to initialize the contents after creating the pixmap, which 92 * causes the pixmap to be moved in for acceleration. The subsequent 93 * call to RasterizeTrapezoid won't be accelerated however, which 94 * forces the pixmap to be moved out again. 95 * 96 */ 97static void 98saa_trapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 99 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 100 int ntrap, xTrapezoid * traps) 101{ 102 ScreenPtr pScreen = pDst->pDrawable->pScreen; 103 PictureScreenPtr ps = GetPictureScreen(pScreen); 104 BoxRec bounds; 105 106 if (maskFormat) { 107 PicturePtr pPicture; 108 INT16 xDst, yDst; 109 INT16 xRel, yRel; 110 saa_access_t access; 111 112 miTrapezoidBounds(ntrap, traps, &bounds); 113 114 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 115 return; 116 117 xDst = traps[0].left.p1.x >> 16; 118 yDst = traps[0].left.p1.y >> 16; 119 120 pPicture = saa_create_alpha_picture(pScreen, pDst, maskFormat, 121 bounds.x2 - bounds.x1, 122 bounds.y2 - bounds.y1); 123 if (!pPicture) 124 return; 125 126 if (saa_pad_write(pPicture->pDrawable, NULL, FALSE, &access)) { 127 for (; ntrap; ntrap--, traps++) 128 (*ps->RasterizeTrapezoid) (pPicture, traps, 129 -bounds.x1, -bounds.y1); 130 saa_fad_write(pPicture->pDrawable, access); 131 } 132 133 xRel = bounds.x1 + xSrc - xDst; 134 yRel = bounds.y1 + ySrc - yDst; 135 CompositePicture(op, pSrc, pPicture, pDst, 136 xRel, yRel, 0, 0, bounds.x1, bounds.y1, 137 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); 138 FreePicture(pPicture, 0); 139 } else { 140 if (pDst->polyEdge == PolyEdgeSharp) 141 maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 142 else 143 maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 144 for (; ntrap; ntrap--, traps++) 145 saa_trapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); 146 } 147} 148 149/** 150 * saa_triangles is essentially a copy of miTriangles that uses 151 * saa_create_alpha_picture instead of miCreateAlphaPicture. 152 * 153 * The problem with miCreateAlphaPicture is that it calls PolyFillRect 154 * to initialize the contents after creating the pixmap, which 155 * causes the pixmap to be moved in for acceleration. The subsequent 156 * call to AddTriangles won't be accelerated however, which forces the pixmap 157 * to be moved out again. 158 */ 159static void 160saa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 161 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 162 int ntri, xTriangle * tris) 163{ 164 ScreenPtr pScreen = pDst->pDrawable->pScreen; 165 PictureScreenPtr ps = GetPictureScreen(pScreen); 166 BoxRec bounds; 167 168 if (maskFormat) { 169 PicturePtr pPicture; 170 INT16 xDst, yDst; 171 INT16 xRel, yRel; 172 saa_access_t access; 173 174 miTriangleBounds(ntri, tris, &bounds); 175 176 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 177 return; 178 179 xDst = tris[0].p1.x >> 16; 180 yDst = tris[0].p1.y >> 16; 181 182 pPicture = saa_create_alpha_picture(pScreen, pDst, maskFormat, 183 bounds.x2 - bounds.x1, 184 bounds.y2 - bounds.y1); 185 if (!pPicture) 186 return; 187 188 if (saa_pad_write(pPicture->pDrawable, NULL, FALSE, &access)) { 189 (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); 190 saa_fad_write(pPicture->pDrawable, access); 191 } 192 193 xRel = bounds.x1 + xSrc - xDst; 194 yRel = bounds.y1 + ySrc - yDst; 195 CompositePicture(op, pSrc, pPicture, pDst, 196 xRel, yRel, 0, 0, bounds.x1, bounds.y1, 197 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); 198 FreePicture(pPicture, 0); 199 } else { 200 if (pDst->polyEdge == PolyEdgeSharp) 201 maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 202 else 203 maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 204 205 for (; ntri; ntri--, tris++) 206 saa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); 207 } 208} 209 210static Bool 211saa_driver_composite(CARD8 op, 212 PicturePtr pSrc, 213 PicturePtr pMask, 214 PicturePtr pDst, 215 INT16 xSrc, 216 INT16 ySrc, 217 INT16 xMask, 218 INT16 yMask, 219 INT16 xDst, 220 INT16 yDst, 221 CARD16 width, 222 CARD16 height, 223 RegionPtr src_reg, 224 RegionPtr mask_reg, 225 RegionPtr dst_reg) 226{ 227 struct saa_screen_priv *sscreen = saa_screen(pDst->pDrawable->pScreen); 228 BoxPtr pbox; 229 int nbox; 230 int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; 231 PixmapPtr src_pix = NULL, mask_pix = NULL, dst_pix; 232 struct saa_driver *driver = sscreen->driver; 233 234 if (!driver->composite_prepare) 235 return FALSE; 236 237 dst_pix = saa_get_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); 238 if (saa_pixmap(dst_pix)->auth_loc != saa_loc_driver) 239 return FALSE; 240 241 if (pMask && pMask->pDrawable) { 242 mask_pix = saa_get_pixmap(pMask->pDrawable, &mask_off_x, &mask_off_y); 243 if (saa_pixmap(mask_pix)->auth_loc != saa_loc_driver) 244 return FALSE; 245 } 246 if (pSrc->pDrawable) { 247 src_pix = saa_get_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y); 248 if (saa_pixmap(src_pix)->auth_loc != saa_loc_driver) 249 return FALSE; 250 } 251 252 if (!driver->composite_prepare(driver, op, pSrc, pMask, pDst, 253 src_pix, mask_pix, dst_pix, 254 src_reg, mask_reg, dst_reg)) 255 return FALSE; 256 257 nbox = REGION_NUM_RECTS(dst_reg); 258 pbox = REGION_RECTS(dst_reg); 259 260 xDst += pDst->pDrawable->x + dst_off_x; 261 yDst += pDst->pDrawable->y + dst_off_y; 262 263 if (src_pix) { 264 xSrc += pSrc->pDrawable->x + src_off_x - xDst; 265 ySrc += pSrc->pDrawable->y + src_off_y - yDst; 266 } 267 if (mask_pix) { 268 xMask += pMask->pDrawable->x + mask_off_x - xDst; 269 yMask += pMask->pDrawable->y + mask_off_y - yDst; 270 } 271 272 while (nbox--) { 273 driver->composite(driver, 274 pbox->x1 + xSrc, 275 pbox->y1 + ySrc, 276 pbox->x1 + xMask, 277 pbox->y1 + yMask, 278 pbox->x1, 279 pbox->y1, 280 pbox->x2 - pbox->x1, 281 pbox->y2 - pbox->y1); 282 pbox++; 283 } 284 285 driver->composite_done(driver); 286 saa_pixmap_dirty(dst_pix, TRUE, dst_reg); 287 288 return TRUE; 289} 290 291/* 292 * Try to turn a composite operation into an accelerated copy. 293 * We can do that in some special cases for PictOpSrc and PictOpOver. 294 */ 295 296static Bool 297saa_copy_composite(CARD8 op, 298 PicturePtr pSrc, 299 PicturePtr pMask, 300 PicturePtr pDst, 301 INT16 xSrc, 302 INT16 ySrc, 303 INT16 xMask, 304 INT16 yMask, 305 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height, 306 RegionPtr dst_region) 307{ 308 if (!pSrc->pDrawable || pSrc->transform || 309 pSrc->repeat || xSrc < 0 || ySrc < 0 || 310 xSrc + width > pSrc->pDrawable->width || 311 ySrc + height > pSrc->pDrawable->height) 312 return FALSE; 313 314 if (op == PictOpSrc || 315 (op == PictOpOver && PICT_FORMAT_A(pSrc->format) == 0 && 316 pMask == NULL)) { 317 318 int xoff, yoff; 319 PixmapPtr dst_pix = saa_get_pixmap(pDst->pDrawable, &xoff, &yoff); 320 struct saa_pixmap *dst_spix = saa_pixmap(dst_pix); 321 struct saa_pixmap *src_spix = 322 saa_pixmap(saa_get_drawable_pixmap(pSrc->pDrawable)); 323 int ret; 324 325 if (src_spix->auth_loc != saa_loc_driver || 326 dst_spix->auth_loc != saa_loc_driver) 327 return FALSE; 328 329 src_spix->src_format = pSrc->format; 330 dst_spix->dst_format = pDst->format; 331 332 xDst += pDst->pDrawable->x; 333 yDst += pDst->pDrawable->y; 334 xSrc += pSrc->pDrawable->x; 335 ySrc += pSrc->pDrawable->y; 336 337 /* 338 * Dst region is in backing pixmap space. We need to 339 * translate it. 340 */ 341 REGION_TRANSLATE(pScreen, dst_region, -xoff, -yoff); 342 ret = saa_hw_copy_nton(pSrc->pDrawable, pDst->pDrawable, NULL, 343 REGION_RECTS(dst_region), 344 REGION_NUM_RECTS(dst_region), 345 xSrc - xDst, ySrc - yDst, FALSE, FALSE); 346 REGION_TRANSLATE(pScreen, dst_region, xoff, yoff); 347 348 src_spix->src_format = 0; 349 dst_spix->dst_format = 0; 350 351 if (ret) 352 return TRUE; 353 } 354 return FALSE; 355} 356 357static void 358saa_composite(CARD8 op, 359 PicturePtr pSrc, 360 PicturePtr pMask, 361 PicturePtr pDst, 362 INT16 xSrc, 363 INT16 ySrc, 364 INT16 xMask, 365 INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) 366{ 367 ScreenPtr pScreen = pDst->pDrawable->pScreen; 368 RegionRec dst_region; 369 RegionPtr src_region; 370 RegionPtr mask_region; 371 372 REGION_NULL(pScreen, &dst_region); 373 if (!saa_compute_composite_regions(pScreen, pSrc, pMask, pDst, 374 xSrc, ySrc, xMask, yMask, xDst, 375 yDst, width, height, 376 &dst_region, &src_region, &mask_region)) 377 goto out; 378 379 if (saa_copy_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 380 xDst, yDst, width, height, &dst_region)) 381 goto out; 382 383 if (saa_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 384 xDst, yDst, width, height, src_region, 385 mask_region, &dst_region)) 386 goto out; 387 388 saa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 389 xDst, yDst, width, height, 390 src_region, mask_region, &dst_region); 391 out: 392 if (src_region) 393 REGION_UNINIT(pScreen, src_region); 394 if (mask_region && mask_region != src_region) 395 REGION_UNINIT(pScreen, mask_region); 396 REGION_UNINIT(pScreen, &dst_region); 397} 398 399void 400saa_render_setup(ScreenPtr pScreen) 401{ 402 PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); 403 struct saa_screen_priv *sscreen = saa_screen(pScreen); 404 405 if (ps) { 406 saa_wrap(sscreen, ps, Trapezoids, saa_trapezoids); 407 saa_wrap(sscreen, ps, Triangles, saa_triangles); 408 saa_wrap(sscreen, ps, Composite, saa_composite); 409 saa_wrap(sscreen, ps, Glyphs, miGlyphs); 410 saa_wrap(sscreen, ps, UnrealizeGlyph, miUnrealizeGlyph); 411 } 412} 413 414void 415saa_render_takedown(ScreenPtr pScreen) 416{ 417 PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); 418 struct saa_screen_priv *sscreen = saa_screen(pScreen); 419 420 if (ps) { 421 saa_unwrap(sscreen, ps, Trapezoids); 422 saa_unwrap(sscreen, ps, Triangles); 423 saa_unwrap(sscreen, ps, Composite); 424 saa_unwrap(sscreen, ps, Glyphs); 425 saa_unwrap(sscreen, ps, UnrealizeGlyph); 426 } 427} 428#endif 429