1 /*
2  * Copyright © 2012 Marek Olšák <maraeo@gmail.com>
3  * Copyright © 2014 Intel Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 /**
26  * @file gettextureimage-targets.c
27  */
28 
29 #include "piglit-util-gl.h"
30 
31 PIGLIT_GL_TEST_CONFIG_BEGIN
32 
33 	config.supports_gl_compat_version = 20;
34 	config.supports_gl_core_version = 31;
35 
36 	config.window_visual = PIGLIT_GL_VISUAL_RGBA |
37 			       PIGLIT_GL_VISUAL_DOUBLE;
38 	config.khr_no_error_support = PIGLIT_NO_ERRORS;
39 
40 PIGLIT_GL_TEST_CONFIG_END
41 
42 #define IMAGE_WIDTH 32
43 #define IMAGE_HEIGHT 32
44 #define IMAGE_SIZE (IMAGE_WIDTH * IMAGE_HEIGHT * 4)
45 
46 static void
init_layer_data(GLubyte * layer_data,int num_layers)47 init_layer_data(GLubyte *layer_data, int num_layers)
48 {
49 	int x, y, z, i, j;
50 
51 	for (z = 0; z < num_layers; z++) {
52 		GLubyte *data = layer_data + IMAGE_SIZE * z;
53 
54 		for (x = 0; x < IMAGE_WIDTH; x += 4) {
55 			for (y = 0; y < IMAGE_HEIGHT; y += 4) {
56 				int r = (x + 1) * 255 / (IMAGE_WIDTH - 1);
57 				int g = (y + 1) * 255 / (IMAGE_HEIGHT - 1);
58 				int b = (z + 1) * 255 / (num_layers - 1);
59 				int a = x ^ y ^ z;
60 
61 				/* each 4x4 block constains only one color (for S3TC) */
62 				for (i = 0; i < 4; i++) {
63 					for (j = 0; j < 4; j++) {
64 						data[((y + j) * IMAGE_WIDTH + x
65 						      + i) * 4 + 0] = r;
66 						data[((y + j) * IMAGE_WIDTH + x
67 						      + i) * 4 + 1] = g;
68 						data[((y + j) * IMAGE_WIDTH + x
69 						      + i) * 4 + 2] = b;
70 						data[((y + j) * IMAGE_WIDTH + x
71 						      + i) * 4 + 3] = a;
72 					}
73 				}
74 			}
75 		}
76 	}
77 }
78 
79 static bool
compare_layer(int layer,int num_elements,int tolerance,GLubyte * data,GLubyte * expected)80 compare_layer(int layer, int num_elements, int tolerance,
81 			  GLubyte *data, GLubyte *expected)
82 {
83 	int i;
84 
85 	for (i = 0; i < num_elements; ++i) {
86 		if (abs((int)data[i] - (int)expected[i]) > tolerance) {
87 			printf("GetTextureImage() returns incorrect data in byte %i for layer %i\n",
88 			       i, layer);
89 			printf("    corresponding to (%i,%i), channel %i\n",
90 			       (i / 4) / IMAGE_WIDTH, (i / 4) % IMAGE_HEIGHT, i % 4);
91 			printf("    expected: %i\n", expected[i]);
92 			printf("    got: %i\n", data[i]);
93 			return false;
94 		}
95 	}
96 	return true;
97 }
98 
99 static bool
getTexImage(bool doPBO,GLenum target,GLubyte data[][IMAGE_SIZE],GLenum internalformat,int tolerance)100 getTexImage(bool doPBO, GLenum target, GLubyte data[][IMAGE_SIZE],
101 	    GLenum internalformat, int tolerance)
102 {
103 	int i;
104 	int num_layers=1, num_faces=1, layer_size;
105 	GLubyte data2[18][IMAGE_SIZE];
106 	GLubyte *dataGet;
107 	GLuint packPBO;
108 	bool pass = true;
109 	GLuint name;
110 
111 	switch (target) {
112 	case GL_TEXTURE_1D:
113 		glCreateTextures(target, 1, &name);
114 		glTextureStorage1D(name, 1, internalformat, IMAGE_WIDTH);
115 		glTextureSubImage1D(name, 0, 0, IMAGE_WIDTH, GL_RGBA,
116 				    GL_UNSIGNED_BYTE, data);
117 		layer_size = IMAGE_WIDTH * 4;
118 		break;
119 
120 	case GL_TEXTURE_2D:
121 	case GL_TEXTURE_RECTANGLE:
122 		glCreateTextures(target, 1, &name);
123 		glTextureStorage2D(name, 1, internalformat, IMAGE_WIDTH,
124 				   IMAGE_HEIGHT);
125 		glTextureSubImage2D(name, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT,
126 				    GL_RGBA, GL_UNSIGNED_BYTE, data);
127 		layer_size = IMAGE_SIZE;
128 		break;
129 
130 	case GL_TEXTURE_CUBE_MAP:
131 		num_faces = 6;
132 		glCreateTextures(target, 1, &name);
133 		/* This is invalid. You must use 2D storage call for cube. */
134 		if (!piglit_khr_no_error) {
135 			glTextureStorage3D(name, 1, internalformat,
136 					   IMAGE_WIDTH, IMAGE_HEIGHT,
137 					   num_faces);
138 			pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
139 		}
140 		/* This is legal. */
141 		glTextureStorage2D(name, 1, internalformat,
142 				   IMAGE_WIDTH, IMAGE_HEIGHT);
143 		glTextureSubImage3D(name, 0, 0, 0, 0, IMAGE_WIDTH,
144 				    IMAGE_HEIGHT, num_faces, GL_RGBA,
145 				    GL_UNSIGNED_BYTE, data);
146 		layer_size = IMAGE_SIZE;
147 		break;
148 
149 	case GL_TEXTURE_1D_ARRAY:
150 		num_layers = 7;
151 		glCreateTextures(target, 1, &name);
152 		// test as a single layer 2D image
153 		glTextureStorage2D(name, 1, internalformat, IMAGE_WIDTH,
154 				   num_layers);
155 		glTextureSubImage2D(name, 0, 0, 0, IMAGE_WIDTH, num_layers,
156 			            GL_RGBA, GL_UNSIGNED_BYTE, data);
157 		layer_size = IMAGE_WIDTH * 4 * num_layers;
158 		num_layers = 1;
159 		break;
160 
161 	case GL_TEXTURE_3D:
162 		num_layers = 16; /* Fall through. */
163 	case GL_TEXTURE_2D_ARRAY:
164 		num_layers = 7; /* Fall through. */
165 	case GL_TEXTURE_CUBE_MAP_ARRAY:
166 		num_layers = 6 * 3;
167 		glCreateTextures(target, 1, &name);
168 		glTextureStorage3D(name, 1, internalformat, IMAGE_WIDTH,
169 				   IMAGE_HEIGHT, num_layers);
170 		glTextureSubImage3D(name, 0, 0, 0, 0,
171 				    IMAGE_WIDTH, IMAGE_HEIGHT, num_layers,
172 				    GL_RGBA, GL_UNSIGNED_BYTE, data);
173 		layer_size = IMAGE_SIZE;
174 		break;
175 
176 	default:
177 		puts("Invalid texture target.");
178 		return false;
179 
180 	}
181 
182 	/* Setup the PBO or data array to read into from glGetTextureImage */
183 	if (doPBO) {
184 		glGenBuffers(1, &packPBO);
185 		glBindBuffer(GL_PIXEL_PACK_BUFFER, packPBO);
186 		glBufferData(GL_PIXEL_PACK_BUFFER,
187 				     layer_size * num_faces * num_layers,
188 				     NULL, GL_STREAM_READ);
189 	} else {
190 		glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
191 		memset(data2, 123, sizeof(data2));
192 	}
193 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
194 	assert(num_layers * num_faces * layer_size <= sizeof(data2));
195 
196 	if (doPBO) {
197 		glGetTextureImage(name, 0, GL_RGBA, GL_UNSIGNED_BYTE,
198 			layer_size * num_faces * num_layers, NULL);
199 	} else {
200 		glGetTextureImage(name, 0, GL_RGBA, GL_UNSIGNED_BYTE,
201 			layer_size * num_faces * num_layers, data2);
202 	}
203 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
204 
205 	if (doPBO)
206 		dataGet = (GLubyte *) glMapBufferRange(
207 					       GL_PIXEL_PACK_BUFFER, 0,
208 					       layer_size * num_layers *
209 					       num_faces,
210 					       GL_MAP_READ_BIT);
211 	else
212 		dataGet = data2[0];
213 
214 	for (i = 0; i < num_faces * num_layers; i++) {
215 		pass = compare_layer(i, layer_size, tolerance, dataGet,
216 				     data[i]) && pass;
217 		dataGet += layer_size;
218 	}
219 
220 	if (doPBO) {
221 		glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
222 		glDeleteBuffers(1, &packPBO);
223 	}
224 
225 	glDeleteTextures(1, &name);
226 
227 	return pass;
228 }
229 
230 struct target_and_mask {
231 	GLenum target;
232 	bool mask;
233 };
234 
235 static struct target_and_mask targets[] = {
236 	{GL_TEXTURE_1D, 1},
237 	{GL_TEXTURE_2D, 1},
238 	{GL_TEXTURE_3D, 1},
239 	{GL_TEXTURE_RECTANGLE, 1},
240 	{GL_TEXTURE_CUBE_MAP, 1},
241 	{GL_TEXTURE_1D_ARRAY, 1},
242 	{GL_TEXTURE_2D_ARRAY, 1},
243 	{GL_TEXTURE_CUBE_MAP_ARRAY, 1},
244 };
245 
246 static void
clear_target_mask(GLenum target)247 clear_target_mask(GLenum target)
248 {
249 	int i;
250 	for (i = 0; i < ARRAY_SIZE(targets); ++i) {
251 		if (targets[i].target == target) {
252 			targets[i].mask = 0;
253 		}
254 	}
255 }
256 
257 void
piglit_init(int argc,char ** argv)258 piglit_init(int argc, char **argv)
259 {
260 	piglit_require_extension("GL_ARB_direct_state_access");
261 	piglit_require_extension("GL_ARB_texture_storage");
262 
263 	if (!piglit_is_extension_supported("GL_ARB_texture_rectangle"))
264 		clear_target_mask(GL_TEXTURE_RECTANGLE);
265 	if (!piglit_is_extension_supported("GL_EXT_texture_array")) {
266 		clear_target_mask(GL_TEXTURE_1D_ARRAY);
267 		clear_target_mask(GL_TEXTURE_2D_ARRAY);
268 	}
269 	if (!piglit_is_extension_supported("GL_ARB_texture_cube_map_array"))
270 		clear_target_mask(GL_TEXTURE_CUBE_MAP_ARRAY);
271 }
272 
273 enum piglit_result
piglit_display(void)274 piglit_display(void)
275 {
276 	int i;
277 	bool pass = true;
278 	GLenum internalformat = GL_RGBA8;
279 	int tolerance = 0;
280 	GLubyte data[18][IMAGE_SIZE];
281 
282 	init_layer_data(data[0], 18);
283 
284 	for (i = 0; i < ARRAY_SIZE(targets); ++i) {
285 		if (!targets[i].mask)
286 			continue;
287 
288 		printf("Testing %s into PBO\n",
289 			piglit_get_gl_enum_name(targets[i].target));
290 		pass = getTexImage(true, targets[i].target, data,
291 				    internalformat, tolerance)
292 			&& pass;
293 
294 		printf("Testing %s into client array\n",
295 			piglit_get_gl_enum_name(targets[i].target));
296 		pass = getTexImage(false, targets[i].target, data,
297 				    internalformat, tolerance)
298 			&& pass;
299 
300 		pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
301 	}
302 
303 	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
304 }
305 
306