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