Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / dmx / dmxpict.c
1 /*
2 * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation on the rights to use, copy, modify, merge,
10 * publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so,
12 * subject to 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
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28 /*
29 * Authors:
30 * Kevin E. Martin <kem@redhat.com>
31 *
32 */
33
34 /** \file
35 * Provide support for the RENDER extension (version 0.8).
36 */
37
38 #ifdef HAVE_DMX_CONFIG_H
39 #include <dmx-config.h>
40 #endif
41
42 #include "dmx.h"
43 #include "dmxsync.h"
44 #include "dmxpict.h"
45 #include "dmxwindow.h"
46 #include "dmxpixmap.h"
47
48 #include "fb.h"
49 #include "pixmapstr.h"
50 #include "dixstruct.h"
51
52 #include <X11/extensions/render.h>
53 #include <X11/extensions/renderproto.h>
54 #include <X11/extensions/Xfixes.h>
55 #include "picture.h"
56 #include "picturestr.h"
57 #include "mipict.h"
58 #include "fbpict.h"
59
60 extern int RenderErrBase;
61 extern int (*ProcRenderVector[RenderNumberRequests]) (ClientPtr);
62
63 static int (*dmxSaveRenderVector[RenderNumberRequests]) (ClientPtr);
64
65 static int dmxProcRenderCreateGlyphSet(ClientPtr client);
66 static int dmxProcRenderFreeGlyphSet(ClientPtr client);
67 static int dmxProcRenderAddGlyphs(ClientPtr client);
68 static int dmxProcRenderFreeGlyphs(ClientPtr client);
69 static int dmxProcRenderCompositeGlyphs(ClientPtr client);
70 static int dmxProcRenderSetPictureTransform(ClientPtr client);
71 static int dmxProcRenderSetPictureFilter(ClientPtr client);
72
73 #if 0
74 /* FIXME: Not (yet) supported */
75 static int dmxProcRenderCreateCursor(ClientPtr client);
76 static int dmxProcRenderCreateAnimCursor(ClientPtr client);
77 #endif
78
79 /** Catch errors that might occur when allocating Glyph Sets. Errors
80 * are saved in dmxGlyphLastError for later handling. */
81 static int dmxGlyphLastError;
82 static int
83 dmxGlyphErrorHandler(Display * dpy, XErrorEvent * ev)
84 {
85 dmxGlyphLastError = ev->error_code;
86 return 0;
87 }
88
89 /** Initialize the Proc Vector for the RENDER extension. The functions
90 * here cannot be handled by the mi layer RENDER hooks either because
91 * the required information is no longer available when it reaches the
92 * mi layer or no mi layer hooks exist. This function is called from
93 * InitOutput() since it should be initialized only once per server
94 * generation. */
95 void
96 dmxInitRender(void)
97 {
98 int i;
99
100 for (i = 0; i < RenderNumberRequests; i++)
101 dmxSaveRenderVector[i] = ProcRenderVector[i];
102
103 ProcRenderVector[X_RenderCreateGlyphSet]
104 = dmxProcRenderCreateGlyphSet;
105 ProcRenderVector[X_RenderFreeGlyphSet]
106 = dmxProcRenderFreeGlyphSet;
107 ProcRenderVector[X_RenderAddGlyphs]
108 = dmxProcRenderAddGlyphs;
109 ProcRenderVector[X_RenderFreeGlyphs]
110 = dmxProcRenderFreeGlyphs;
111 ProcRenderVector[X_RenderCompositeGlyphs8]
112 = dmxProcRenderCompositeGlyphs;
113 ProcRenderVector[X_RenderCompositeGlyphs16]
114 = dmxProcRenderCompositeGlyphs;
115 ProcRenderVector[X_RenderCompositeGlyphs32]
116 = dmxProcRenderCompositeGlyphs;
117 ProcRenderVector[X_RenderSetPictureTransform]
118 = dmxProcRenderSetPictureTransform;
119 ProcRenderVector[X_RenderSetPictureFilter]
120 = dmxProcRenderSetPictureFilter;
121 }
122
123 /** Reset the Proc Vector for the RENDER extension back to the original
124 * functions. This function is called from dmxCloseScreen() during the
125 * server reset (only for screen #0). */
126 void
127 dmxResetRender(void)
128 {
129 int i;
130
131 for (i = 0; i < RenderNumberRequests; i++)
132 ProcRenderVector[i] = dmxSaveRenderVector[i];
133 }
134
135 /** Initialize the RENDER extension, allocate the picture privates and
136 * wrap mi function hooks. If the shadow frame buffer is used, then
137 * call the appropriate fb initialization function. */
138 Bool
139 dmxPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
140 {
141 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
142 PictureScreenPtr ps;
143
144 if (!miPictureInit(pScreen, formats, nformats))
145 return FALSE;
146
147 if (!dixRegisterPrivateKey
148 (&dmxPictPrivateKeyRec, PRIVATE_PICTURE, sizeof(dmxPictPrivRec)))
149 return FALSE;
150
151 ps = GetPictureScreen(pScreen);
152
153 DMX_WRAP(CreatePicture, dmxCreatePicture, dmxScreen, ps);
154 DMX_WRAP(DestroyPicture, dmxDestroyPicture, dmxScreen, ps);
155
156 DMX_WRAP(ChangePictureClip, dmxChangePictureClip, dmxScreen, ps);
157 DMX_WRAP(DestroyPictureClip, dmxDestroyPictureClip, dmxScreen, ps);
158
159 DMX_WRAP(ChangePicture, dmxChangePicture, dmxScreen, ps);
160 DMX_WRAP(ValidatePicture, dmxValidatePicture, dmxScreen, ps);
161
162 DMX_WRAP(Composite, dmxComposite, dmxScreen, ps);
163 DMX_WRAP(Glyphs, dmxGlyphs, dmxScreen, ps);
164 DMX_WRAP(CompositeRects, dmxCompositeRects, dmxScreen, ps);
165
166 DMX_WRAP(Trapezoids, dmxTrapezoids, dmxScreen, ps);
167 DMX_WRAP(Triangles, dmxTriangles, dmxScreen, ps);
168
169 return TRUE;
170 }
171
172 /** Find the appropriate format on the requested screen given the
173 * internal format requested. The list of formats is searched
174 * sequentially as the XRenderFindFormat() function does not always
175 * find the appropriate format when a specific format is requested. */
176 static XRenderPictFormat *
177 dmxFindFormat(DMXScreenInfo * dmxScreen, PictFormatPtr pFmt)
178 {
179 XRenderPictFormat *pFormat = NULL;
180 int i = 0;
181
182 if (!pFmt || !dmxScreen->beDisplay)
183 return pFormat;
184
185 while (1) {
186 pFormat = XRenderFindFormat(dmxScreen->beDisplay, 0, 0, i++);
187 if (!pFormat)
188 break;
189
190 if (pFormat->type != pFmt->type)
191 continue;
192 if (pFormat->depth != pFmt->depth)
193 continue;
194 if (pFormat->direct.red != pFmt->direct.red)
195 continue;
196 if (pFormat->direct.redMask != pFmt->direct.redMask)
197 continue;
198 if (pFormat->direct.green != pFmt->direct.green)
199 continue;
200 if (pFormat->direct.greenMask != pFmt->direct.greenMask)
201 continue;
202 if (pFormat->direct.blue != pFmt->direct.blue)
203 continue;
204 if (pFormat->direct.blueMask != pFmt->direct.blueMask)
205 continue;
206 if (pFormat->direct.alpha != pFmt->direct.alpha)
207 continue;
208 if (pFormat->direct.alphaMask != pFmt->direct.alphaMask)
209 continue;
210
211 /* We have a match! */
212 break;
213 }
214
215 return pFormat;
216 }
217
218 /** Free \a glyphSet on back-end screen number \a idx. */
219 Bool
220 dmxBEFreeGlyphSet(ScreenPtr pScreen, GlyphSetPtr glyphSet)
221 {
222 dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
223 int idx = pScreen->myNum;
224 DMXScreenInfo *dmxScreen = &dmxScreens[idx];
225
226 if (glyphPriv->glyphSets[idx]) {
227 XRenderFreeGlyphSet(dmxScreen->beDisplay, glyphPriv->glyphSets[idx]);
228 glyphPriv->glyphSets[idx] = (GlyphSet) 0;
229 return TRUE;
230 }
231
232 return FALSE;
233 }
234
235 /** Create \a glyphSet on the backend screen number \a idx. */
236 int
237 dmxBECreateGlyphSet(int idx, GlyphSetPtr glyphSet)
238 {
239 XRenderPictFormat *pFormat;
240 DMXScreenInfo *dmxScreen = &dmxScreens[idx];
241 dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
242 PictFormatPtr pFmt = glyphSet->format;
243 int (*oldErrorHandler) (Display *, XErrorEvent *);
244
245 pFormat = dmxFindFormat(dmxScreen, pFmt);
246 if (!pFormat) {
247 return BadMatch;
248 }
249
250 dmxGlyphLastError = 0;
251 oldErrorHandler = XSetErrorHandler(dmxGlyphErrorHandler);
252
253 /* Catch when this fails */
254 glyphPriv->glyphSets[idx]
255 = XRenderCreateGlyphSet(dmxScreen->beDisplay, pFormat);
256
257 XSetErrorHandler(oldErrorHandler);
258
259 if (dmxGlyphLastError) {
260 return dmxGlyphLastError;
261 }
262
263 return Success;
264 }
265
266 /** Create a Glyph Set on each screen. Save the glyphset ID from each
267 * screen in the Glyph Set's private structure. Fail if the format
268 * requested is not available or if the Glyph Set cannot be created on
269 * the screen. */
270 static int
271 dmxProcRenderCreateGlyphSet(ClientPtr client)
272 {
273 int ret;
274
275 REQUEST(xRenderCreateGlyphSetReq);
276
277 ret = dmxSaveRenderVector[stuff->renderReqType] (client);
278
279 if (ret == Success) {
280 GlyphSetPtr glyphSet;
281 dmxGlyphPrivPtr glyphPriv;
282 int i;
283
284 /* Look up glyphSet that was just created ???? */
285 /* Store glyphsets from backends in glyphSet->devPrivate ????? */
286 /* Make sure we handle all errors here!! */
287
288 dixLookupResourceByType((pointer *) &glyphSet,
289 stuff->gsid, GlyphSetType,
290 client, DixDestroyAccess);
291
292 glyphPriv = malloc(sizeof(dmxGlyphPrivRec));
293 if (!glyphPriv)
294 return BadAlloc;
295 glyphPriv->glyphSets = NULL;
296 MAXSCREENSALLOC_RETURN(glyphPriv->glyphSets, BadAlloc);
297 DMX_SET_GLYPH_PRIV(glyphSet, glyphPriv);
298
299 for (i = 0; i < dmxNumScreens; i++) {
300 DMXScreenInfo *dmxScreen = &dmxScreens[i];
301 int beret;
302
303 if (!dmxScreen->beDisplay) {
304 glyphPriv->glyphSets[i] = 0;
305 continue;
306 }
307
308 if ((beret = dmxBECreateGlyphSet(i, glyphSet)) != Success) {
309 int j;
310
311 /* Free the glyph sets we've allocated thus far */
312 for (j = 0; j < i; j++)
313 dmxBEFreeGlyphSet(screenInfo.screens[j], glyphSet);
314
315 /* Free the resource created by render */
316 FreeResource(stuff->gsid, RT_NONE);
317
318 return beret;
319 }
320 }
321 }
322
323 return ret;
324 }
325
326 /** Free the previously allocated Glyph Sets for each screen. */
327 static int
328 dmxProcRenderFreeGlyphSet(ClientPtr client)
329 {
330 GlyphSetPtr glyphSet;
331
332 REQUEST(xRenderFreeGlyphSetReq);
333
334 REQUEST_SIZE_MATCH(xRenderFreeGlyphSetReq);
335 dixLookupResourceByType((pointer *) &glyphSet,
336 stuff->glyphset, GlyphSetType,
337 client, DixDestroyAccess);
338
339 if (glyphSet && glyphSet->refcnt == 1) {
340 dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
341 int i;
342
343 for (i = 0; i < dmxNumScreens; i++) {
344 DMXScreenInfo *dmxScreen = &dmxScreens[i];
345
346 if (dmxScreen->beDisplay) {
347 if (dmxBEFreeGlyphSet(screenInfo.screens[i], glyphSet))
348 dmxSync(dmxScreen, FALSE);
349 }
350 }
351
352 MAXSCREENSFREE(glyphPriv->glyphSets);
353 free(glyphPriv);
354 DMX_SET_GLYPH_PRIV(glyphSet, NULL);
355 }
356
357 return dmxSaveRenderVector[stuff->renderReqType] (client);
358 }
359
360 /** Add glyphs to the Glyph Set on each screen. */
361 static int
362 dmxProcRenderAddGlyphs(ClientPtr client)
363 {
364 int ret;
365
366 REQUEST(xRenderAddGlyphsReq);
367
368 ret = dmxSaveRenderVector[stuff->renderReqType] (client);
369
370 if (ret == Success) {
371 GlyphSetPtr glyphSet;
372 dmxGlyphPrivPtr glyphPriv;
373 int i;
374 int nglyphs;
375 CARD32 *gids;
376 Glyph *gidsCopy;
377 xGlyphInfo *gi;
378 CARD8 *bits;
379 int nbytes;
380
381 dixLookupResourceByType((pointer *) &glyphSet,
382 stuff->glyphset, GlyphSetType,
383 client, DixReadAccess);
384 glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
385
386 nglyphs = stuff->nglyphs;
387 gids = (CARD32 *) (stuff + 1);
388 gi = (xGlyphInfo *) (gids + nglyphs);
389 bits = (CARD8 *) (gi + nglyphs);
390 nbytes = ((stuff->length << 2) -
391 sizeof(xRenderAddGlyphsReq) -
392 (sizeof(CARD32) + sizeof(xGlyphInfo)) * nglyphs);
393
394 gidsCopy = malloc(sizeof(*gidsCopy) * nglyphs);
395 for (i = 0; i < nglyphs; i++)
396 gidsCopy[i] = gids[i];
397
398 /* FIXME: Will this ever fail? */
399 for (i = 0; i < dmxNumScreens; i++) {
400 DMXScreenInfo *dmxScreen = &dmxScreens[i];
401
402 if (dmxScreen->beDisplay) {
403 XRenderAddGlyphs(dmxScreen->beDisplay,
404 glyphPriv->glyphSets[i],
405 gidsCopy,
406 (XGlyphInfo *) gi,
407 nglyphs, (char *) bits, nbytes);
408 dmxSync(dmxScreen, FALSE);
409 }
410 }
411 free(gidsCopy);
412 }
413
414 return ret;
415 }
416
417 /** Free glyphs from the Glyph Set for each screen. */
418 static int
419 dmxProcRenderFreeGlyphs(ClientPtr client)
420 {
421 GlyphSetPtr glyphSet;
422
423 REQUEST(xRenderFreeGlyphsReq);
424
425 REQUEST_AT_LEAST_SIZE(xRenderFreeGlyphsReq);
426 dixLookupResourceByType((pointer *) &glyphSet,
427 stuff->glyphset, GlyphSetType,
428 client, DixWriteAccess);
429
430 if (glyphSet) {
431 dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
432 int i;
433 int nglyphs;
434 Glyph *gids;
435
436 nglyphs = ((client->req_len << 2) - sizeof(xRenderFreeGlyphsReq)) >> 2;
437 if (nglyphs) {
438 gids = malloc(sizeof(*gids) * nglyphs);
439 for (i = 0; i < nglyphs; i++)
440 gids[i] = ((CARD32 *) (stuff + 1))[i];
441
442 for (i = 0; i < dmxNumScreens; i++) {
443 DMXScreenInfo *dmxScreen = &dmxScreens[i];
444
445 if (dmxScreen->beDisplay) {
446 XRenderFreeGlyphs(dmxScreen->beDisplay,
447 glyphPriv->glyphSets[i], gids, nglyphs);
448 dmxSync(dmxScreen, FALSE);
449 }
450 }
451 free(gids);
452 }
453 }
454
455 return dmxSaveRenderVector[stuff->renderReqType] (client);
456 }
457
458 /** Composite glyphs on each screen into the requested picture. If
459 * either the src or dest picture has not been allocated due to lazy
460 * window creation, this request will gracefully return. */
461 static int
462 dmxProcRenderCompositeGlyphs(ClientPtr client)
463 {
464 int ret;
465
466 REQUEST(xRenderCompositeGlyphsReq);
467
468 ret = dmxSaveRenderVector[stuff->renderReqType] (client);
469
470 /* For the following to work with PanoramiX, it assumes that Render
471 * wraps the ProcRenderVector after dmxRenderInit has been called.
472 */
473 if (ret == Success) {
474 PicturePtr pSrc;
475 dmxPictPrivPtr pSrcPriv;
476 PicturePtr pDst;
477 dmxPictPrivPtr pDstPriv;
478 PictFormatPtr pFmt;
479 XRenderPictFormat *pFormat;
480 int size;
481
482 int scrnNum;
483 DMXScreenInfo *dmxScreen;
484
485 CARD8 *buffer;
486 CARD8 *end;
487 int space;
488
489 int nglyph;
490 char *glyphs;
491 char *curGlyph;
492
493 xGlyphElt *elt;
494 int nelt;
495 XGlyphElt8 *elts;
496 XGlyphElt8 *curElt;
497
498 GlyphSetPtr glyphSet;
499 dmxGlyphPrivPtr glyphPriv;
500
501 dixLookupResourceByType((pointer *) &pSrc,
502 stuff->src, PictureType, client, DixReadAccess);
503
504 pSrcPriv = DMX_GET_PICT_PRIV(pSrc);
505 if (!pSrcPriv->pict)
506 return ret;
507
508 dixLookupResourceByType((pointer *) &pDst,
509 stuff->dst, PictureType,
510 client, DixWriteAccess);
511
512 pDstPriv = DMX_GET_PICT_PRIV(pDst);
513 if (!pDstPriv->pict)
514 return ret;
515
516 scrnNum = pDst->pDrawable->pScreen->myNum;
517 dmxScreen = &dmxScreens[scrnNum];
518
519 /* Note: If the back-end display has been detached, then it
520 * should not be possible to reach here since the pSrcPriv->pict
521 * and pDstPriv->pict will have already been set to 0.
522 */
523 if (!dmxScreen->beDisplay)
524 return ret;
525
526 if (stuff->maskFormat)
527 dixLookupResourceByType((pointer *) &pFmt,
528 stuff->maskFormat, PictFormatType,
529 client, DixReadAccess);
530 else
531 pFmt = NULL;
532
533 pFormat = dmxFindFormat(dmxScreen, pFmt);
534
535 switch (stuff->renderReqType) {
536 case X_RenderCompositeGlyphs8:
537 size = sizeof(CARD8);
538 break;
539 case X_RenderCompositeGlyphs16:
540 size = sizeof(CARD16);
541 break;
542 case X_RenderCompositeGlyphs32:
543 size = sizeof(CARD32);
544 break;
545 default:
546 return BadPictOp; /* Can't happen */
547 }
548
549 buffer = (CARD8 *) (stuff + 1);
550 end = (CARD8 *) stuff + (stuff->length << 2);
551 nelt = 0;
552 nglyph = 0;
553 while (buffer + sizeof(xGlyphElt) < end) {
554 elt = (xGlyphElt *) buffer;
555 buffer += sizeof(xGlyphElt);
556
557 if (elt->len == 0xff) {
558 buffer += 4;
559 }
560 else {
561 nelt++;
562 nglyph += elt->len;
563 space = size * elt->len;
564 if (space & 3)
565 space += 4 - (space & 3);
566 buffer += space;
567 }
568 }
569
570 /* The following only works for Render version > 0.2 */
571
572 /* All of the XGlyphElt* structure sizes are identical */
573 elts = malloc(nelt * sizeof(XGlyphElt8));
574 if (!elts)
575 return BadAlloc;
576
577 glyphs = malloc(nglyph * size);
578 if (!glyphs) {
579 free(elts);
580 return BadAlloc;
581 }
582
583 buffer = (CARD8 *) (stuff + 1);
584 end = (CARD8 *) stuff + (stuff->length << 2);
585 curGlyph = glyphs;
586 curElt = elts;
587
588 dixLookupResourceByType((pointer *) &glyphSet,
589 stuff->glyphset, GlyphSetType,
590 client, DixReadAccess);
591 glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
592
593 while (buffer + sizeof(xGlyphElt) < end) {
594 elt = (xGlyphElt *) buffer;
595 buffer += sizeof(xGlyphElt);
596
597 if (elt->len == 0xff) {
598 dixLookupResourceByType((pointer *) &glyphSet,
599 *((CARD32 *) buffer),
600 GlyphSetType, client, DixReadAccess);
601 glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
602 buffer += 4;
603 }
604 else {
605 curElt->glyphset = glyphPriv->glyphSets[scrnNum];
606 curElt->xOff = elt->deltax;
607 curElt->yOff = elt->deltay;
608 curElt->nchars = elt->len;
609 curElt->chars = curGlyph;
610
611 memcpy(curGlyph, buffer, size * elt->len);
612 curGlyph += size * elt->len;
613
614 curElt++;
615
616 space = size * elt->len;
617 if (space & 3)
618 space += 4 - (space & 3);
619 buffer += space;
620 }
621 }
622
623 switch (stuff->renderReqType) {
624 case X_RenderCompositeGlyphs8:
625 XRenderCompositeText8(dmxScreen->beDisplay, stuff->op,
626 pSrcPriv->pict, pDstPriv->pict,
627 pFormat,
628 stuff->xSrc, stuff->ySrc, 0, 0, elts, nelt);
629 break;
630 case X_RenderCompositeGlyphs16:
631 XRenderCompositeText16(dmxScreen->beDisplay, stuff->op,
632 pSrcPriv->pict, pDstPriv->pict,
633 pFormat,
634 stuff->xSrc, stuff->ySrc,
635 0, 0, (XGlyphElt16 *) elts, nelt);
636 break;
637 case X_RenderCompositeGlyphs32:
638 XRenderCompositeText32(dmxScreen->beDisplay, stuff->op,
639 pSrcPriv->pict, pDstPriv->pict,
640 pFormat,
641 stuff->xSrc, stuff->ySrc,
642 0, 0, (XGlyphElt32 *) elts, nelt);
643 break;
644 }
645
646 dmxSync(dmxScreen, FALSE);
647
648 free(elts);
649 free(glyphs);
650 }
651
652 return ret;
653 }
654
655 /** Set the picture transform on each screen. */
656 static int
657 dmxProcRenderSetPictureTransform(ClientPtr client)
658 {
659 DMXScreenInfo *dmxScreen;
660 PicturePtr pPicture;
661 dmxPictPrivPtr pPictPriv;
662 XTransform xform;
663
664 REQUEST(xRenderSetPictureTransformReq);
665
666 REQUEST_SIZE_MATCH(xRenderSetPictureTransformReq);
667 VERIFY_PICTURE(pPicture, stuff->picture, client, DixWriteAccess);
668
669 /* For the following to work with PanoramiX, it assumes that Render
670 * wraps the ProcRenderVector after dmxRenderInit has been called.
671 */
672 dmxScreen = &dmxScreens[pPicture->pDrawable->pScreen->myNum];
673 pPictPriv = DMX_GET_PICT_PRIV(pPicture);
674
675 if (pPictPriv->pict) {
676 xform.matrix[0][0] = stuff->transform.matrix11;
677 xform.matrix[0][1] = stuff->transform.matrix12;
678 xform.matrix[0][2] = stuff->transform.matrix13;
679 xform.matrix[1][0] = stuff->transform.matrix21;
680 xform.matrix[1][1] = stuff->transform.matrix22;
681 xform.matrix[1][2] = stuff->transform.matrix23;
682 xform.matrix[2][0] = stuff->transform.matrix31;
683 xform.matrix[2][1] = stuff->transform.matrix32;
684 xform.matrix[2][2] = stuff->transform.matrix33;
685
686 XRenderSetPictureTransform(dmxScreen->beDisplay,
687 pPictPriv->pict, &xform);
688 dmxSync(dmxScreen, FALSE);
689 }
690
691 return dmxSaveRenderVector[stuff->renderReqType] (client);
692 }
693
694 /** Set the picture filter on each screen. */
695 static int
696 dmxProcRenderSetPictureFilter(ClientPtr client)
697 {
698 DMXScreenInfo *dmxScreen;
699 PicturePtr pPicture;
700 dmxPictPrivPtr pPictPriv;
701 char *filter;
702 XFixed *params;
703 int nparams;
704
705 REQUEST(xRenderSetPictureFilterReq);
706
707 REQUEST_AT_LEAST_SIZE(xRenderSetPictureFilterReq);
708 VERIFY_PICTURE(pPicture, stuff->picture, client, DixWriteAccess);
709
710 /* For the following to work with PanoramiX, it assumes that Render
711 * wraps the ProcRenderVector after dmxRenderInit has been called.
712 */
713 dmxScreen = &dmxScreens[pPicture->pDrawable->pScreen->myNum];
714 pPictPriv = DMX_GET_PICT_PRIV(pPicture);
715
716 if (pPictPriv->pict) {
717 filter = (char *) (stuff + 1);
718 params = (XFixed *) (filter + ((stuff->nbytes + 3) & ~3));
719 nparams = ((XFixed *) stuff + client->req_len) - params;
720
721 XRenderSetPictureFilter(dmxScreen->beDisplay,
722 pPictPriv->pict, filter, params, nparams);
723 dmxSync(dmxScreen, FALSE);
724 }
725
726 return dmxSaveRenderVector[stuff->renderReqType] (client);
727 }
728
729 /** Create a picture on the appropriate screen. This is the actual
730 * function that creates the picture. However, if the associated
731 * window has not yet been created due to lazy window creation, then
732 * delay the picture creation until the window is mapped. */
733 static Picture
734 dmxDoCreatePicture(PicturePtr pPicture)
735 {
736 DrawablePtr pDraw = pPicture->pDrawable;
737 ScreenPtr pScreen = pDraw->pScreen;
738 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
739 XRenderPictFormat *pFormat;
740 Drawable draw;
741
742 if (pPicture->pDrawable->type == DRAWABLE_WINDOW) {
743 dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV((WindowPtr) (pDraw));
744
745 if (!(draw = pWinPriv->window)) {
746 /* Window has not been created yet due to the window
747 * optimization. Delay picture creation until window is
748 * mapped.
749 */
750 pWinPriv->hasPict = TRUE;
751 return 0;
752 }
753 }
754 else {
755 dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV((PixmapPtr) (pDraw));
756
757 if (!(draw = pPixPriv->pixmap)) {
758 /* FIXME: Zero width/height pixmap?? */
759 return 0;
760 }
761 }
762
763 /* This should not be reached if the back-end display has been
764 * detached because the pWinPriv->window or the pPixPriv->pixmap
765 * will be NULL; however, we add it here for completeness
766 */
767 if (!dmxScreen->beDisplay)
768 return 0;
769
770 pFormat = dmxFindFormat(dmxScreen, pPicture->pFormat);
771
772 return XRenderCreatePicture(dmxScreen->beDisplay, draw, pFormat, 0, 0);
773 }
774
775 /** Create a list of pictures. This function is called by
776 * dmxCreateAndRealizeWindow() during the lazy window creation
777 * realization process. It creates the entire list of pictures that
778 * are associated with the given window. */
779 void
780 dmxCreatePictureList(WindowPtr pWindow)
781 {
782 PicturePtr pPicture = GetPictureWindow(pWindow);
783
784 while (pPicture) {
785 dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture);
786
787 /* Create the picture for this window */
788 pPictPriv->pict = dmxDoCreatePicture(pPicture);
789
790 /* ValidatePicture takes care of the state changes */
791
792 pPicture = pPicture->pNext;
793 }
794 }
795
796 /** Create \a pPicture on the backend. */
797 int
798 dmxBECreatePicture(PicturePtr pPicture)
799 {
800 dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture);
801
802 /* Create picutre on BE */
803 pPictPriv->pict = dmxDoCreatePicture(pPicture);
804
805 /* Flush changes to the backend server */
806 dmxValidatePicture(pPicture, (1 << (CPLastBit + 1)) - 1);
807
808 return Success;
809 }
810
811 /** Create a picture. This function handles the CreatePicture
812 * unwrapping/wrapping and calls dmxDoCreatePicture to actually create
813 * the picture on the appropriate screen. */
814 int
815 dmxCreatePicture(PicturePtr pPicture)
816 {
817 ScreenPtr pScreen = pPicture->pDrawable->pScreen;
818 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
819 PictureScreenPtr ps = GetPictureScreen(pScreen);
820 dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture);
821 int ret = Success;
822
823 DMX_UNWRAP(CreatePicture, dmxScreen, ps);
824 #if 1
825 if (ps->CreatePicture)
826 ret = ps->CreatePicture(pPicture);
827 #endif
828
829 /* Create picture on back-end server */
830 pPictPriv->pict = dmxDoCreatePicture(pPicture);
831 pPictPriv->savedMask = 0;
832
833 DMX_WRAP(CreatePicture, dmxCreatePicture, dmxScreen, ps);
834
835 return ret;
836 }
837
838 /** Destroy \a pPicture on the back-end server. */
839 Bool
840 dmxBEFreePicture(PicturePtr pPicture)
841 {
842 ScreenPtr pScreen = pPicture->pDrawable->pScreen;
843 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
844 dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture);
845
846 if (pPictPriv->pict) {
847 XRenderFreePicture(dmxScreen->beDisplay, pPictPriv->pict);
848 pPictPriv->pict = (Picture) 0;
849 return TRUE;
850 }
851
852 return FALSE;
853 }
854
855 /** Destroy a list of pictures that are associated with the window that
856 * is being destroyed. This function is called by #dmxDestroyWindow().
857 * */
858 Bool
859 dmxDestroyPictureList(WindowPtr pWindow)
860 {
861 PicturePtr pPicture = GetPictureWindow(pWindow);
862 Bool ret = FALSE;
863
864 while (pPicture) {
865 ret |= dmxBEFreePicture(pPicture);
866 pPicture = pPicture->pNext;
867 }
868
869 return ret;
870 }
871
872 /** Destroy a picture. This function calls the wrapped function that
873 * frees the resources in the DMX server associated with this
874 * picture. */
875 void
876 dmxDestroyPicture(PicturePtr pPicture)
877 {
878 ScreenPtr pScreen = pPicture->pDrawable->pScreen;
879 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
880 PictureScreenPtr ps = GetPictureScreen(pScreen);
881
882 DMX_UNWRAP(DestroyPicture, dmxScreen, ps);
883
884 /* Destroy picture on back-end server */
885 if (dmxBEFreePicture(pPicture))
886 dmxSync(dmxScreen, FALSE);
887
888 #if 1
889 if (ps->DestroyPicture)
890 ps->DestroyPicture(pPicture);
891 #endif
892 DMX_WRAP(DestroyPicture, dmxDestroyPicture, dmxScreen, ps);
893 }
894
895 /** Change the picture's list of clip rectangles. */
896 int
897 dmxChangePictureClip(PicturePtr pPicture, int clipType, pointer value, int n)
898 {
899 ScreenPtr pScreen = pPicture->pDrawable->pScreen;
900 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
901 PictureScreenPtr ps = GetPictureScreen(pScreen);
902 dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture);
903
904 DMX_UNWRAP(ChangePictureClip, dmxScreen, ps);
905 #if 1
906 if (ps->ChangePictureClip)
907 ps->ChangePictureClip(pPicture, clipType, value, n);
908 #endif
909
910 /* Change picture clip rects on back-end server */
911 if (pPictPriv->pict) {
912 /* The clip has already been changed into a region by the mi
913 * routine called above.
914 */
915 if (clipType == CT_NONE) {
916 /* Disable clipping, show all */
917 XFixesSetPictureClipRegion(dmxScreen->beDisplay,
918 pPictPriv->pict, 0, 0, None);
919 }
920 else if (pPicture->clientClip) {
921 RegionPtr pClip = pPicture->clientClip;
922 BoxPtr pBox = RegionRects(pClip);
923 int nBox = RegionNumRects(pClip);
924 XRectangle *pRects;
925 XRectangle *pRect;
926 int nRects;
927
928 nRects = nBox;
929 pRects = pRect = malloc(nRects * sizeof(*pRect));
930
931 while (nBox--) {
932 pRect->x = pBox->x1;
933 pRect->y = pBox->y1;
934 pRect->width = pBox->x2 - pBox->x1;
935 pRect->height = pBox->y2 - pBox->y1;
936 pBox++;
937 pRect++;
938 }
939
940 XRenderSetPictureClipRectangles(dmxScreen->beDisplay,
941 pPictPriv->pict,
942 0, 0, pRects, nRects);
943 free(pRects);
944 }
945 else {
946 XRenderSetPictureClipRectangles(dmxScreen->beDisplay,
947 pPictPriv->pict, 0, 0, NULL, 0);
948 }
949 dmxSync(dmxScreen, FALSE);
950 }
951 else {
952 /* FIXME: Handle saving clip region when offscreen */
953 }
954
955 DMX_WRAP(ChangePictureClip, dmxChangePictureClip, dmxScreen, ps);
956
957 return Success;
958 }
959
960 /** Destroy the picture's list of clip rectangles. */
961 void
962 dmxDestroyPictureClip(PicturePtr pPicture)
963 {
964 ScreenPtr pScreen = pPicture->pDrawable->pScreen;
965 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
966 PictureScreenPtr ps = GetPictureScreen(pScreen);
967 dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture);
968
969 DMX_UNWRAP(DestroyPictureClip, dmxScreen, ps);
970 #if 1
971 if (ps->DestroyPictureClip)
972 ps->DestroyPictureClip(pPicture);
973 #endif
974
975 /* Destroy picture clip rects on back-end server */
976 if (pPictPriv->pict) {
977 XRenderSetPictureClipRectangles(dmxScreen->beDisplay,
978 pPictPriv->pict, 0, 0, NULL, 0);
979 dmxSync(dmxScreen, FALSE);
980 }
981 else {
982 /* FIXME: Handle destroying clip region when offscreen */
983 }
984
985 DMX_WRAP(DestroyPictureClip, dmxDestroyPictureClip, dmxScreen, ps);
986 }
987
988 /** Change the attributes of the pictures. If the picture has not yet
989 * been created due to lazy window creation, save the mask so that it
990 * can be used to appropriately initialize the picture's attributes
991 * when it is created later. */
992 void
993 dmxChangePicture(PicturePtr pPicture, Mask mask)
994 {
995 ScreenPtr pScreen = pPicture->pDrawable->pScreen;
996 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
997 PictureScreenPtr ps = GetPictureScreen(pScreen);
998 dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture);
999
1000 DMX_UNWRAP(ChangePicture, dmxScreen, ps);
1001 #if 1
1002 if (ps->ChangePicture)
1003 ps->ChangePicture(pPicture, mask);
1004 #endif
1005
1006 /* Picture attribute changes are handled in ValidatePicture */
1007 pPictPriv->savedMask |= mask;
1008
1009 DMX_WRAP(ChangePicture, dmxChangePicture, dmxScreen, ps);
1010 }
1011
1012 /** Validate the picture's attributes before rendering to it. Update
1013 * any picture attributes that have been changed by one of the higher
1014 * layers. */
1015 void
1016 dmxValidatePicture(PicturePtr pPicture, Mask mask)
1017 {
1018 ScreenPtr pScreen = pPicture->pDrawable->pScreen;
1019 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
1020 PictureScreenPtr ps = GetPictureScreen(pScreen);
1021 dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture);
1022
1023 DMX_UNWRAP(ValidatePicture, dmxScreen, ps);
1024
1025 /* Change picture attributes on back-end server */
1026 if (pPictPriv->pict) {
1027 XRenderPictureAttributes attribs;
1028
1029 if (mask & CPRepeat) {
1030 attribs.repeat = pPicture->repeatType;
1031 }
1032 if (mask & CPAlphaMap) {
1033 if (pPicture->alphaMap) {
1034 dmxPictPrivPtr pAlphaPriv;
1035
1036 pAlphaPriv = DMX_GET_PICT_PRIV(pPicture->alphaMap);
1037 if (pAlphaPriv->pict) {
1038 attribs.alpha_map = pAlphaPriv->pict;
1039 }
1040 else {
1041 /* FIXME: alpha picture drawable has not been created?? */
1042 return; /* or should this be: attribs.alpha_map = None; */
1043 }
1044 }
1045 else {
1046 attribs.alpha_map = None;
1047 }
1048 }
1049 if (mask & CPAlphaXOrigin)
1050 attribs.alpha_x_origin = pPicture->alphaOrigin.x;
1051 if (mask & CPAlphaYOrigin)
1052 attribs.alpha_y_origin = pPicture->alphaOrigin.y;
1053 if (mask & CPClipXOrigin)
1054 attribs.clip_x_origin = pPicture->clipOrigin.x;
1055 if (mask & CPClipYOrigin)
1056 attribs.clip_y_origin = pPicture->clipOrigin.y;
1057 if (mask & CPClipMask)
1058 mask &= ~CPClipMask; /* Handled in ChangePictureClip */
1059 if (mask & CPGraphicsExposure)
1060 attribs.graphics_exposures = pPicture->graphicsExposures;
1061 if (mask & CPSubwindowMode)
1062 attribs.subwindow_mode = pPicture->subWindowMode;
1063 if (mask & CPPolyEdge)
1064 attribs.poly_edge = pPicture->polyEdge;
1065 if (mask & CPPolyMode)
1066 attribs.poly_mode = pPicture->polyMode;
1067 if (mask & CPComponentAlpha)
1068 attribs.component_alpha = pPicture->componentAlpha;
1069
1070 XRenderChangePicture(dmxScreen->beDisplay, pPictPriv->pict,
1071 mask, &attribs);
1072 dmxSync(dmxScreen, FALSE);
1073 }
1074 else {
1075 pPictPriv->savedMask |= mask;
1076 }
1077
1078 #if 1
1079 if (ps->ValidatePicture)
1080 ps->ValidatePicture(pPicture, mask);
1081 #endif
1082
1083 DMX_WRAP(ValidatePicture, dmxValidatePicture, dmxScreen, ps);
1084 }
1085
1086 /** Composite a picture on the appropriate screen by combining the
1087 * specified rectangle of the transformed src and mask operands with
1088 * the specified rectangle of the dst using op as the compositing
1089 * operator. For a complete description see the protocol document of
1090 * the RENDER library. */
1091 void
1092 dmxComposite(CARD8 op,
1093 PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
1094 INT16 xSrc, INT16 ySrc,
1095 INT16 xMask, INT16 yMask,
1096 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
1097 {
1098 ScreenPtr pScreen = pDst->pDrawable->pScreen;
1099 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
1100 PictureScreenPtr ps = GetPictureScreen(pScreen);
1101 dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc);
1102 dmxPictPrivPtr pMaskPriv = NULL;
1103 dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst);
1104
1105 if (pMask)
1106 pMaskPriv = DMX_GET_PICT_PRIV(pMask);
1107
1108 DMX_UNWRAP(Composite, dmxScreen, ps);
1109 #if 0
1110 if (ps->Composite)
1111 ps->Composite(op, pSrc, pMask, pDst,
1112 xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
1113 #endif
1114
1115 /* Composite on back-end server */
1116 if (pSrcPriv->pict && pDstPriv->pict &&
1117 ((pMaskPriv && pMaskPriv->pict) || !pMaskPriv)) {
1118 XRenderComposite(dmxScreen->beDisplay,
1119 op,
1120 pSrcPriv->pict,
1121 pMaskPriv ? pMaskPriv->pict : None,
1122 pDstPriv->pict,
1123 xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
1124 dmxSync(dmxScreen, FALSE);
1125 }
1126
1127 DMX_WRAP(Composite, dmxComposite, dmxScreen, ps);
1128 }
1129
1130 /** Null function to catch when/if RENDER calls lower level mi hooks.
1131 * Compositing glyphs is handled by dmxProcRenderCompositeGlyphs().
1132 * This function should never be called. */
1133 void
1134 dmxGlyphs(CARD8 op,
1135 PicturePtr pSrc, PicturePtr pDst,
1136 PictFormatPtr maskFormat,
1137 INT16 xSrc, INT16 ySrc,
1138 int nlists, GlyphListPtr lists, GlyphPtr * glyphs)
1139 {
1140 /* This won't work, so we need to wrap ProcRenderCompositeGlyphs */
1141 }
1142
1143 /** Fill a rectangle on the appropriate screen by combining the color
1144 * with the dest picture in the area specified by the list of
1145 * rectangles. For a complete description see the protocol document of
1146 * the RENDER library. */
1147 void
1148 dmxCompositeRects(CARD8 op,
1149 PicturePtr pDst,
1150 xRenderColor * color, int nRect, xRectangle *rects)
1151 {
1152 ScreenPtr pScreen = pDst->pDrawable->pScreen;
1153 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
1154 PictureScreenPtr ps = GetPictureScreen(pScreen);
1155 dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pDst);
1156
1157 DMX_UNWRAP(CompositeRects, dmxScreen, ps);
1158 #if 0
1159 if (ps->CompositeRects)
1160 ps->CompositeRects(op, pDst, color, nRect, rects);
1161 #endif
1162
1163 /* CompositeRects on back-end server */
1164 if (pPictPriv->pict) {
1165 XRenderFillRectangles(dmxScreen->beDisplay,
1166 op,
1167 pPictPriv->pict,
1168 (XRenderColor *) color,
1169 (XRectangle *) rects, nRect);
1170 dmxSync(dmxScreen, FALSE);
1171 }
1172
1173 DMX_WRAP(CompositeRects, dmxCompositeRects, dmxScreen, ps);
1174 }
1175
1176 /** Indexed color visuals are not yet supported. */
1177 Bool
1178 dmxInitIndexed(ScreenPtr pScreen, PictFormatPtr pFormat)
1179 {
1180 return TRUE;
1181 }
1182
1183 /** Indexed color visuals are not yet supported. */
1184 void
1185 dmxCloseIndexed(ScreenPtr pScreen, PictFormatPtr pFormat)
1186 {
1187 }
1188
1189 /** Indexed color visuals are not yet supported. */
1190 void
1191 dmxUpdateIndexed(ScreenPtr pScreen, PictFormatPtr pFormat,
1192 int ndef, xColorItem * pdef)
1193 {
1194 }
1195
1196 /** Composite a list of trapezoids on the appropriate screen. For a
1197 * complete description see the protocol document of the RENDER
1198 * library. */
1199 void
1200 dmxTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1201 PictFormatPtr maskFormat,
1202 INT16 xSrc, INT16 ySrc, int ntrap, xTrapezoid * traps)
1203 {
1204 ScreenPtr pScreen = pDst->pDrawable->pScreen;
1205 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
1206 PictureScreenPtr ps = GetPictureScreen(pScreen);
1207 dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc);
1208 dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst);
1209
1210 DMX_UNWRAP(Trapezoids, dmxScreen, ps);
1211 #if 0
1212 if (ps->Trapezoids)
1213 ps->Trapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntrap, *traps);
1214 #endif
1215
1216 /* Draw trapezoids on back-end server */
1217 if (pDstPriv->pict) {
1218 XRenderPictFormat *pFormat;
1219
1220 pFormat = dmxFindFormat(dmxScreen, maskFormat);
1221 if (!pFormat) {
1222 /* FIXME: Error! */
1223 }
1224
1225 XRenderCompositeTrapezoids(dmxScreen->beDisplay,
1226 op,
1227 pSrcPriv->pict,
1228 pDstPriv->pict,
1229 pFormat,
1230 xSrc, ySrc, (XTrapezoid *) traps, ntrap);
1231 dmxSync(dmxScreen, FALSE);
1232 }
1233
1234 DMX_WRAP(Trapezoids, dmxTrapezoids, dmxScreen, ps);
1235 }
1236
1237 /** Composite a list of triangles on the appropriate screen. For a
1238 * complete description see the protocol document of the RENDER
1239 * library. */
1240 void
1241 dmxTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1242 PictFormatPtr maskFormat,
1243 INT16 xSrc, INT16 ySrc, int ntri, xTriangle * tris)
1244 {
1245 ScreenPtr pScreen = pDst->pDrawable->pScreen;
1246 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
1247 PictureScreenPtr ps = GetPictureScreen(pScreen);
1248 dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc);
1249 dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst);
1250
1251 DMX_UNWRAP(Triangles, dmxScreen, ps);
1252 #if 0
1253 if (ps->Triangles)
1254 ps->Triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, *tris);
1255 #endif
1256
1257 /* Draw trapezoids on back-end server */
1258 if (pDstPriv->pict) {
1259 XRenderPictFormat *pFormat;
1260
1261 pFormat = dmxFindFormat(dmxScreen, maskFormat);
1262 if (!pFormat) {
1263 /* FIXME: Error! */
1264 }
1265
1266 XRenderCompositeTriangles(dmxScreen->beDisplay,
1267 op,
1268 pSrcPriv->pict,
1269 pDstPriv->pict,
1270 pFormat,
1271 xSrc, ySrc, (XTriangle *) tris, ntri);
1272 dmxSync(dmxScreen, FALSE);
1273 }
1274
1275 DMX_WRAP(Triangles, dmxTriangles, dmxScreen, ps);
1276 }