do_blt.c revision 264fa531
1/* $Xorg: do_blt.c,v 1.3 2000/08/17 19:54:09 cpqbld Exp $ */
2/*****************************************************************************
3Copyright 1988, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
4
5                        All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the name of Digital not be
12used in advertising or publicity pertaining to distribution of the
13software without specific, written prior permission.
14
15DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21SOFTWARE.
22
23******************************************************************************/
24/* $XFree86: xc/programs/x11perf/do_blt.c,v 1.8 2001/05/01 16:19:16 alanh Exp $ */
25
26#include "x11perf.h"
27#include <stdio.h>
28
29#define NUMPOINTS 100
30
31static Pixmap   pix;
32static XImage   *image;
33static XPoint   points[NUMPOINTS];
34static XSegment *segsa, *segsb;
35
36#define NegMod(x, y) ((y) - (((-x)-1) % (7)) - 1)
37
38static void
39InitBltLines(void)
40{
41    int i, x, y;
42
43    points[0].x = points[0].y = y = 0;
44    for (i = 1; i != NUMPOINTS/2; i++) {
45	if (i & 1) {
46	    points[i].x = WIDTH-1;
47	} else {
48	    points[i].x = 0;
49	}
50	y += HEIGHT / (NUMPOINTS/2);
51	points[i].y = y;
52    }
53
54    x = 0;
55    for (i = NUMPOINTS/2; i!= NUMPOINTS; i++) {
56	if (i & 1) {
57	    points[i].y = HEIGHT-1;
58	} else {
59	    points[i].y = 0;
60	}
61	x += WIDTH / (NUMPOINTS/2);
62	points[i].x = x;
63    }
64}
65
66int
67InitScroll(XParms xp, Parms p, int reps)
68{
69    InitBltLines();
70    XDrawLines(xp->d, xp->w, xp->fggc, points, NUMPOINTS, CoordModeOrigin);
71    return reps;
72}
73
74void
75DoScroll(XParms xp, Parms p, int reps)
76{
77    int i, size, x, y, xorg, yorg, delta;
78
79    size = p->special;
80    xorg = 0;   yorg = 0;
81    x    = 0;   y    = 0;
82    if (xp->version == VERSION1_2) {
83	delta = 1;
84    } else {
85	/* Version 1.2 only scrolled up by 1 scanline, which made hardware
86	   using page-mode access to VRAM look better on paper than it would
87	   perform in a more realistic scroll.  So we've changed to scroll by
88	   the height of the 6x13 fonts. */
89	delta = 13;
90    }
91
92    for (i = 0; i != reps; i++) {
93	XCopyArea(xp->d, xp->w, xp->w, xp->fggc, x, y + delta,
94	    size, size, x, y);
95	y += size;
96	if (y + size + delta > HEIGHT) {
97	    yorg += delta;
98	    if (yorg >= size || yorg + size + delta > HEIGHT) {
99		yorg = 0;
100		xorg++;
101		if (xorg >= size || xorg + size > WIDTH) {
102		    xorg = 0;
103		}
104	    }
105	    y = yorg;
106	    x += size;
107	    if (x + size > WIDTH) {
108		x = xorg;
109	    }
110	}
111	CheckAbort ();
112    }
113}
114
115void
116MidScroll(XParms xp, Parms p)
117{
118    XClearWindow(xp->d, xp->w);
119    XDrawLines(xp->d, xp->w, xp->fggc, points, NUMPOINTS, CoordModeOrigin);
120}
121
122void
123EndScroll(XParms xp, Parms p)
124{
125}
126
127static void
128InitCopyLocations(XParms xp, Parms p, int reps)
129{
130    int x1, y1, x2, y2, size, i;
131    int xinc, yinc;
132    int width, height;
133
134    /* Try to exercise all alignments of src and destination equally, as well
135       as all 4 top-to-bottom/bottom-to-top, left-to-right, right-to-left
136       copying directions.  Computation done here just to make sure slow
137       machines aren't measuring anything but the XCopyArea calls.
138    */
139    size = p->special;
140    xinc = (size & ~3) + 1;
141    yinc = xinc + 3;
142
143    width = (WIDTH - size) & ~31;
144    height = (HEIGHT - size) & ~31;
145
146    x1 = 0;
147    y1 = 0;
148    x2 = width;
149    y2 = height;
150
151    segsa = (XSegment *)malloc(reps * sizeof(XSegment));
152    segsb = (XSegment *)malloc(reps * sizeof(XSegment));
153    for (i = 0; i != reps; i++) {
154	segsa[i].x1 = x1;
155	segsa[i].y1 = y1;
156	segsa[i].x2 = x2;
157	segsa[i].y2 = y2;
158
159	/* Move x2, y2, location backward */
160	x2 -= xinc;
161	if (x2 < 0) {
162	    x2 = NegMod(x2, width);
163	    y2 -= yinc;
164	    if (y2 < 0) {
165		y2 = NegMod(y2, height);
166	    }
167	}
168
169	segsb[i].x1 = x1;
170	segsb[i].y1 = y1;
171	segsb[i].x2 = x2;
172	segsb[i].y2 = y2;
173
174	/* Move x1, y1 location forward */
175	x1 += xinc;
176	if (x1 > width) {
177	    x1 %= 32;
178	    y1 += yinc;
179	    if (y1 > height) {
180		y1 %= 32;
181	    }
182	}
183    } /* end for */
184}
185
186
187int
188InitCopyWin(XParms xp, Parms p, int reps)
189{
190    (void) InitScroll(xp, p, reps);
191    InitCopyLocations(xp, p, reps);
192    return reps;
193}
194
195int
196InitCopyPix(XParms xp, Parms p, int reps)
197{
198    GC		pixgc;
199    (void) InitCopyWin(xp, p, reps);
200
201    /* Create pixmap to write stuff into, and initialize it */
202    pix = XCreatePixmap(xp->d, xp->w, WIDTH, HEIGHT, xp->vinfo.depth);
203    pixgc = XCreateGC(xp->d, pix, 0, 0);
204    /* need a gc with GXcopy cos pixmaps contain junk on creation. mmm */
205    XCopyArea(xp->d, xp->w, pix, pixgc, 0, 0, WIDTH, HEIGHT, 0, 0);
206    XFreeGC(xp->d, pixgc);
207    return reps;
208}
209
210int
211InitGetImage(XParms xp, Parms p, int reps)
212{
213    (void) InitCopyWin(xp, p, reps);
214
215    /* Create image to stuff bits into */
216    image = XGetImage(xp->d, xp->w, 0, 0, WIDTH, HEIGHT, xp->planemask,
217		      p->font==0?ZPixmap:XYPixmap);
218    if(image==0){
219	printf("XGetImage failed\n");
220	return False;
221    }
222    return reps;
223}
224
225int
226InitPutImage(XParms xp, Parms p, int reps)
227{
228    if(!InitGetImage(xp, p, reps))return False;
229    XClearWindow(xp->d, xp->w);
230    return reps;
231}
232
233static void
234CopyArea(XParms xp, Parms p, int reps, Drawable src, Drawable dst)
235{
236    int i, size;
237    XSegment *sa, *sb;
238
239    size = p->special;
240    for (sa = segsa, sb = segsb, i = 0; i != reps; i++, sa++, sb++) {
241	XCopyArea(xp->d, src, dst, xp->fggc,
242	    sa->x1, sa->y1, size, size, sa->x2, sa->y2);
243	XCopyArea(xp->d, src, dst, xp->fggc,
244	    sa->x2, sa->y2, size, size, sa->x1, sa->y1);
245	XCopyArea(xp->d, src, dst, xp->fggc,
246	    sb->x2, sb->y2, size, size, sb->x1, sb->y1);
247	XCopyArea(xp->d, src, dst, xp->fggc,
248	    sb->x1, sb->y1, size, size, sb->x2, sb->y2);
249	CheckAbort ();
250    }
251}
252
253void
254DoCopyWinWin(XParms xp, Parms p, int reps)
255{
256    CopyArea(xp, p, reps, xp->w, xp->w);
257}
258
259void
260DoCopyPixWin(XParms xp, Parms p, int reps)
261{
262    CopyArea(xp, p, reps, pix, xp->w);
263}
264
265void
266DoCopyWinPix(XParms xp, Parms p, int reps)
267{
268    CopyArea(xp, p, reps, xp->w, pix);
269    xp->p = pix;	/* HardwareSync will now sync on pixmap */
270}
271
272void
273DoCopyPixPix(XParms xp, Parms p, int reps)
274{
275    CopyArea(xp, p, reps, pix, pix);
276    xp->p = pix;	/* HardwareSync will now sync on pixmap */
277}
278
279void
280DoGetImage(XParms xp, Parms p, int reps)
281{
282    int i, size;
283    XSegment *sa, *sb;
284    int format;
285
286    size = p->special;
287    format = (p->font == 0) ? ZPixmap : XYPixmap;
288    for (sa = segsa, sb = segsb, i = 0; i != reps; i++, sa++, sb++) {
289	XDestroyImage(image);
290	image = XGetImage(xp->d, xp->w, sa->x1, sa->y1, size, size,
291	    xp->planemask, format);
292	if (image) XDestroyImage(image);
293	image = XGetImage(xp->d, xp->w, sa->x2, sa->y2, size, size,
294	    xp->planemask, format);
295	if (image) XDestroyImage(image);
296	image = XGetImage(xp->d, xp->w, sb->x2, sb->y2, size, size,
297	    xp->planemask, format);
298	if (image) XDestroyImage(image);
299	image = XGetImage(xp->d, xp->w, sb->x1, sb->y1, size, size,
300	    xp->planemask, format);
301/*
302
303One might expect XGetSubImage to be slightly faster than XGetImage.  Go look
304at the code in Xlib.  MIT X11R3 ran approximately 30 times slower for a 500x500
305rectangle.
306
307	(void) XGetSubImage(xp->d, xp->w, sa->x1, sa->y1, size, size,
308	    xp->planemask, ZPixmap, image, sa->x2, sa->y2);
309	(void) XGetSubImage(xp->d, xp->w, sa->x2, sa->y2, size, size,
310	    xp->planemask, ZPixmap, image, sa->x1, sa->y1);
311	(void) XGetSubImage(xp->d, xp->w, sb->x2, sb->y2, size, size,
312	    xp->planemask, ZPixmap, image, sb->x2, sb->y2);
313	(void) XGetSubImage(xp->d, xp->w, sb->x1, sb->y1, size, size,
314	    xp->planemask, ZPixmap, image, sb->x2, sb->y2);
315*/
316	CheckAbort ();
317    }
318}
319
320void
321DoPutImage(XParms xp, Parms p, int reps)
322{
323    int i, size;
324    XSegment *sa, *sb;
325
326    size = p->special;
327    for (sa = segsa, sb = segsb, i = 0; i != reps; i++, sa++, sb++) {
328	XPutImage(xp->d, xp->w, xp->fggc, image,
329	    sa->x1, sa->y1, sa->x2, sa->y2, size, size);
330	XPutImage(xp->d, xp->w, xp->fggc, image,
331	    sa->x2, sa->y2, sa->x1, sa->y1, size, size);
332	XPutImage(xp->d, xp->w, xp->fggc, image,
333	    sb->x2, sb->y2, sb->x2, sb->y2, size, size);
334	XPutImage(xp->d, xp->w, xp->fggc, image,
335	    sb->x1, sb->y1, sb->x2, sb->y2, size, size);
336	CheckAbort ();
337    }
338}
339
340#ifdef MITSHM
341
342#include <sys/types.h>
343#ifndef Lynx
344#include <sys/ipc.h>
345#include <sys/shm.h>
346#else
347#include <ipc.h>
348#include <shm.h>
349#endif
350#include <X11/extensions/XShm.h>
351
352static XImage		shm_image;
353static XShmSegmentInfo	shm_info;
354
355static int haderror;
356static int (*origerrorhandler)(Display *, XErrorEvent *);
357
358static int
359shmerrorhandler(Display *d, XErrorEvent *e)
360{
361    haderror++;
362    if(e->error_code==BadAccess) {
363	fprintf(stderr,"failed to attach shared memory\n");
364	return 0;
365    } else
366	return (*origerrorhandler)(d,e);
367}
368
369int
370InitShmPutImage(XParms xp, Parms p, int reps)
371{
372    int	image_size;
373
374    if(!InitGetImage(xp, p, reps))return False;
375    if (!XShmQueryExtension(xp->d)) {
376	/*
377 	 * Clean up here because cleanup function is not called if this
378	 * function fails
379	 */
380       	if (image)
381      	    XDestroyImage(image);
382    	image = NULL;
383    	free(segsa);
384    	free(segsb);
385    	return False;
386    }
387    XClearWindow(xp->d, xp->w);
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, 0, 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, 0);
421	return False;
422    }
423    shm_info.readOnly = True;
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, 0)==-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
452void
453DoShmPutImage(XParms xp, Parms p, int reps)
454{
455    int i, size;
456    XSegment *sa, *sb;
457
458    size = p->special;
459    for (sa = segsa, sb = segsb, i = 0; i != reps; i++, sa++, sb++) {
460	XShmPutImage(xp->d, xp->w, xp->fggc, &shm_image,
461	    sa->x1, sa->y1, sa->x2, sa->y2, size, size, False);
462	XShmPutImage(xp->d, xp->w, xp->fggc, &shm_image,
463	    sa->x2, sa->y2, sa->x1, sa->y1, size, size, False);
464	XShmPutImage(xp->d, xp->w, xp->fggc, &shm_image,
465	    sb->x2, sb->y2, sb->x2, sb->y2, size, size, False);
466	XShmPutImage(xp->d, xp->w, xp->fggc, &shm_image,
467	    sb->x1, sb->y1, sb->x2, sb->y2, size, size, False);
468	CheckAbort ();
469    }
470}
471
472void
473EndShmPutImage(XParms xp, Parms p)
474{
475
476    EndGetImage (xp, p);
477    XShmDetach (xp->d, &shm_info);
478    XSync(xp->d, False);	/* need server to detach so can remove id */
479    if(shmdt (shm_info.shmaddr)==-1)
480	perror("shmdt:");
481    if(shmctl (shm_info.shmid, IPC_RMID, 0)==-1)
482	perror("shmctl rmid:");
483}
484
485#endif
486
487
488void
489MidCopyPix(XParms xp, Parms p)
490{
491    XClearWindow(xp->d, xp->w);
492}
493
494void
495EndCopyWin(XParms xp, Parms p)
496{
497    EndScroll(xp, p);
498    free(segsa);
499    free(segsb);
500}
501
502void
503EndCopyPix(XParms xp, Parms p)
504{
505    EndCopyWin(xp, p);
506    XFreePixmap(xp->d, pix);
507    /*
508     * Ensure that the next test doesn't try and sync on the pixmap
509     */
510    xp->p = (Pixmap)0;
511}
512
513void
514EndGetImage(XParms xp, Parms p)
515{
516    EndCopyWin(xp, p);
517    if (image) XDestroyImage(image);
518}
519
520int
521InitCopyPlane(XParms xp, Parms p, int reps)
522{
523    XGCValues   gcv;
524    GC		pixgc;
525
526    InitBltLines();
527    InitCopyLocations(xp, p, reps);
528
529    /* Create pixmap to write stuff into, and initialize it */
530    pix = XCreatePixmap(xp->d, xp->w, WIDTH, HEIGHT,
531	    p->font==0 ? 1 : xp->vinfo.depth);
532    gcv.graphics_exposures = False;
533    gcv.foreground = 0;
534    gcv.background = 1;
535    pixgc = XCreateGC(xp->d, pix,
536		GCForeground | GCBackground | GCGraphicsExposures, &gcv);
537    XFillRectangle(xp->d, pix, pixgc, 0, 0, WIDTH, HEIGHT);
538    gcv.foreground = 1;
539    gcv.background = 0;
540    XChangeGC(xp->d, pixgc, GCForeground | GCBackground, &gcv);
541    XDrawLines(xp->d, pix, pixgc, points, NUMPOINTS, CoordModeOrigin);
542    XFreeGC(xp->d, pixgc);
543
544    return reps;
545}
546
547void
548DoCopyPlane(XParms xp, Parms p, int reps)
549{
550    int		i, size;
551    XSegment    *sa, *sb;
552
553    size = p->special;
554    for (sa = segsa, sb = segsb, i = 0; i != reps; i++, sa++, sb++) {
555	XCopyPlane(xp->d, pix, xp->w, xp->fggc,
556	    sa->x1, sa->y1, size, size, sa->x2, sa->y2, 1);
557	XCopyPlane(xp->d, pix, xp->w, xp->fggc,
558	    sa->x2, sa->y2, size, size, sa->x1, sa->y1, 1);
559	XCopyPlane(xp->d, pix, xp->w, xp->fggc,
560	    sb->x2, sb->y2, size, size, sb->x1, sb->y1, 1);
561	XCopyPlane(xp->d, pix, xp->w, xp->fggc,
562	    sb->x1, sb->y1, size, size, sb->x2, sb->y2, 1);
563	CheckAbort ();
564    }
565}
566
567