do_blt.c revision 533545b5
1/*****************************************************************************
2Copyright 1988, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
3
4                        All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of Digital not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22******************************************************************************/
23
24#include "x11perf.h"
25#include <stdio.h>
26
27#define NUMPOINTS 100
28
29static Pixmap   pix;
30static XImage   *image;
31static XPoint   points[NUMPOINTS];
32static XSegment *segsa, *segsb;
33static XSegment *segsa2, *segsb2;
34
35#define NegMod(x, y) ((y) - (((-x)-1) % (7)) - 1)
36
37static void
38InitBltLines(void)
39{
40    int i, x, y;
41
42    points[0].x = points[0].y = y = 0;
43    for (i = 1; i != NUMPOINTS/2; i++) {
44	if (i & 1) {
45	    points[i].x = WIDTH-1;
46	} else {
47	    points[i].x = 0;
48	}
49	y += HEIGHT / (NUMPOINTS/2);
50	points[i].y = y;
51    }
52
53    x = 0;
54    for (i = NUMPOINTS/2; i!= NUMPOINTS; i++) {
55	if (i & 1) {
56	    points[i].y = HEIGHT-1;
57	} else {
58	    points[i].y = 0;
59	}
60	x += WIDTH / (NUMPOINTS/2);
61	points[i].x = x;
62    }
63}
64
65int
66InitScroll(XParms xp, Parms p, int64_t reps)
67{
68    InitBltLines();
69    XDrawLines(xp->d, xp->w, xp->fggc, points, NUMPOINTS, CoordModeOrigin);
70    return reps;
71}
72
73void
74DoScroll(XParms xp, Parms p, int64_t reps)
75{
76    int i, size, x, y, xorg, yorg, delta;
77
78    size = p->special;
79    xorg = 0;   yorg = 0;
80    x    = 0;   y    = 0;
81    if (xp->version == VERSION1_2) {
82	delta = 1;
83    } else {
84	/* Version 1.2 only scrolled up by 1 scanline, which made hardware
85	   using page-mode access to VRAM look better on paper than it would
86	   perform in a more realistic scroll.  So we've changed to scroll by
87	   the height of the 6x13 fonts. */
88	delta = 13;
89    }
90
91    for (i = 0; i != reps; i++) {
92	XCopyArea(xp->d, xp->w, xp->w, xp->fggc, x, y + delta,
93	    size, size, x, y);
94	y += size;
95	if (y + size + delta > HEIGHT) {
96	    yorg += delta;
97	    if (yorg >= size || yorg + size + delta > HEIGHT) {
98		yorg = 0;
99		xorg++;
100		if (xorg >= size || xorg + size > WIDTH) {
101		    xorg = 0;
102		}
103	    }
104	    y = yorg;
105	    x += size;
106	    if (x + size > WIDTH) {
107		x = xorg;
108	    }
109	}
110	CheckAbort ();
111    }
112}
113
114void
115MidScroll(XParms xp, Parms p)
116{
117    XClearWindow(xp->d, xp->w);
118    XDrawLines(xp->d, xp->w, xp->fggc, points, NUMPOINTS, CoordModeOrigin);
119}
120
121void
122EndScroll(XParms xp, Parms p)
123{
124}
125
126static void
127InitCopyLocations(int size, int mul, int div,
128		  int64_t reps, XSegment **ap, XSegment **bp)
129{
130    int x1, y1, x2, y2, i;
131    int xinc, yinc;
132    int width, height;
133    XSegment *a, *b;
134
135    size = size * mul / div;
136    /* Try to exercise all alignments of src and destination equally, as well
137       as all 4 top-to-bottom/bottom-to-top, left-to-right, right-to-left
138       copying directions.  Computation done here just to make sure slow
139       machines aren't measuring anything but the XCopyArea calls.
140    */
141    xinc = (size & ~3) + 1;
142    yinc = xinc + 3;
143
144    width = (WIDTH - size) & ~31;
145    height = (HEIGHT - size) & ~31;
146
147    x1 = 0;
148    y1 = 0;
149    x2 = width;
150    y2 = height;
151
152    *ap = a = (XSegment *)malloc(reps * sizeof(XSegment));
153    *bp = b = (XSegment *)malloc(reps * sizeof(XSegment));
154    for (i = 0; i != reps; i++) {
155	a[i].x1 = x1 * div / mul;
156	a[i].y1 = y1 * div / mul;
157	a[i].x2 = x2 * div / mul;
158	a[i].y2 = y2 * div / mul;
159
160	/* Move x2, y2, location backward */
161	x2 -= xinc;
162	if (x2 < 0) {
163	    x2 = NegMod(x2, width);
164	    y2 -= yinc;
165	    if (y2 < 0) {
166		y2 = NegMod(y2, height);
167	    }
168	}
169
170	b[i].x1 = x1 * div / mul;
171	b[i].y1 = y1 * div / mul;
172	b[i].x2 = x2 * div / mul;
173	b[i].y2 = y2 * div / mul;
174
175	/* Move x1, y1 location forward */
176	x1 += xinc;
177	if (x1 > width) {
178	    x1 %= 32;
179	    y1 += yinc;
180	    if (y1 > height) {
181		y1 %= 32;
182	    }
183	}
184    } /* end for */
185}
186
187
188int
189InitCopyWin(XParms xp, Parms p, int64_t reps)
190{
191    (void) InitScroll(xp, p, reps);
192    InitCopyLocations(p->special, 1, 1, reps, &segsa, &segsb);
193    return reps;
194}
195
196int
197InitCopyPix(XParms xp, Parms p, int64_t reps)
198{
199    GC		pixgc;
200    (void) InitCopyWin(xp, p, reps);
201
202    /* Create pixmap to write stuff into, and initialize it */
203    pix = XCreatePixmap(xp->d, xp->w, WIDTH, HEIGHT, xp->vinfo.depth);
204    pixgc = XCreateGC(xp->d, pix, 0, NULL);
205    /* need a gc with GXcopy cos pixmaps contain junk on creation. mmm */
206    XCopyArea(xp->d, xp->w, pix, pixgc, 0, 0, WIDTH, HEIGHT, 0, 0);
207    XFreeGC(xp->d, pixgc);
208    return reps;
209}
210
211int
212InitGetImage(XParms xp, Parms p, int64_t reps)
213{
214    (void) InitCopyWin(xp, p, reps);
215
216    /* Create image to stuff bits into */
217    image = XGetImage(xp->d, xp->w, 0, 0, WIDTH, HEIGHT, xp->planemask,
218		      p->font==NULL?ZPixmap:XYPixmap);
219    if(image==NULL){
220	printf("XGetImage failed\n");
221	return False;
222    }
223    return reps;
224}
225
226int
227InitPutImage(XParms xp, Parms p, int64_t reps)
228{
229    if(!InitGetImage(xp, p, reps))return False;
230    XClearWindow(xp->d, xp->w);
231    return reps;
232}
233
234static void
235CopyArea(XParms xp, Parms p, int64_t reps, Drawable src, Drawable dst)
236{
237    int i, size;
238    XSegment *sa, *sb;
239
240    size = p->special;
241    for (sa = segsa, sb = segsb, i = 0; i != reps; i++, sa++, sb++) {
242	XCopyArea(xp->d, src, dst, xp->fggc,
243	    sa->x1, sa->y1, size, size, sa->x2, sa->y2);
244	XCopyArea(xp->d, src, dst, xp->fggc,
245	    sa->x2, sa->y2, size, size, sa->x1, sa->y1);
246	XCopyArea(xp->d, src, dst, xp->fggc,
247	    sb->x2, sb->y2, size, size, sb->x1, sb->y1);
248	XCopyArea(xp->d, src, dst, xp->fggc,
249	    sb->x1, sb->y1, size, size, sb->x2, sb->y2);
250	CheckAbort ();
251    }
252}
253
254void
255DoCopyWinWin(XParms xp, Parms p, int64_t reps)
256{
257    CopyArea(xp, p, reps, xp->w, xp->w);
258}
259
260void
261DoCopyPixWin(XParms xp, Parms p, int64_t reps)
262{
263    CopyArea(xp, p, reps, pix, xp->w);
264}
265
266void
267DoCopyWinPix(XParms xp, Parms p, int64_t reps)
268{
269    CopyArea(xp, p, reps, xp->w, pix);
270    xp->p = pix;	/* HardwareSync will now sync on pixmap */
271}
272
273void
274DoCopyPixPix(XParms xp, Parms p, int64_t reps)
275{
276    CopyArea(xp, p, reps, pix, pix);
277    xp->p = pix;	/* HardwareSync will now sync on pixmap */
278}
279
280void
281DoGetImage(XParms xp, Parms p, int64_t reps)
282{
283    int i, size;
284    XSegment *sa, *sb;
285    int format;
286
287    size = p->special;
288    format = (p->font == NULL) ? ZPixmap : XYPixmap;
289    for (sa = segsa, sb = segsb, i = 0; i != reps; i++, sa++, sb++) {
290	XDestroyImage(image);
291	image = XGetImage(xp->d, xp->w, sa->x1, sa->y1, size, size,
292	    xp->planemask, format);
293	if (image) XDestroyImage(image);
294	image = XGetImage(xp->d, xp->w, sa->x2, sa->y2, size, size,
295	    xp->planemask, format);
296	if (image) XDestroyImage(image);
297	image = XGetImage(xp->d, xp->w, sb->x2, sb->y2, size, size,
298	    xp->planemask, format);
299	if (image) XDestroyImage(image);
300	image = XGetImage(xp->d, xp->w, sb->x1, sb->y1, size, size,
301	    xp->planemask, format);
302/*
303
304One might expect XGetSubImage to be slightly faster than XGetImage.  Go look
305at the code in Xlib.  MIT X11R3 ran approximately 30 times slower for a 500x500
306rectangle.
307
308	(void) XGetSubImage(xp->d, xp->w, sa->x1, sa->y1, size, size,
309	    xp->planemask, ZPixmap, image, sa->x2, sa->y2);
310	(void) XGetSubImage(xp->d, xp->w, sa->x2, sa->y2, size, size,
311	    xp->planemask, ZPixmap, image, sa->x1, sa->y1);
312	(void) XGetSubImage(xp->d, xp->w, sb->x2, sb->y2, size, size,
313	    xp->planemask, ZPixmap, image, sb->x2, sb->y2);
314	(void) XGetSubImage(xp->d, xp->w, sb->x1, sb->y1, size, size,
315	    xp->planemask, ZPixmap, image, sb->x2, sb->y2);
316*/
317	CheckAbort ();
318    }
319}
320
321void
322DoPutImage(XParms xp, Parms p, int64_t reps)
323{
324    int i, size;
325    XSegment *sa, *sb;
326
327    size = p->special;
328    for (sa = segsa, sb = segsb, i = 0; i != reps; i++, sa++, sb++) {
329	XPutImage(xp->d, xp->w, xp->fggc, image,
330	    sa->x1, sa->y1, sa->x2, sa->y2, size, size);
331	XPutImage(xp->d, xp->w, xp->fggc, image,
332	    sa->x2, sa->y2, sa->x1, sa->y1, size, size);
333	XPutImage(xp->d, xp->w, xp->fggc, image,
334	    sb->x2, sb->y2, sb->x2, sb->y2, size, size);
335	XPutImage(xp->d, xp->w, xp->fggc, image,
336	    sb->x1, sb->y1, sb->x2, sb->y2, size, size);
337	CheckAbort ();
338    }
339}
340
341#ifdef MITSHM
342
343#include <sys/types.h>
344#ifndef Lynx
345#include <sys/ipc.h>
346#include <sys/shm.h>
347#else
348#include <ipc.h>
349#include <shm.h>
350#endif
351#include <X11/extensions/XShm.h>
352
353static XImage		shm_image;
354static XShmSegmentInfo	shm_info;
355
356static int haderror;
357static int (*origerrorhandler)(Display *, XErrorEvent *);
358
359static int
360shmerrorhandler(Display *d, XErrorEvent *e)
361{
362    haderror++;
363    if(e->error_code==BadAccess) {
364	fprintf(stderr,"failed to attach shared memory\n");
365	return 0;
366    } else
367	return (*origerrorhandler)(d,e);
368}
369
370static int
371InitShmImage(XParms xp, Parms p, int64_t reps, Bool read_only)
372{
373    int	image_size;
374
375    if(!InitGetImage(xp, p, reps))return False;
376    if (!XShmQueryExtension(xp->d)) {
377	/*
378 	 * Clean up here because cleanup function is not called if this
379	 * function fails
380	 */
381       	if (image)
382      	    XDestroyImage(image);
383    	image = NULL;
384    	free(segsa);
385    	free(segsb);
386    	return False;
387    }
388    shm_image = *image;
389    image_size = image->bytes_per_line * image->height;
390    /* allow XYPixmap choice: */
391    if(p->font)image_size *= xp->vinfo.depth;
392    shm_info.shmid = shmget(IPC_PRIVATE, image_size, IPC_CREAT|0777);
393    if (shm_info.shmid < 0)
394    {
395	/*
396	 * Clean up here because cleanup function is not called if this
397	 * function fails
398	 */
399	if (image)
400	    XDestroyImage(image);
401	image = NULL;
402	free(segsa);
403	free(segsb);
404	perror ("shmget");
405	return False;
406    }
407    shm_info.shmaddr = (char *) shmat(shm_info.shmid, NULL, 0);
408    if (shm_info.shmaddr == ((char *) -1))
409    {
410	/*
411	 * Clean up here because cleanup function is not called if this
412	 * function fails
413	 */
414	if (image)
415	    XDestroyImage(image);
416	image = NULL;
417	free(segsa);
418	free(segsb);
419	perror ("shmat");
420	shmctl (shm_info.shmid, IPC_RMID, NULL);
421	return False;
422    }
423    shm_info.readOnly = read_only;
424    XSync(xp->d,True);
425    haderror = False;
426    origerrorhandler = XSetErrorHandler(shmerrorhandler);
427    XShmAttach (xp->d, &shm_info);
428    XSync(xp->d,True);	/* wait for error or ok */
429    XSetErrorHandler(origerrorhandler);
430    if(haderror){
431	/*
432	 * Clean up here because cleanup function is not called if this
433	 * function fails
434	 */
435	if (image)
436	    XDestroyImage(image);
437	image = NULL;
438	free(segsa);
439	free(segsb);
440	if(shmdt (shm_info.shmaddr)==-1)
441	    perror("shmdt:");
442	if(shmctl (shm_info.shmid, IPC_RMID, NULL)==-1)
443	    perror("shmctl rmid:");
444	return False;
445    }
446    shm_image.data = shm_info.shmaddr;
447    memmove( shm_image.data, image->data, image_size);
448    shm_image.obdata = (char *) &shm_info;
449    return reps;
450}
451
452int
453InitShmPutImage(XParms xp, Parms p, int64_t reps)
454{
455    if (!InitShmImage(xp, p, reps, True)) return False;
456    XClearWindow(xp->d, xp->w);
457    return reps;
458}
459
460int
461InitShmGetImage(XParms xp, Parms p, int64_t reps)
462{
463    return InitShmImage(xp, p, reps, False);
464}
465
466void
467DoShmPutImage(XParms xp, Parms p, int64_t reps)
468{
469    int i, size;
470    XSegment *sa, *sb;
471
472    size = p->special;
473    for (sa = segsa, sb = segsb, i = 0; i != reps; i++, sa++, sb++) {
474	XShmPutImage(xp->d, xp->w, xp->fggc, &shm_image,
475	    sa->x1, sa->y1, sa->x2, sa->y2, size, size, False);
476	XShmPutImage(xp->d, xp->w, xp->fggc, &shm_image,
477	    sa->x2, sa->y2, sa->x1, sa->y1, size, size, False);
478	XShmPutImage(xp->d, xp->w, xp->fggc, &shm_image,
479	    sb->x2, sb->y2, sb->x2, sb->y2, size, size, False);
480	XShmPutImage(xp->d, xp->w, xp->fggc, &shm_image,
481	    sb->x1, sb->y1, sb->x2, sb->y2, size, size, False);
482	CheckAbort ();
483    }
484}
485
486void
487DoShmGetImage(XParms xp, Parms p, int64_t reps)
488{
489    int i, size;
490    XSegment *sa, *sb;
491
492    size = p->special;
493
494    shm_image.width = size;
495    shm_image.height = size;
496
497    for (sa = segsa, sb = segsb, i = 0; i != reps; i++, sa++, sb++) {
498	/* compute offsets into image data? */
499	XShmGetImage(xp->d, xp->w, &shm_image, sa->x1, sa->y1, xp->planemask);
500	XShmGetImage(xp->d, xp->w, &shm_image, sa->x2, sa->y2, xp->planemask);
501	XShmGetImage(xp->d, xp->w, &shm_image, sb->x2, sb->y2, xp->planemask);
502	XShmGetImage(xp->d, xp->w, &shm_image, sb->x1, sb->y1, xp->planemask);
503	CheckAbort ();
504    }
505}
506
507static void
508EndShmImage(XParms xp, Parms p)
509{
510    EndGetImage (xp, p);
511    XShmDetach (xp->d, &shm_info);
512    XSync(xp->d, False);	/* need server to detach so can remove id */
513    if(shmdt (shm_info.shmaddr)==-1)
514	perror("shmdt:");
515    if(shmctl (shm_info.shmid, IPC_RMID, NULL)==-1)
516	perror("shmctl rmid:");
517}
518
519void
520EndShmGetImage(XParms xp, Parms p)
521{
522    EndShmImage(xp, p);
523}
524
525void
526EndShmPutImage(XParms xp, Parms p)
527{
528    EndShmImage(xp, p);
529}
530#endif
531
532
533void
534MidCopyPix(XParms xp, Parms p)
535{
536    XClearWindow(xp->d, xp->w);
537}
538
539void
540EndCopyWin(XParms xp, Parms p)
541{
542    EndScroll(xp, p);
543    free(segsa);
544    free(segsb);
545    if (segsa2)
546	free (segsa2);
547    if (segsb2)
548	free (segsb2);
549    segsa = segsb = segsa2 = segsb2 = NULL;
550}
551
552void
553EndCopyPix(XParms xp, Parms p)
554{
555    EndCopyWin(xp, p);
556    XFreePixmap(xp->d, pix);
557    /*
558     * Ensure that the next test doesn't try and sync on the pixmap
559     */
560    xp->p = (Pixmap)0;
561}
562
563void
564EndGetImage(XParms xp, Parms p)
565{
566    EndCopyWin(xp, p);
567    if (image) XDestroyImage(image);
568}
569
570int
571InitCopyPlane(XParms xp, Parms p, int64_t reps)
572{
573    XGCValues   gcv;
574    GC		pixgc;
575
576    InitBltLines();
577    InitCopyLocations(p->special, 1, 1, reps, &segsa, &segsb);
578
579    /* Create pixmap to write stuff into, and initialize it */
580    pix = XCreatePixmap(xp->d, xp->w, WIDTH, HEIGHT,
581	    p->font==NULL ? 1 : xp->vinfo.depth);
582    gcv.graphics_exposures = False;
583    gcv.foreground = 0;
584    gcv.background = 1;
585    pixgc = XCreateGC(xp->d, pix,
586		GCForeground | GCBackground | GCGraphicsExposures, &gcv);
587    XFillRectangle(xp->d, pix, pixgc, 0, 0, WIDTH, HEIGHT);
588    gcv.foreground = 1;
589    gcv.background = 0;
590    XChangeGC(xp->d, pixgc, GCForeground | GCBackground, &gcv);
591    XDrawLines(xp->d, pix, pixgc, points, NUMPOINTS, CoordModeOrigin);
592    XFreeGC(xp->d, pixgc);
593
594    return reps;
595}
596
597void
598DoCopyPlane(XParms xp, Parms p, int64_t reps)
599{
600    int		i, size;
601    XSegment    *sa, *sb;
602
603    size = p->special;
604    for (sa = segsa, sb = segsb, i = 0; i != reps; i++, sa++, sb++) {
605	XCopyPlane(xp->d, pix, xp->w, xp->fggc,
606	    sa->x1, sa->y1, size, size, sa->x2, sa->y2, 1);
607	XCopyPlane(xp->d, pix, xp->w, xp->fggc,
608	    sa->x2, sa->y2, size, size, sa->x1, sa->y1, 1);
609	XCopyPlane(xp->d, pix, xp->w, xp->fggc,
610	    sb->x2, sb->y2, size, size, sb->x1, sb->y1, 1);
611	XCopyPlane(xp->d, pix, xp->w, xp->fggc,
612	    sb->x1, sb->y1, size, size, sb->x2, sb->y2, 1);
613	CheckAbort ();
614    }
615}
616
617#include <X11/extensions/Xrender.h>
618
619static Picture	winPict, pixPict;
620
621int
622InitCompositeWin(XParms xp, Parms p, int64_t reps)
623{
624    XRenderPictFormat	*format;
625
626    (void) InitScroll (xp, p, reps);
627    InitCopyLocations(p->special, 1, 1, reps, &segsa, &segsb);
628    if (p->fillStyle) {
629	int mul = 0x10000;
630	int div = p->fillStyle;
631	InitCopyLocations (p->special, mul, div, reps, &segsa2, &segsb2);
632    }
633    format = XRenderFindVisualFormat (xp->d, xp->vinfo.visual);
634    winPict = XRenderCreatePicture (xp->d, xp->w, format, 0, NULL);
635    return reps;
636}
637
638int
639InitCompositePix(XParms xp, Parms p, int64_t reps)
640{
641    XRenderPictFormat	*format = NULL;
642    int			depth;
643    static XRenderColor c = { 0xffff, 0x0000, 0xffff, 0xffff };
644
645    (void) InitCompositeWin (xp, p, reps);
646
647    /* Create pixmap to write stuff into, and initialize it */
648    switch (xp->planemask) {
649    case PictStandardNative:
650	depth = xp->vinfo.depth;
651	format = XRenderFindVisualFormat (xp->d, xp->vinfo.visual);
652	break;
653    case PictStandardRGB24:
654	depth = 24;
655	break;
656    case PictStandardARGB32:
657	depth = 32;
658	break;
659    case PictStandardA8:
660	depth = 8;
661	break;
662    case PictStandardA4:
663	depth = 4;
664	break;
665    case PictStandardA1:
666	depth = 1;
667	break;
668    default:
669	depth = 0;
670	break;
671    }
672    if (!format)
673	format = XRenderFindStandardFormat (xp->d, xp->planemask);
674
675    pix = XCreatePixmap(xp->d, xp->w, WIDTH, HEIGHT, depth);
676    pixPict = XRenderCreatePicture (xp->d, pix, format, 0, NULL);
677
678    XRenderComposite (xp->d, PictOpClear,
679		      winPict, None, pixPict,
680		      0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
681
682    XRenderFillRectangle (xp->d, PictOpSrc,
683			  pixPict, &c, 0, 0, WIDTH, HEIGHT);
684#if 1
685    XRenderComposite (xp->d, PictOpSrc,
686		      winPict, None, pixPict,
687		      0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
688#endif
689    if (p->fillStyle) {
690	XTransform		transform;
691	memset (&transform, '\0', sizeof (transform));
692	transform.matrix[0][0] = ((long long) 0x10000 * 0x10000) / p->fillStyle;
693	transform.matrix[1][1] = ((long long) 0x10000 * 0x10000) / p->fillStyle;
694	transform.matrix[2][2] = 0x10000;
695	XRenderSetPictureTransform (xp->d, pixPict, &transform);
696	XRenderSetPictureFilter (xp->d, pixPict, FilterBilinear, NULL, 0);
697    }
698    return reps;
699}
700
701void
702EndCompositeWin (XParms xp, Parms p)
703{
704    if (winPict)
705    {
706	XRenderFreePicture (xp->d, winPict);
707	winPict = None;
708    }
709    if (pixPict)
710    {
711	XRenderFreePicture (xp->d, pixPict);
712	pixPict = None;
713    }
714}
715
716static void
717CompositeArea(XParms xp, Parms p, int64_t reps, Picture src, Picture dst)
718{
719    int i, size;
720    XSegment *sa, *sb;
721    XSegment *sa2, *sb2;
722
723
724    size = p->special;
725    sa = segsa;
726    sb = segsb;
727    sa2 = segsa2 ? segsa2 : segsa;
728    sb2 = segsb2 ? segsb2 : segsb;
729    for (i = 0; i < reps; i++) {
730	XRenderComposite (xp->d, xp->func,
731			  src, None, dst,
732			  sa2->x1, sa2->y1, 0, 0, sa->x2, sa->y2, size, size);
733	XRenderComposite (xp->d, xp->func,
734			  src, None, dst,
735			  sa2->x2, sa2->y2, 0, 0, sa->x1, sa->y1, size, size);
736	XRenderComposite (xp->d, xp->func,
737			  src, None, dst,
738			  sb2->x2, sb2->y2, 0, 0, sb->x1, sb->y1, size, size);
739	XRenderComposite (xp->d, xp->func,
740			  src, None, dst,
741			  sb2->x1, sb2->y1, 0, 0, sb->x2, sb->y2, size, size);
742	CheckAbort ();
743	sa++; sb++;
744	sa2++; sb2++;
745    }
746}
747
748void
749DoCompositeWinWin (XParms xp, Parms p, int64_t reps)
750{
751    CompositeArea (xp, p, reps, winPict, winPict);
752}
753
754void
755DoCompositePixWin (XParms xp, Parms p, int64_t reps)
756{
757    CompositeArea (xp, p, reps, pixPict, winPict);
758}
759