tizen 2.4 release
[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     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((void **) &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((void **) &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((void **) &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((void **) &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((void **) &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((void **) &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((void **) &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((void **) &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((void **) &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, void *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 }