diff options
Diffstat (limited to 'saa/saa_render.c')
-rw-r--r-- | saa/saa_render.c | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/saa/saa_render.c b/saa/saa_render.c new file mode 100644 index 0000000..c69f2c9 --- /dev/null +++ b/saa/saa_render.c | |||
@@ -0,0 +1,424 @@ | |||
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 | |||
41 | static PicturePtr | ||
42 | saa_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 | */ | ||
97 | static void | ||
98 | saa_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 | */ | ||
159 | static void | ||
160 | saa_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 | |||
210 | static Bool | ||
211 | saa_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 | |||
296 | static Bool | ||
297 | saa_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 | |||
357 | static void | ||
358 | saa_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 | |||
399 | void | ||
400 | saa_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 | } | ||
410 | } | ||
411 | |||
412 | void | ||
413 | saa_render_takedown(ScreenPtr pScreen) | ||
414 | { | ||
415 | PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); | ||
416 | struct saa_screen_priv *sscreen = saa_screen(pScreen); | ||
417 | |||
418 | if (ps) { | ||
419 | saa_unwrap(sscreen, ps, Trapezoids); | ||
420 | saa_unwrap(sscreen, ps, Triangles); | ||
421 | saa_unwrap(sscreen, ps, Composite); | ||
422 | } | ||
423 | } | ||
424 | #endif | ||