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