dmxpict.c revision 48a68b89
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        if (nparams < 0)
690            return BadLength;
691
692	XRenderSetPictureFilter(dmxScreen->beDisplay,
693				pPictPriv->pict,
694				filter,
695				params,
696				nparams);
697	dmxSync(dmxScreen, FALSE);
698    }
699
700    return dmxSaveRenderVector[stuff->renderReqType](client);
701}
702
703
704/** Create a picture on the appropriate screen.  This is the actual
705 *  function that creates the picture.  However, if the associated
706 *  window has not yet been created due to lazy window creation, then
707 *  delay the picture creation until the window is mapped. */
708static Picture dmxDoCreatePicture(PicturePtr pPicture)
709{
710    DrawablePtr               pDraw     = pPicture->pDrawable;
711    ScreenPtr                 pScreen   = pDraw->pScreen;
712    DMXScreenInfo            *dmxScreen = &dmxScreens[pScreen->myNum];
713    XRenderPictFormat        *pFormat;
714    Drawable                  draw;
715
716    if (pPicture->pDrawable->type == DRAWABLE_WINDOW) {
717	dmxWinPrivPtr  pWinPriv = DMX_GET_WINDOW_PRIV((WindowPtr)(pDraw));
718
719	if (!(draw = pWinPriv->window)) {
720	    /* Window has not been created yet due to the window
721	     * optimization.  Delay picture creation until window is
722	     * mapped.
723	     */
724	    pWinPriv->hasPict = TRUE;
725	    return 0;
726	}
727    } else {
728	dmxPixPrivPtr  pPixPriv = DMX_GET_PIXMAP_PRIV((PixmapPtr)(pDraw));
729
730	if (!(draw = pPixPriv->pixmap)) {
731	    /* FIXME: Zero width/height pixmap?? */
732	    return 0;
733	}
734    }
735
736    /* This should not be reached if the back-end display has been
737     * detached because the pWinPriv->window or the pPixPriv->pixmap
738     * will be NULL; however, we add it here for completeness
739     */
740    if (!dmxScreen->beDisplay)
741	return 0;
742
743    pFormat = dmxFindFormat(dmxScreen, pPicture->pFormat);
744
745    return XRenderCreatePicture(dmxScreen->beDisplay, draw, pFormat, 0, 0);
746}
747
748/** Create a list of pictures.  This function is called by
749 *  dmxCreateAndRealizeWindow() during the lazy window creation
750 *  realization process.  It creates the entire list of pictures that
751 *  are associated with the given window. */
752void dmxCreatePictureList(WindowPtr pWindow)
753{
754    PicturePtr  pPicture = GetPictureWindow(pWindow);
755
756    while (pPicture) {
757	dmxPictPrivPtr  pPictPriv = DMX_GET_PICT_PRIV(pPicture);
758
759	/* Create the picture for this window */
760	pPictPriv->pict = dmxDoCreatePicture(pPicture);
761
762	/* ValidatePicture takes care of the state changes */
763
764	pPicture = pPicture->pNext;
765    }
766}
767
768/** Create \a pPicture on the backend. */
769int dmxBECreatePicture(PicturePtr pPicture)
770{
771    dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pPicture);
772
773    /* Create picutre on BE */
774    pPictPriv->pict = dmxDoCreatePicture(pPicture);
775
776    /* Flush changes to the backend server */
777    dmxValidatePicture(pPicture, (1 << (CPLastBit+1)) - 1);
778
779    return Success;
780}
781
782/** Create a picture.  This function handles the CreatePicture
783 *  unwrapping/wrapping and calls dmxDoCreatePicture to actually create
784 *  the picture on the appropriate screen.  */
785int dmxCreatePicture(PicturePtr pPicture)
786{
787    ScreenPtr         pScreen   = pPicture->pDrawable->pScreen;
788    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
789    PictureScreenPtr  ps        = GetPictureScreen(pScreen);
790    dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pPicture);
791    int               ret       = Success;
792
793    DMX_UNWRAP(CreatePicture, dmxScreen, ps);
794#if 1
795    if (ps->CreatePicture)
796	ret = ps->CreatePicture(pPicture);
797#endif
798
799    /* Create picture on back-end server */
800    pPictPriv->pict      = dmxDoCreatePicture(pPicture);
801    pPictPriv->savedMask = 0;
802
803    DMX_WRAP(CreatePicture, dmxCreatePicture, dmxScreen, ps);
804
805    return ret;
806}
807
808/** Destroy \a pPicture on the back-end server. */
809Bool dmxBEFreePicture(PicturePtr pPicture)
810{
811    ScreenPtr      pScreen   = pPicture->pDrawable->pScreen;
812    DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
813    dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture);
814
815    if (pPictPriv->pict) {
816	XRenderFreePicture(dmxScreen->beDisplay, pPictPriv->pict);
817	pPictPriv->pict = (Picture)0;
818	return TRUE;
819    }
820
821    return FALSE;
822}
823
824/** Destroy a list of pictures that are associated with the window that
825 *  is being destroyed.  This function is called by #dmxDestroyWindow().
826 *  */
827Bool dmxDestroyPictureList(WindowPtr pWindow)
828{
829    PicturePtr  pPicture = GetPictureWindow(pWindow);
830    Bool        ret      = FALSE;
831
832    while (pPicture) {
833	ret |= dmxBEFreePicture(pPicture);
834	pPicture = pPicture->pNext;
835    }
836
837    return ret;
838}
839
840/** Destroy a picture.  This function calls the wrapped function that
841 *  frees the resources in the DMX server associated with this
842 *  picture. */
843void dmxDestroyPicture(PicturePtr pPicture)
844{
845    ScreenPtr         pScreen   = pPicture->pDrawable->pScreen;
846    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
847    PictureScreenPtr  ps        = GetPictureScreen(pScreen);
848
849    DMX_UNWRAP(DestroyPicture, dmxScreen, ps);
850
851    /* Destroy picture on back-end server */
852    if (dmxBEFreePicture(pPicture))
853	dmxSync(dmxScreen, FALSE);
854
855#if 1
856    if (ps->DestroyPicture)
857	ps->DestroyPicture(pPicture);
858#endif
859    DMX_WRAP(DestroyPicture, dmxDestroyPicture, dmxScreen, ps);
860}
861
862/** Change the picture's list of clip rectangles. */
863int dmxChangePictureClip(PicturePtr pPicture, int clipType,
864			 pointer value, int n)
865{
866    ScreenPtr         pScreen   = pPicture->pDrawable->pScreen;
867    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
868    PictureScreenPtr  ps        = GetPictureScreen(pScreen);
869    dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pPicture);
870
871    DMX_UNWRAP(ChangePictureClip, dmxScreen, ps);
872#if 1
873    if (ps->ChangePictureClip)
874	ps->ChangePictureClip(pPicture, clipType, value, n);
875#endif
876
877    /* Change picture clip rects on back-end server */
878    if (pPictPriv->pict) {
879	/* The clip has already been changed into a region by the mi
880	 * routine called above.
881	 */
882	if (clipType == CT_NONE) {
883	    /* Disable clipping, show all */
884	    XFixesSetPictureClipRegion(dmxScreen->beDisplay,
885				       pPictPriv->pict, 0, 0, None);
886	} else if (pPicture->clientClip) {
887	    RegionPtr   pClip = pPicture->clientClip;
888	    BoxPtr      pBox  = RegionRects(pClip);
889	    int         nBox  = RegionNumRects(pClip);
890	    XRectangle *pRects;
891	    XRectangle *pRect;
892	    int         nRects;
893
894	    nRects = nBox;
895	    pRects = pRect = malloc(nRects * sizeof(*pRect));
896
897	    while (nBox--) {
898		pRect->x      = pBox->x1;
899		pRect->y      = pBox->y1;
900		pRect->width  = pBox->x2 - pBox->x1;
901		pRect->height = pBox->y2 - pBox->y1;
902		pBox++;
903		pRect++;
904	    }
905
906	    XRenderSetPictureClipRectangles(dmxScreen->beDisplay,
907					    pPictPriv->pict,
908					    0, 0,
909					    pRects,
910					    nRects);
911	    free(pRects);
912	} else {
913	    XRenderSetPictureClipRectangles(dmxScreen->beDisplay,
914					    pPictPriv->pict,
915					    0, 0, NULL, 0);
916	}
917	dmxSync(dmxScreen, FALSE);
918    } else {
919	/* FIXME: Handle saving clip region when offscreen */
920    }
921
922    DMX_WRAP(ChangePictureClip, dmxChangePictureClip, dmxScreen, ps);
923
924    return Success;
925}
926
927/** Destroy the picture's list of clip rectangles. */
928void dmxDestroyPictureClip(PicturePtr pPicture)
929{
930    ScreenPtr         pScreen   = pPicture->pDrawable->pScreen;
931    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
932    PictureScreenPtr  ps        = GetPictureScreen(pScreen);
933    dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pPicture);
934
935    DMX_UNWRAP(DestroyPictureClip, dmxScreen, ps);
936#if 1
937    if (ps->DestroyPictureClip)
938	ps->DestroyPictureClip(pPicture);
939#endif
940
941    /* Destroy picture clip rects on back-end server */
942    if (pPictPriv->pict) {
943	XRenderSetPictureClipRectangles(dmxScreen->beDisplay,
944					pPictPriv->pict,
945					0, 0, NULL, 0);
946	dmxSync(dmxScreen, FALSE);
947    } else {
948	/* FIXME: Handle destroying clip region when offscreen */
949    }
950
951    DMX_WRAP(DestroyPictureClip, dmxDestroyPictureClip, dmxScreen, ps);
952}
953
954/** Change the attributes of the pictures.  If the picture has not yet
955 *  been created due to lazy window creation, save the mask so that it
956 *  can be used to appropriately initialize the picture's attributes
957 *  when it is created later. */
958void dmxChangePicture(PicturePtr pPicture, Mask mask)
959{
960    ScreenPtr         pScreen   = pPicture->pDrawable->pScreen;
961    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
962    PictureScreenPtr  ps        = GetPictureScreen(pScreen);
963    dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pPicture);
964
965    DMX_UNWRAP(ChangePicture, dmxScreen, ps);
966#if 1
967    if (ps->ChangePicture)
968	ps->ChangePicture(pPicture, mask);
969#endif
970
971    /* Picture attribute changes are handled in ValidatePicture */
972    pPictPriv->savedMask |= mask;
973
974    DMX_WRAP(ChangePicture, dmxChangePicture, dmxScreen, ps);
975}
976
977/** Validate the picture's attributes before rendering to it.  Update
978 *  any picture attributes that have been changed by one of the higher
979 *  layers. */
980void dmxValidatePicture(PicturePtr pPicture, Mask mask)
981{
982    ScreenPtr         pScreen   = pPicture->pDrawable->pScreen;
983    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
984    PictureScreenPtr  ps        = GetPictureScreen(pScreen);
985    dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pPicture);
986
987    DMX_UNWRAP(ValidatePicture, dmxScreen, ps);
988
989    /* Change picture attributes on back-end server */
990    if (pPictPriv->pict) {
991	XRenderPictureAttributes  attribs;
992
993	if (mask & CPRepeat) {
994	    attribs.repeat = pPicture->repeatType;
995	}
996	if (mask & CPAlphaMap) {
997	    if (pPicture->alphaMap) {
998		dmxPictPrivPtr  pAlphaPriv;
999		pAlphaPriv = DMX_GET_PICT_PRIV(pPicture->alphaMap);
1000		if (pAlphaPriv->pict) {
1001		    attribs.alpha_map = pAlphaPriv->pict;
1002		} else {
1003		    /* FIXME: alpha picture drawable has not been created?? */
1004		    return; /* or should this be: attribs.alpha_map = None; */
1005		}
1006	    } else {
1007		attribs.alpha_map = None;
1008	    }
1009	}
1010	if (mask & CPAlphaXOrigin)
1011	    attribs.alpha_x_origin = pPicture->alphaOrigin.x;
1012	if (mask & CPAlphaYOrigin)
1013	    attribs.alpha_y_origin = pPicture->alphaOrigin.y;
1014	if (mask & CPClipXOrigin)
1015	    attribs.clip_x_origin = pPicture->clipOrigin.x;
1016	if (mask & CPClipYOrigin)
1017	    attribs.clip_y_origin = pPicture->clipOrigin.y;
1018	if (mask & CPClipMask)
1019	    mask &= ~CPClipMask; /* Handled in ChangePictureClip */
1020	if (mask & CPGraphicsExposure)
1021	    attribs.graphics_exposures = pPicture->graphicsExposures;
1022	if (mask & CPSubwindowMode)
1023	    attribs.subwindow_mode = pPicture->subWindowMode;
1024	if (mask & CPPolyEdge)
1025	    attribs.poly_edge = pPicture->polyEdge;
1026	if (mask & CPPolyMode)
1027	    attribs.poly_mode = pPicture->polyMode;
1028	if (mask & CPComponentAlpha)
1029	    attribs.component_alpha = pPicture->componentAlpha;
1030
1031	XRenderChangePicture(dmxScreen->beDisplay, pPictPriv->pict,
1032			     mask, &attribs);
1033	dmxSync(dmxScreen, FALSE);
1034    } else {
1035	pPictPriv->savedMask |= mask;
1036    }
1037
1038#if 1
1039    if (ps->ValidatePicture)
1040	ps->ValidatePicture(pPicture, mask);
1041#endif
1042
1043    DMX_WRAP(ValidatePicture, dmxValidatePicture, dmxScreen, ps);
1044}
1045
1046/** Composite a picture on the appropriate screen by combining the
1047 *  specified rectangle of the transformed src and mask operands with
1048 *  the specified rectangle of the dst using op as the compositing
1049 *  operator.  For a complete description see the protocol document of
1050 *  the RENDER library. */
1051void dmxComposite(CARD8 op,
1052		  PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
1053		  INT16 xSrc, INT16 ySrc,
1054		  INT16 xMask, INT16 yMask,
1055		  INT16 xDst, INT16 yDst,
1056		  CARD16 width, CARD16 height)
1057{
1058    ScreenPtr         pScreen   = pDst->pDrawable->pScreen;
1059    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
1060    PictureScreenPtr  ps        = GetPictureScreen(pScreen);
1061    dmxPictPrivPtr    pSrcPriv  = DMX_GET_PICT_PRIV(pSrc);
1062    dmxPictPrivPtr    pMaskPriv = NULL;
1063    dmxPictPrivPtr    pDstPriv  = DMX_GET_PICT_PRIV(pDst);
1064
1065    if (pMask) pMaskPriv = DMX_GET_PICT_PRIV(pMask);
1066
1067    DMX_UNWRAP(Composite, dmxScreen, ps);
1068#if 0
1069    if (ps->Composite)
1070	ps->Composite(op, pSrc, pMask, pDst,
1071		      xSrc, ySrc, xMask, yMask, xDst, yDst,
1072		      width, height);
1073#endif
1074
1075    /* Composite on back-end server */
1076    if (pSrcPriv->pict && pDstPriv->pict &&
1077	((pMaskPriv && pMaskPriv->pict) || !pMaskPriv)) {
1078	XRenderComposite(dmxScreen->beDisplay,
1079			 op,
1080			 pSrcPriv->pict,
1081			 pMaskPriv ? pMaskPriv->pict : None,
1082			 pDstPriv->pict,
1083			 xSrc, ySrc,
1084			 xMask, yMask,
1085			 xDst, yDst,
1086			 width, height);
1087	dmxSync(dmxScreen, FALSE);
1088    }
1089
1090
1091    DMX_WRAP(Composite, dmxComposite, dmxScreen, ps);
1092}
1093
1094/** Null function to catch when/if RENDER calls lower level mi hooks.
1095 *  Compositing glyphs is handled by dmxProcRenderCompositeGlyphs().
1096 *  This function should never be called. */
1097void dmxGlyphs(CARD8 op,
1098	       PicturePtr pSrc, PicturePtr pDst,
1099	       PictFormatPtr maskFormat,
1100	       INT16 xSrc, INT16 ySrc,
1101	       int nlists, GlyphListPtr lists, GlyphPtr *glyphs)
1102{
1103    /* This won't work, so we need to wrap ProcRenderCompositeGlyphs */
1104}
1105
1106/** Fill a rectangle on the appropriate screen by combining the color
1107 *  with the dest picture in the area specified by the list of
1108 *  rectangles.  For a complete description see the protocol document of
1109 *  the RENDER library. */
1110void dmxCompositeRects(CARD8 op,
1111		       PicturePtr pDst,
1112		       xRenderColor *color,
1113		       int nRect, xRectangle *rects)
1114{
1115    ScreenPtr         pScreen   = pDst->pDrawable->pScreen;
1116    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
1117    PictureScreenPtr  ps        = GetPictureScreen(pScreen);
1118    dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pDst);
1119
1120    DMX_UNWRAP(CompositeRects, dmxScreen, ps);
1121#if 0
1122    if (ps->CompositeRects)
1123	ps->CompositeRects(op, pDst, color, nRect, rects);
1124#endif
1125
1126    /* CompositeRects on back-end server */
1127    if (pPictPriv->pict) {
1128	XRenderFillRectangles(dmxScreen->beDisplay,
1129			      op,
1130			      pPictPriv->pict,
1131			      (XRenderColor *)color,
1132			      (XRectangle *)rects,
1133			      nRect);
1134	dmxSync(dmxScreen, FALSE);
1135    }
1136
1137    DMX_WRAP(CompositeRects, dmxCompositeRects, dmxScreen, ps);
1138}
1139
1140/** Indexed color visuals are not yet supported. */
1141Bool dmxInitIndexed(ScreenPtr pScreen, PictFormatPtr pFormat)
1142{
1143    return TRUE;
1144}
1145
1146/** Indexed color visuals are not yet supported. */
1147void dmxCloseIndexed(ScreenPtr pScreen, PictFormatPtr pFormat)
1148{
1149}
1150
1151/** Indexed color visuals are not yet supported. */
1152void dmxUpdateIndexed(ScreenPtr pScreen, PictFormatPtr pFormat,
1153		      int ndef, xColorItem *pdef)
1154{
1155}
1156
1157/** Composite a list of trapezoids on the appropriate screen.  For a
1158 *  complete description see the protocol document of the RENDER
1159 *  library. */
1160void dmxTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1161		   PictFormatPtr maskFormat,
1162		   INT16 xSrc, INT16 ySrc,
1163		   int ntrap, xTrapezoid *traps)
1164{
1165    ScreenPtr         pScreen   = pDst->pDrawable->pScreen;
1166    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
1167    PictureScreenPtr  ps        = GetPictureScreen(pScreen);
1168    dmxPictPrivPtr    pSrcPriv  = DMX_GET_PICT_PRIV(pSrc);
1169    dmxPictPrivPtr    pDstPriv  = DMX_GET_PICT_PRIV(pDst);
1170
1171    DMX_UNWRAP(Trapezoids, dmxScreen, ps);
1172#if 0
1173    if (ps->Trapezoids)
1174	ps->Trapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntrap, *traps);
1175#endif
1176
1177    /* Draw trapezoids on back-end server */
1178    if (pDstPriv->pict) {
1179	XRenderPictFormat *pFormat;
1180
1181	pFormat = dmxFindFormat(dmxScreen, maskFormat);
1182	if (!pFormat) {
1183	    /* FIXME: Error! */
1184	}
1185
1186	XRenderCompositeTrapezoids(dmxScreen->beDisplay,
1187				   op,
1188				   pSrcPriv->pict,
1189				   pDstPriv->pict,
1190				   pFormat,
1191				   xSrc, ySrc,
1192				   (XTrapezoid *)traps,
1193				   ntrap);
1194	dmxSync(dmxScreen, FALSE);
1195    }
1196
1197    DMX_WRAP(Trapezoids, dmxTrapezoids, dmxScreen, ps);
1198}
1199
1200/** Composite a list of triangles on the appropriate screen.  For a
1201 *  complete description see the protocol document of the RENDER
1202 *  library. */
1203void dmxTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1204		  PictFormatPtr maskFormat,
1205		  INT16 xSrc, INT16 ySrc,
1206		  int ntri, xTriangle *tris)
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(Triangles, dmxScreen, ps);
1215#if 0
1216    if (ps->Triangles)
1217	ps->Triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, *tris);
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	XRenderCompositeTriangles(dmxScreen->beDisplay,
1230				  op,
1231				  pSrcPriv->pict,
1232				  pDstPriv->pict,
1233				  pFormat,
1234				  xSrc, ySrc,
1235				  (XTriangle *)tris,
1236				  ntri);
1237	dmxSync(dmxScreen, FALSE);
1238    }
1239
1240    DMX_WRAP(Triangles, dmxTriangles, dmxScreen, ps);
1241}
1242
1243/** Composite a triangle strip on the appropriate screen.  For a
1244 *  complete description see the protocol document of the RENDER
1245 *  library. */
1246void dmxTriStrip(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1247		 PictFormatPtr maskFormat,
1248		 INT16 xSrc, INT16 ySrc,
1249		 int npoint, xPointFixed *points)
1250{
1251    ScreenPtr         pScreen   = pDst->pDrawable->pScreen;
1252    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
1253    PictureScreenPtr  ps        = GetPictureScreen(pScreen);
1254    dmxPictPrivPtr    pSrcPriv  = DMX_GET_PICT_PRIV(pSrc);
1255    dmxPictPrivPtr    pDstPriv  = DMX_GET_PICT_PRIV(pDst);
1256
1257    DMX_UNWRAP(TriStrip, dmxScreen, ps);
1258#if 0
1259    if (ps->TriStrip)
1260	ps->TriStrip(op, pSrc, pDst, maskFormat, xSrc, ySrc, npoint, *points);
1261#endif
1262
1263    /* Draw trapezoids on back-end server */
1264    if (pDstPriv->pict) {
1265	XRenderPictFormat *pFormat;
1266
1267	pFormat = dmxFindFormat(dmxScreen, maskFormat);
1268	if (!pFormat) {
1269	    /* FIXME: Error! */
1270	}
1271
1272	XRenderCompositeTriStrip(dmxScreen->beDisplay,
1273				 op,
1274				 pSrcPriv->pict,
1275				 pDstPriv->pict,
1276				 pFormat,
1277				 xSrc, ySrc,
1278				 (XPointFixed *)points,
1279				 npoint);
1280	dmxSync(dmxScreen, FALSE);
1281    }
1282
1283    DMX_WRAP(TriStrip, dmxTriStrip, dmxScreen, ps);
1284}
1285
1286/** Composite a triangle fan on the appropriate screen.  For a complete
1287 *  description see the protocol document of the RENDER library. */
1288void dmxTriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1289	       PictFormatPtr maskFormat,
1290	       INT16 xSrc, INT16 ySrc,
1291	       int npoint, xPointFixed *points)
1292{
1293    ScreenPtr         pScreen   = pDst->pDrawable->pScreen;
1294    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
1295    PictureScreenPtr  ps        = GetPictureScreen(pScreen);
1296    dmxPictPrivPtr    pSrcPriv  = DMX_GET_PICT_PRIV(pSrc);
1297    dmxPictPrivPtr    pDstPriv  = DMX_GET_PICT_PRIV(pDst);
1298
1299    DMX_UNWRAP(TriFan, dmxScreen, ps);
1300#if 0
1301    if (ps->TriFan)
1302	ps->TriFan(op, pSrc, pDst, maskFormat, xSrc, ySrc, npoint, *points);
1303#endif
1304
1305    /* Draw trapezoids on back-end server */
1306    if (pDstPriv->pict) {
1307	XRenderPictFormat *pFormat;
1308
1309	pFormat = dmxFindFormat(dmxScreen, maskFormat);
1310	if (!pFormat) {
1311	    /* FIXME: Error! */
1312	}
1313
1314	XRenderCompositeTriFan(dmxScreen->beDisplay,
1315			       op,
1316			       pSrcPriv->pict,
1317			       pDstPriv->pict,
1318			       pFormat,
1319			       xSrc, ySrc,
1320			       (XPointFixed *)points,
1321			       npoint);
1322	dmxSync(dmxScreen, FALSE);
1323    }
1324
1325    DMX_WRAP(TriFan, dmxTriFan, dmxScreen, ps);
1326}
1327