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