Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / dmx / dmxpict.c
CommitLineData
a09e091a
JB
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
60extern int RenderErrBase;
61extern int (*ProcRenderVector[RenderNumberRequests]) (ClientPtr);
62
63static int (*dmxSaveRenderVector[RenderNumberRequests]) (ClientPtr);
64
65static int dmxProcRenderCreateGlyphSet(ClientPtr client);
66static int dmxProcRenderFreeGlyphSet(ClientPtr client);
67static int dmxProcRenderAddGlyphs(ClientPtr client);
68static int dmxProcRenderFreeGlyphs(ClientPtr client);
69static int dmxProcRenderCompositeGlyphs(ClientPtr client);
70static int dmxProcRenderSetPictureTransform(ClientPtr client);
71static int dmxProcRenderSetPictureFilter(ClientPtr client);
72
73#if 0
74/* FIXME: Not (yet) supported */
75static int dmxProcRenderCreateCursor(ClientPtr client);
76static 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. */
81static int dmxGlyphLastError;
82static int
83dmxGlyphErrorHandler(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. */
95void
96dmxInitRender(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
127dmxResetRender(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. */
138Bool
139dmxPictureInit(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. */
176static XRenderPictFormat *
177dmxFindFormat(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. */
219Bool
220dmxBEFreeGlyphSet(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. */
236int
237dmxBECreateGlyphSet(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. */
270static int
271dmxProcRenderCreateGlyphSet(ClientPtr client)
272{
273 int ret;
274
275 REQUEST(xRenderCreateGlyphSetReq);
276
277 ret = dmxSaveRenderVector[stuff->renderReqType] (client);
278
279 if (ret == Success) {
280 GlyphSetPtr glyphSet;
281 dmxGlyphPrivPtr glyphPriv;
282 int i;
283
284 /* Look up glyphSet that was just created ???? */
285 /* Store glyphsets from backends in glyphSet->devPrivate ????? */
286 /* Make sure we handle all errors here!! */
287
288 dixLookupResourceByType((pointer *) &glyphSet,
289 stuff->gsid, GlyphSetType,
290 client, DixDestroyAccess);
291
292 glyphPriv = malloc(sizeof(dmxGlyphPrivRec));
293 if (!glyphPriv)
294 return BadAlloc;
295 glyphPriv->glyphSets = NULL;
296 MAXSCREENSALLOC_RETURN(glyphPriv->glyphSets, BadAlloc);
297 DMX_SET_GLYPH_PRIV(glyphSet, glyphPriv);
298
299 for (i = 0; i < dmxNumScreens; i++) {
300 DMXScreenInfo *dmxScreen = &dmxScreens[i];
301 int beret;
302
303 if (!dmxScreen->beDisplay) {
304 glyphPriv->glyphSets[i] = 0;
305 continue;
306 }
307
308 if ((beret = dmxBECreateGlyphSet(i, glyphSet)) != Success) {
309 int j;
310
311 /* Free the glyph sets we've allocated thus far */
312 for (j = 0; j < i; j++)
313 dmxBEFreeGlyphSet(screenInfo.screens[j], glyphSet);
314
315 /* Free the resource created by render */
316 FreeResource(stuff->gsid, RT_NONE);
317
318 return beret;
319 }
320 }
321 }
322
323 return ret;
324}
325
326/** Free the previously allocated Glyph Sets for each screen. */
327static int
328dmxProcRenderFreeGlyphSet(ClientPtr client)
329{
330 GlyphSetPtr glyphSet;
331
332 REQUEST(xRenderFreeGlyphSetReq);
333
334 REQUEST_SIZE_MATCH(xRenderFreeGlyphSetReq);
335 dixLookupResourceByType((pointer *) &glyphSet,
336 stuff->glyphset, GlyphSetType,
337 client, DixDestroyAccess);
338
339 if (glyphSet && glyphSet->refcnt == 1) {
340 dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
341 int i;
342
343 for (i = 0; i < dmxNumScreens; i++) {
344 DMXScreenInfo *dmxScreen = &dmxScreens[i];
345
346 if (dmxScreen->beDisplay) {
347 if (dmxBEFreeGlyphSet(screenInfo.screens[i], glyphSet))
348 dmxSync(dmxScreen, FALSE);
349 }
350 }
351
352 MAXSCREENSFREE(glyphPriv->glyphSets);
353 free(glyphPriv);
354 DMX_SET_GLYPH_PRIV(glyphSet, NULL);
355 }
356
357 return dmxSaveRenderVector[stuff->renderReqType] (client);
358}
359
360/** Add glyphs to the Glyph Set on each screen. */
361static int
362dmxProcRenderAddGlyphs(ClientPtr client)
363{
364 int ret;
365
366 REQUEST(xRenderAddGlyphsReq);
367
368 ret = dmxSaveRenderVector[stuff->renderReqType] (client);
369
370 if (ret == Success) {
371 GlyphSetPtr glyphSet;
372 dmxGlyphPrivPtr glyphPriv;
373 int i;
374 int nglyphs;
375 CARD32 *gids;
376 Glyph *gidsCopy;
377 xGlyphInfo *gi;
378 CARD8 *bits;
379 int nbytes;
380
381 dixLookupResourceByType((pointer *) &glyphSet,
382 stuff->glyphset, GlyphSetType,
383 client, DixReadAccess);
384 glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
385
386 nglyphs = stuff->nglyphs;
387 gids = (CARD32 *) (stuff + 1);
388 gi = (xGlyphInfo *) (gids + nglyphs);
389 bits = (CARD8 *) (gi + nglyphs);
390 nbytes = ((stuff->length << 2) -
391 sizeof(xRenderAddGlyphsReq) -
392 (sizeof(CARD32) + sizeof(xGlyphInfo)) * nglyphs);
393
394 gidsCopy = malloc(sizeof(*gidsCopy) * nglyphs);
395 for (i = 0; i < nglyphs; i++)
396 gidsCopy[i] = gids[i];
397
398 /* FIXME: Will this ever fail? */
399 for (i = 0; i < dmxNumScreens; i++) {
400 DMXScreenInfo *dmxScreen = &dmxScreens[i];
401
402 if (dmxScreen->beDisplay) {
403 XRenderAddGlyphs(dmxScreen->beDisplay,
404 glyphPriv->glyphSets[i],
405 gidsCopy,
406 (XGlyphInfo *) gi,
407 nglyphs, (char *) bits, nbytes);
408 dmxSync(dmxScreen, FALSE);
409 }
410 }
411 free(gidsCopy);
412 }
413
414 return ret;
415}
416
417/** Free glyphs from the Glyph Set for each screen. */
418static int
419dmxProcRenderFreeGlyphs(ClientPtr client)
420{
421 GlyphSetPtr glyphSet;
422
423 REQUEST(xRenderFreeGlyphsReq);
424
425 REQUEST_AT_LEAST_SIZE(xRenderFreeGlyphsReq);
426 dixLookupResourceByType((pointer *) &glyphSet,
427 stuff->glyphset, GlyphSetType,
428 client, DixWriteAccess);
429
430 if (glyphSet) {
431 dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
432 int i;
433 int nglyphs;
434 Glyph *gids;
435
436 nglyphs = ((client->req_len << 2) - sizeof(xRenderFreeGlyphsReq)) >> 2;
437 if (nglyphs) {
438 gids = malloc(sizeof(*gids) * nglyphs);
439 for (i = 0; i < nglyphs; i++)
440 gids[i] = ((CARD32 *) (stuff + 1))[i];
441
442 for (i = 0; i < dmxNumScreens; i++) {
443 DMXScreenInfo *dmxScreen = &dmxScreens[i];
444
445 if (dmxScreen->beDisplay) {
446 XRenderFreeGlyphs(dmxScreen->beDisplay,
447 glyphPriv->glyphSets[i], gids, nglyphs);
448 dmxSync(dmxScreen, FALSE);
449 }
450 }
451 free(gids);
452 }
453 }
454
455 return dmxSaveRenderVector[stuff->renderReqType] (client);
456}
457
458/** Composite glyphs on each screen into the requested picture. If
459 * either the src or dest picture has not been allocated due to lazy
460 * window creation, this request will gracefully return. */
461static int
462dmxProcRenderCompositeGlyphs(ClientPtr client)
463{
464 int ret;
465
466 REQUEST(xRenderCompositeGlyphsReq);
467
468 ret = dmxSaveRenderVector[stuff->renderReqType] (client);
469
470 /* For the following to work with PanoramiX, it assumes that Render
471 * wraps the ProcRenderVector after dmxRenderInit has been called.
472 */
473 if (ret == Success) {
474 PicturePtr pSrc;
475 dmxPictPrivPtr pSrcPriv;
476 PicturePtr pDst;
477 dmxPictPrivPtr pDstPriv;
478 PictFormatPtr pFmt;
479 XRenderPictFormat *pFormat;
480 int size;
481
482 int scrnNum;
483 DMXScreenInfo *dmxScreen;
484
485 CARD8 *buffer;
486 CARD8 *end;
487 int space;
488
489 int nglyph;
490 char *glyphs;
491 char *curGlyph;
492
493 xGlyphElt *elt;
494 int nelt;
495 XGlyphElt8 *elts;
496 XGlyphElt8 *curElt;
497
498 GlyphSetPtr glyphSet;
499 dmxGlyphPrivPtr glyphPriv;
500
501 dixLookupResourceByType((pointer *) &pSrc,
502 stuff->src, PictureType, client, DixReadAccess);
503
504 pSrcPriv = DMX_GET_PICT_PRIV(pSrc);
505 if (!pSrcPriv->pict)
506 return ret;
507
508 dixLookupResourceByType((pointer *) &pDst,
509 stuff->dst, PictureType,
510 client, DixWriteAccess);
511
512 pDstPriv = DMX_GET_PICT_PRIV(pDst);
513 if (!pDstPriv->pict)
514 return ret;
515
516 scrnNum = pDst->pDrawable->pScreen->myNum;
517 dmxScreen = &dmxScreens[scrnNum];
518
519 /* Note: If the back-end display has been detached, then it
520 * should not be possible to reach here since the pSrcPriv->pict
521 * and pDstPriv->pict will have already been set to 0.
522 */
523 if (!dmxScreen->beDisplay)
524 return ret;
525
526 if (stuff->maskFormat)
527 dixLookupResourceByType((pointer *) &pFmt,
528 stuff->maskFormat, PictFormatType,
529 client, DixReadAccess);
530 else
531 pFmt = NULL;
532
533 pFormat = dmxFindFormat(dmxScreen, pFmt);
534
535 switch (stuff->renderReqType) {
536 case X_RenderCompositeGlyphs8:
537 size = sizeof(CARD8);
538 break;
539 case X_RenderCompositeGlyphs16:
540 size = sizeof(CARD16);
541 break;
542 case X_RenderCompositeGlyphs32:
543 size = sizeof(CARD32);
544 break;
545 default:
546 return BadPictOp; /* Can't happen */
547 }
548
549 buffer = (CARD8 *) (stuff + 1);
550 end = (CARD8 *) stuff + (stuff->length << 2);
551 nelt = 0;
552 nglyph = 0;
553 while (buffer + sizeof(xGlyphElt) < end) {
554 elt = (xGlyphElt *) buffer;
555 buffer += sizeof(xGlyphElt);
556
557 if (elt->len == 0xff) {
558 buffer += 4;
559 }
560 else {
561 nelt++;
562 nglyph += elt->len;
563 space = size * elt->len;
564 if (space & 3)
565 space += 4 - (space & 3);
566 buffer += space;
567 }
568 }
569
570 /* The following only works for Render version > 0.2 */
571
572 /* All of the XGlyphElt* structure sizes are identical */
573 elts = malloc(nelt * sizeof(XGlyphElt8));
574 if (!elts)
575 return BadAlloc;
576
577 glyphs = malloc(nglyph * size);
578 if (!glyphs) {
579 free(elts);
580 return BadAlloc;
581 }
582
583 buffer = (CARD8 *) (stuff + 1);
584 end = (CARD8 *) stuff + (stuff->length << 2);
585 curGlyph = glyphs;
586 curElt = elts;
587
588 dixLookupResourceByType((pointer *) &glyphSet,
589 stuff->glyphset, GlyphSetType,
590 client, DixReadAccess);
591 glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
592
593 while (buffer + sizeof(xGlyphElt) < end) {
594 elt = (xGlyphElt *) buffer;
595 buffer += sizeof(xGlyphElt);
596
597 if (elt->len == 0xff) {
598 dixLookupResourceByType((pointer *) &glyphSet,
599 *((CARD32 *) buffer),
600 GlyphSetType, client, DixReadAccess);
601 glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
602 buffer += 4;
603 }
604 else {
605 curElt->glyphset = glyphPriv->glyphSets[scrnNum];
606 curElt->xOff = elt->deltax;
607 curElt->yOff = elt->deltay;
608 curElt->nchars = elt->len;
609 curElt->chars = curGlyph;
610
611 memcpy(curGlyph, buffer, size * elt->len);
612 curGlyph += size * elt->len;
613
614 curElt++;
615
616 space = size * elt->len;
617 if (space & 3)
618 space += 4 - (space & 3);
619 buffer += space;
620 }
621 }
622
623 switch (stuff->renderReqType) {
624 case X_RenderCompositeGlyphs8:
625 XRenderCompositeText8(dmxScreen->beDisplay, stuff->op,
626 pSrcPriv->pict, pDstPriv->pict,
627 pFormat,
628 stuff->xSrc, stuff->ySrc, 0, 0, elts, nelt);
629 break;
630 case X_RenderCompositeGlyphs16:
631 XRenderCompositeText16(dmxScreen->beDisplay, stuff->op,
632 pSrcPriv->pict, pDstPriv->pict,
633 pFormat,
634 stuff->xSrc, stuff->ySrc,
635 0, 0, (XGlyphElt16 *) elts, nelt);
636 break;
637 case X_RenderCompositeGlyphs32:
638 XRenderCompositeText32(dmxScreen->beDisplay, stuff->op,
639 pSrcPriv->pict, pDstPriv->pict,
640 pFormat,
641 stuff->xSrc, stuff->ySrc,
642 0, 0, (XGlyphElt32 *) elts, nelt);
643 break;
644 }
645
646 dmxSync(dmxScreen, FALSE);
647
648 free(elts);
649 free(glyphs);
650 }
651
652 return ret;
653}
654
655/** Set the picture transform on each screen. */
656static int
657dmxProcRenderSetPictureTransform(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. */
695static int
696dmxProcRenderSetPictureFilter(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. */
733static Picture
734dmxDoCreatePicture(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. */
779void
780dmxCreatePictureList(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. */
797int
798dmxBECreatePicture(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. */
814int
815dmxCreatePicture(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. */
839Bool
840dmxBEFreePicture(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 * */
858Bool
859dmxDestroyPictureList(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. */
875void
876dmxDestroyPicture(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. */
896int
897dmxChangePictureClip(PicturePtr pPicture, int clipType, pointer value, int n)
898{
899 ScreenPtr pScreen = pPicture->pDrawable->pScreen;
900 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
901 PictureScreenPtr ps = GetPictureScreen(pScreen);
902 dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture);
903
904 DMX_UNWRAP(ChangePictureClip, dmxScreen, ps);
905#if 1
906 if (ps->ChangePictureClip)
907 ps->ChangePictureClip(pPicture, clipType, value, n);
908#endif
909
910 /* Change picture clip rects on back-end server */
911 if (pPictPriv->pict) {
912 /* The clip has already been changed into a region by the mi
913 * routine called above.
914 */
915 if (clipType == CT_NONE) {
916 /* Disable clipping, show all */
917 XFixesSetPictureClipRegion(dmxScreen->beDisplay,
918 pPictPriv->pict, 0, 0, None);
919 }
920 else if (pPicture->clientClip) {
921 RegionPtr pClip = pPicture->clientClip;
922 BoxPtr pBox = RegionRects(pClip);
923 int nBox = RegionNumRects(pClip);
924 XRectangle *pRects;
925 XRectangle *pRect;
926 int nRects;
927
928 nRects = nBox;
929 pRects = pRect = malloc(nRects * sizeof(*pRect));
930
931 while (nBox--) {
932 pRect->x = pBox->x1;
933 pRect->y = pBox->y1;
934 pRect->width = pBox->x2 - pBox->x1;
935 pRect->height = pBox->y2 - pBox->y1;
936 pBox++;
937 pRect++;
938 }
939
940 XRenderSetPictureClipRectangles(dmxScreen->beDisplay,
941 pPictPriv->pict,
942 0, 0, pRects, nRects);
943 free(pRects);
944 }
945 else {
946 XRenderSetPictureClipRectangles(dmxScreen->beDisplay,
947 pPictPriv->pict, 0, 0, NULL, 0);
948 }
949 dmxSync(dmxScreen, FALSE);
950 }
951 else {
952 /* FIXME: Handle saving clip region when offscreen */
953 }
954
955 DMX_WRAP(ChangePictureClip, dmxChangePictureClip, dmxScreen, ps);
956
957 return Success;
958}
959
960/** Destroy the picture's list of clip rectangles. */
961void
962dmxDestroyPictureClip(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. */
992void
993dmxChangePicture(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. */
1015void
1016dmxValidatePicture(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. */
1091void
1092dmxComposite(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. */
1133void
1134dmxGlyphs(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. */
1147void
1148dmxCompositeRects(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. */
1177Bool
1178dmxInitIndexed(ScreenPtr pScreen, PictFormatPtr pFormat)
1179{
1180 return TRUE;
1181}
1182
1183/** Indexed color visuals are not yet supported. */
1184void
1185dmxCloseIndexed(ScreenPtr pScreen, PictFormatPtr pFormat)
1186{
1187}
1188
1189/** Indexed color visuals are not yet supported. */
1190void
1191dmxUpdateIndexed(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. */
1199void
1200dmxTrapezoids(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. */
1240void
1241dmxTriangles(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}