1 /* Copyright © 2014 Keith Packard <keithp@keithp.com>
2  * Copyright © 2014 Intel Corporation
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 /** @file t_libreoffice_xrgb.c
20  *
21  * Test Render's XRGB behavior when the pixmap is initialized with PutImage.
22  * Catches a bug in glamor where the Render acceleration was relying on the
23  * high bits of the pixmap having been set to 0xff, which is certainly not
24  * guaranteed.  The rest of rendercheck didn't catch the bug, because it uses
25  * XRenderFillRectangle() to initialize the common XRGB pictures, and
26  * apparently that was setting the unused bits to 1 at the time.
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32 #include <strings.h>
33 #include "rendercheck.h"
34 
35 #define WIDTH	1
36 #define HEIGHT	1
37 
38 #define PIXEL_XRGB		0x11886644
39 #define PIXEL_ARGB		0xff886644
40 #define INVERT_PIXEL_ARGB	0xff7799bb
41 
42 Bool
libreoffice_xrgb_test(Display * dpy,Bool invert)43 libreoffice_xrgb_test(Display *dpy, Bool invert)
44 {
45 	int x, y;
46 	Pixmap	src_pix, dst_pix;
47 	Picture	src_pict, dst_pict;
48 	XRenderPictFormat templ;
49 	XRenderPictFormat *pic_xrgb_format;
50 	XRenderPictFormat *pic_argb_format;
51 	XRenderPictFormat *pic_rgb_format;
52 	GC gc;
53 	XImage *image;
54 
55 	templ.type = PictTypeDirect;
56 	templ.depth = 32;
57 	templ.direct.alphaMask = 0;
58 	templ.direct.red = 16;
59 	templ.direct.green = 8;
60 	templ.direct.blue = 0;
61 
62 	pic_xrgb_format = XRenderFindFormat(dpy,
63 	    PictFormatType |
64 	    PictFormatDepth |
65 	    PictFormatAlphaMask |
66 	    PictFormatRed |
67 	    PictFormatGreen |
68 	    PictFormatBlue,
69 	    &templ, 0);
70 
71 	templ.type = PictTypeDirect;
72 	templ.depth = 32;
73 	templ.direct.alpha = 24;
74 	templ.direct.red = 16;
75 	templ.direct.green = 8;
76 	templ.direct.blue = 0;
77 
78 	pic_argb_format = XRenderFindFormat(dpy,
79 	    PictFormatType |
80 	    PictFormatDepth |
81 	    PictFormatAlpha |
82 	    PictFormatRed |
83 	    PictFormatGreen |
84 	    PictFormatBlue,
85 	    &templ, 0);
86 
87 	templ.type = PictTypeDirect;
88 	templ.depth = 24;
89 	templ.direct.red = 16;
90 	templ.direct.green = 8;
91 	templ.direct.blue = 0;
92 
93 	pic_rgb_format = XRenderFindFormat(dpy,
94 	    PictFormatType |
95 	    PictFormatDepth |
96 	    PictFormatRed |
97 	    PictFormatGreen |
98 	    PictFormatBlue,
99 	    &templ, 0);
100 
101 	if (!pic_argb_format || !pic_xrgb_format || !pic_rgb_format) {
102 		printf("Couldn't find xRGB and ARGB formats\n");
103 		return FALSE;
104 	}
105 
106 	src_pix = XCreatePixmap(dpy, RootWindow(dpy, DefaultScreen(dpy)),
107 	    WIDTH, HEIGHT, 32);
108 
109 	dst_pix = XCreatePixmap(dpy, RootWindow(dpy, DefaultScreen(dpy)),
110 	    WIDTH, HEIGHT, 32);
111 
112 	src_pict = XRenderCreatePicture(dpy, src_pix, pic_xrgb_format, 0,
113 	    NULL);
114 	dst_pict = XRenderCreatePicture(dpy, dst_pix, pic_argb_format, 0,
115 	    NULL);
116 
117 	image = XCreateImage(dpy,
118 	    NULL,
119 	    32,
120 	    ZPixmap,
121 	    0,
122 	    NULL,
123 	    WIDTH, HEIGHT, 32, 0);
124 
125 	image->data = malloc(HEIGHT * image->bytes_per_line);
126 
127 	for (y = 0; y < HEIGHT; y++)
128 		for (x = 0; x < WIDTH; x++)
129 			XPutPixel(image, x, y, PIXEL_XRGB);
130 
131 	gc = XCreateGC(dpy, src_pix, 0, NULL);
132 
133 	XPutImage(dpy, src_pix, gc, image, 0, 0, 0, 0, WIDTH, HEIGHT);
134 
135 	if (invert) {
136 		XSetFunction(dpy, gc, GXinvert);
137 
138 		XFillRectangle(dpy, src_pix, gc, 0, 0, WIDTH, HEIGHT);
139 	}
140 
141 	XDestroyImage(image);
142 
143 	XRenderComposite(dpy, PictOpOver, src_pict, None, dst_pict,
144 	    0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
145 
146 	image = XGetImage(dpy, dst_pix, 0, 0, WIDTH, HEIGHT, 0xffffffff,
147 			  ZPixmap);
148 	for (y = 0; y < HEIGHT; y++) {
149 		for (x = 0; x < WIDTH; x++) {
150 			unsigned long expected = (invert ? INVERT_PIXEL_ARGB :
151 						  PIXEL_ARGB);
152 			unsigned long pixel = XGetPixel(image, x, y);
153 
154 			if (pixel != expected) {
155 				printf("fail: pixel value is %08lx, "
156 				       "should be %08lx\n",
157 				       pixel, expected);
158 				return FALSE;
159 			}
160 		}
161 	}
162 	XDestroyImage(image);
163 
164 	return TRUE;
165 }
166