1 /*
2  * Copyright (c) 2011 VMware, Inc.
3  * Copyright (c) 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  * on the rights to use, copy, modify, merge, publish, distribute, sub
9  * license, and/or sell copies of the Software, and to permit persons to whom
10  * the 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,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NON-INFRINGEMENT.  IN NO EVENT SHALL VMWARE AND/OR THEIR SUPPLIERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 
27 /**
28  * @file gettextureimage-formats.c
29  */
30 
31 
32 #include "piglit-util-gl.h"
33 #include "../fbo/fbo-formats.h"
34 #include "dsa-utils.h"
35 
36 PIGLIT_GL_TEST_CONFIG_BEGIN
37 
38 	config.supports_gl_compat_version = 20;
39 	config.supports_gl_core_version = 31;
40 
41 	config.window_width = 600;
42 	config.window_height = 200;
43 	config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE;
44 	config.khr_no_error_support = PIGLIT_NO_ERRORS;
45 
46 PIGLIT_GL_TEST_CONFIG_END
47 
48 static const char *TestName = "gettextureimage-formats";
49 
50 static const GLfloat clearColor[4] = { 0.4, 0.4, 0.4, 0.0 };
51 static GLuint texture_id;
52 static GLuint prog;
53 static bool init_by_rendering;
54 
55 #define TEX_SIZE 128
56 
57 #define DO_BLEND 1
58 
59 
60 /**
61  * Make a simple texture image where red increases from left to right,
62  * green increases from bottom to top, blue stays constant (50%) and
63  * the alpha channel is a checkerboard pattern.
64  * \return true for success, false if unsupported format
65  */
66 static bool
make_texture_image(GLenum intFormat,GLubyte upperRightTexel[4])67 make_texture_image(GLenum intFormat, GLubyte upperRightTexel[4])
68 {
69 	GLubyte tex[TEX_SIZE][TEX_SIZE][4];
70 	int i, j;
71 	GLuint fb, status;
72 
73 	for (i = 0; i < TEX_SIZE; i++) {
74 		for (j = 0; j < TEX_SIZE; j++) {
75 			tex[i][j][0] = j * 255 / TEX_SIZE;
76 			tex[i][j][1] = i * 255 / TEX_SIZE;
77 			tex[i][j][2] = 128;
78 			if (((i >> 4) ^ (j >> 4)) & 1)
79 				tex[i][j][3] = 255;  /* opaque */
80 			else
81 				tex[i][j][3] = 125;	/* transparent */
82 		}
83 	}
84 
85 	memcpy(upperRightTexel, tex[TEX_SIZE-1][TEX_SIZE-1], 4);
86 
87 	if (init_by_rendering) {
88 		/* Initialize the mipmap levels. */
89 		for (i = TEX_SIZE, j = 0; i; i >>= 1, j++) {
90 			glTexImage2D(GL_TEXTURE_2D, j, intFormat, i, i, 0,
91 				     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
92 		}
93 
94 		/* Initialize the texture with glDrawPixels. */
95 		glGenFramebuffers(1, &fb);
96 		glBindFramebuffer(GL_FRAMEBUFFER, fb);
97 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
98 				       GL_TEXTURE_2D, texture_id, 0);
99 		status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
100 		if (status != GL_FRAMEBUFFER_COMPLETE) {
101 			glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
102 			glDeleteFramebuffers(1, &fb);
103 			return false;
104 		}
105 
106 		glViewport(0, 0, TEX_SIZE, TEX_SIZE);
107 
108 		glWindowPos2iARB(0, 0);
109 		glDrawPixels(TEX_SIZE, TEX_SIZE, GL_RGBA, GL_UNSIGNED_BYTE, tex);
110 		glGenerateTextureMipmap(texture_id);
111 
112 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
113 		glDeleteFramebuffers(1, &fb);
114 		glViewport(0, 0, piglit_width, piglit_height);
115 	} else {
116 		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
117 		glTexImage2D(GL_TEXTURE_2D, 0, intFormat, TEX_SIZE, TEX_SIZE, 0,
118 			     GL_RGBA, GL_UNSIGNED_BYTE, tex);
119 	}
120 
121 	return glGetError() == GL_NO_ERROR;
122 }
123 
124 static GLfloat
ubyte_to_float(GLubyte b,GLint bits)125 ubyte_to_float(GLubyte b, GLint bits)
126 {
127 	if (bits <= 8) {
128 		GLint b2 = b >> (8 - bits);
129 		GLint max = 255 >> (8 - bits);
130 		return b2 / (float) max;
131 	} else {
132 		return b / 255.0;
133 	}
134 }
135 
136 
137 static GLfloat
bits_to_tolerance(GLint bits,bool compressed)138 bits_to_tolerance(GLint bits, bool compressed)
139 {
140 	GLfloat t;
141 
142 	if (bits == 0) {
143 		return 0.25;
144 	} else if (bits == 1) {
145 		return 0.5;
146 	} else if (bits > 8) {
147 		/* The original texture was specified as GLubyte and we
148 		 * assume that the window/surface is 8-bits/channel.
149 		 */
150 		t = 4.0 / 255;
151 	} else {
152 		t = 4.0 / (1 << (bits - 1));
153 	}
154 
155 	if (compressed) {
156 		/* Use a fudge factor.  The queries for GL_TEXTURE_RED/
157 		 * GREEN/BLUE/ALPHA_SIZE don't return well-defined values for
158 		 * compressed formats so using them is unreliable.  This is
159 		 * pretty loose, but good enough to catch some Mesa bugs during
160 		 * development.
161 		 */
162 		t = 0.3;
163 	}
164 	return t;
165 }
166 
167 
168 static void
compute_expected_color(const struct format_desc * fmt,const GLubyte upperRightTexel[4],GLfloat expected[4],GLfloat tolerance[4])169 compute_expected_color(const struct format_desc *fmt,
170 		       const GLubyte upperRightTexel[4],
171 		       GLfloat expected[4], GLfloat tolerance[4])
172 {
173 	GLfloat texel[4];
174 	GLint compressed;
175 	int bits[4];
176 
177 	bits[0] = bits[1] = bits[2] = bits[3] = 0;
178 
179 	/* Handle special cases first */
180 	if (fmt->internalformat == GL_R11F_G11F_B10F_EXT) {
181 		bits[0] = bits[1] = bits[2] = 8;
182 		bits[3] = 0;
183 		texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
184 		texel[1] = ubyte_to_float(upperRightTexel[1], bits[1]);
185 		texel[2] = ubyte_to_float(upperRightTexel[2], bits[2]);
186 		texel[3] = 1.0;
187 		compressed = GL_FALSE;
188 	} else {
189 		GLint r, g, b, a, l, i;
190 		GLenum baseFormat = 0;
191 
192 		glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_RED_SIZE, &r);
193 		glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_GREEN_SIZE, &g);
194 		glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BLUE_SIZE, &b);
195 		glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_ALPHA_SIZE, &a);
196 		glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_LUMINANCE_SIZE, &l);
197 		glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTENSITY_SIZE, &i);
198 		glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &compressed);
199 
200 		if (0)
201 			printf("r=%d g=%d b=%d a=%d l=%d i=%d\n", r, g, b, a, l, i);
202 
203 		if (i > 0) {
204 			baseFormat = GL_INTENSITY;
205 			bits[0] = i;
206 			bits[1] = 0;
207 			bits[2] = 0;
208 			bits[3] = i;
209 			texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
210 			texel[1] = 0.0;
211 			texel[2] = 0.0;
212 			texel[3] = ubyte_to_float(upperRightTexel[0], bits[3]);
213 		} else if (a > 0) {
214 			if (l > 0) {
215 				baseFormat = GL_LUMINANCE_ALPHA;
216 				bits[0] = l;
217 				bits[1] = 0;
218 				bits[2] = 0;
219 				bits[3] = a;
220 				texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
221 				texel[1] = 0.0;
222 				texel[2] = 0.0;
223 				texel[3] = ubyte_to_float(upperRightTexel[3], bits[3]);
224 			} else if (r > 0 && g > 0 && b > 0) {
225 				baseFormat = GL_RGBA;
226 				bits[0] = r;
227 				bits[1] = g;
228 				bits[2] = b;
229 				bits[3] = a;
230 				texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
231 				texel[1] = ubyte_to_float(upperRightTexel[1], bits[1]);
232 				texel[2] = ubyte_to_float(upperRightTexel[2], bits[2]);
233 				texel[3] = ubyte_to_float(upperRightTexel[3], bits[3]);
234 			} else if (r == 0 && g == 0 && b == 0) {
235 				baseFormat = GL_ALPHA;
236 				bits[0] = 0;
237 				bits[1] = 0;
238 				bits[2] = 0;
239 				bits[3] = a;
240 				texel[0] = 0.0;
241 				texel[1] = 0.0;
242 				texel[2] = 0.0;
243 				texel[3] = ubyte_to_float(upperRightTexel[3], bits[3]);
244 			} else {
245 				baseFormat = 0;  /* ??? */
246 				texel[0] = 0.0;
247 				texel[1] = 0.0;
248 				texel[2] = 0.0;
249 				texel[3] = 0.0;
250 			}
251 		} else if (l > 0) {
252 			baseFormat = GL_LUMINANCE;
253 			bits[0] = l;
254 			bits[1] = 0;
255 			bits[2] = 0;
256 			bits[3] = 0;
257 			texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
258 			texel[1] = 0.0;
259 			texel[2] = 0.0;
260 			texel[3] = 1.0;
261 		} else if (r > 0) {
262 			if (g > 0) {
263 				if (b > 0) {
264 					baseFormat = GL_RGB;
265 					bits[0] = r;
266 					bits[1] = g;
267 					bits[2] = b;
268 					bits[3] = 0;
269 					texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
270 					texel[1] = ubyte_to_float(upperRightTexel[1], bits[1]);
271 					texel[2] = ubyte_to_float(upperRightTexel[2], bits[2]);
272 					texel[3] = 1.0;
273 				} else {
274 					baseFormat = GL_RG;
275 					bits[0] = r;
276 					bits[1] = g;
277 					bits[2] = 0;
278 					bits[3] = 0;
279 					texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
280 					texel[1] = ubyte_to_float(upperRightTexel[1], bits[1]);
281 					texel[2] = 0.0;
282 					texel[3] = 1.0;
283 				}
284 			} else {
285 				baseFormat = GL_RED;
286 				bits[0] = r;
287 				bits[1] = 0;
288 				bits[2] = 0;
289 				bits[3] = 0;
290 				texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
291 				texel[1] = 0.0;
292 				texel[2] = 0.0;
293 				texel[3] = 1.0;
294 			}
295 		} else {
296 			assert(!"Unexpected texture component sizes");
297 			texel[0] = 0.0;
298 			texel[1] = 0.0;
299 			texel[2] = 0.0;
300 			texel[3] = 0.0;
301 		}
302 
303 		(void) baseFormat;  /* not used, at this time */
304 	}
305 
306 	/* compute texel color blended with background color */
307 #if DO_BLEND
308 	expected[0] = texel[0] * texel[3] + clearColor[0] * (1.0 - texel[3]);
309 	expected[1] = texel[1] * texel[3] + clearColor[1] * (1.0 - texel[3]);
310 	expected[2] = texel[2] * texel[3] + clearColor[2] * (1.0 - texel[3]);
311 	expected[3] = texel[3] * texel[3] + clearColor[3] * (1.0 - texel[3]);
312 #else
313         expected[0] = texel[0];
314         expected[1] = texel[1];
315         expected[2] = texel[2];
316         expected[3] = texel[3];
317 #endif
318 
319 	assert(expected[0] == expected[0]);
320 
321 	tolerance[0] = bits_to_tolerance(bits[0], compressed);
322 	tolerance[1] = bits_to_tolerance(bits[1], compressed);
323 	tolerance[2] = bits_to_tolerance(bits[2], compressed);
324 	tolerance[3] = bits_to_tolerance(bits[3], compressed);
325 }
326 
327 
328 static bool
colors_equal(const GLfloat expected[4],const GLfloat pix[4],GLfloat tolerance[4])329 colors_equal(const GLfloat expected[4], const GLfloat pix[4],
330 	     GLfloat tolerance[4])
331 {
332 	if (fabsf(expected[0] - pix[0]) > tolerance[0] ||
333 		 fabsf(expected[1] - pix[1]) > tolerance[1] ||
334 		 fabsf(expected[2] - pix[2]) > tolerance[2] ||
335 		 fabsf(expected[3] - pix[3]) > tolerance[3]) {
336 		return false;
337 	}
338 	return true;
339 }
340 
341 
342 static bool
test_format(const struct test_desc * test,const struct format_desc * fmt)343 test_format(const struct test_desc *test,
344 	    const struct format_desc *fmt)
345 {
346 	int x, y;
347 	int w = TEX_SIZE, h = TEX_SIZE;
348 	GLfloat readback[TEX_SIZE][TEX_SIZE][4];
349 	GLubyte upperRightTexel[4];
350 	int level;
351 	GLfloat expected[4], pix[4], tolerance[4];
352 	bool pass = true;
353 
354 	glClear(GL_COLOR_BUFFER_BIT);
355 
356 	/* The RGBA_DXT1 formats seem to expose a Mesa/libtxc_dxtn bug.
357 	 * Just skip them for now.  Testing the other compressed formats
358 	 * is good enough.
359 	 */
360 	if (fmt->internalformat != GL_COMPRESSED_RGBA_S3TC_DXT1_EXT &&
361 	    fmt->internalformat != GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) {
362 		/* init texture image */
363 		if (!make_texture_image(fmt->internalformat, upperRightTexel))
364 			return true; /* unsupported = OK */
365 
366 		x = 10;
367 		y = 40;
368 
369 		compute_expected_color(fmt, upperRightTexel, expected, tolerance);
370 
371 		/* Draw with the texture */
372 		glUseProgram(prog);
373 		dsa_set_xform(prog, piglit_width, piglit_height);
374 #if DO_BLEND
375 		glEnable(GL_BLEND);
376 #endif
377 		piglit_draw_rect_tex(x, y, w, h,  0.0, 0.0, 1.0, 1.0);
378 		glUseProgram(0);
379 		glDisable(GL_BLEND);
380 
381 		x += TEX_SIZE + 20;
382 
383 		level = 0;
384 		while (w > 0) {
385 			/* Get the texture image */
386 			glGetTextureImage(texture_id, level, GL_RGBA,
387 					  GL_FLOAT, sizeof(readback),
388 					  readback);
389 
390 			/* Draw the texture image */
391 			glWindowPos2iARB(x, y);
392 #if DO_BLEND
393 			glEnable(GL_BLEND);
394 #endif
395 			glDrawPixels(w, h, GL_RGBA, GL_FLOAT, readback);
396 			glDisable(GL_BLEND);
397 
398 			if (level <= 2) {
399 				GLint rx = x + w-1;
400 				GLint ry = y + h-1;
401 				glReadPixels(rx, ry, 1, 1, GL_RGBA, GL_FLOAT, pix);
402 				if (!colors_equal(expected, pix, tolerance)) {
403 					printf("%s failure: format: %s, level %d at pixel(%d, %d)\n",
404 					       TestName,
405 					       get_format_name(
406 						       fmt->internalformat),
407 					       level, rx, ry);
408 					printf(" Expected (%f, %f, %f, %f)\n",
409 							 expected[0], expected[1], expected[2], expected[3]);
410 					printf("	 Found (%f, %f, %f, %f)\n",
411 							 pix[0], pix[1], pix[2], pix[3]);
412 					printf("Tolerance (%f, %f, %f, %f)\n",
413 							 tolerance[0], tolerance[1], tolerance[2], tolerance[3]);
414 					pass = false;
415 				}
416 			}
417 
418 			x += w + 20;
419 			w /= 2;
420 			h /= 2;
421 			level++;
422 		}
423 
424 	}
425 
426 	piglit_present_results();
427 
428 	return pass;
429 }
430 
431 
432 /**
433  * Is the given set of formats supported?
434  * This checks if required extensions are present and if this piglit test
435  * can actually grok the formats.
436  */
437 static bool
supported_format_set(const struct test_desc * set)438 supported_format_set(const struct test_desc *set)
439 {
440 	if (!supported(set))
441 		return false;
442 
443 	if (set->format == ext_texture_integer ||
444 	    set->format == ext_packed_depth_stencil ||
445 	    set->format == arb_texture_rg_int ||
446 	    set->format == arb_depth_texture ||
447 	    set->format == arb_depth_buffer_float) {
448 		/* texture_integer requires a fragment shader, different
449 		 * glTexImage calls.  Depth/stencil formats not implemented.
450 		 */
451 		return false;
452 	}
453 
454 	return true;
455 }
456 
457 
458 static bool
test_all_formats(void)459 test_all_formats(void)
460 {
461 	bool pass = true;
462 	int i, j;
463 
464 	for (i = 0; i < ARRAY_SIZE(test_sets); i++) {
465 		const struct test_desc *set = &test_sets[i];
466 		if (supported_format_set(set)) {
467 			for (j = 0; j < set->num_formats; j++) {
468 				if (!test_format(set, &set->format[j])) {
469 					pass = false;
470 				}
471 			}
472 		}
473 	}
474 
475 	return pass;
476 }
477 
478 
479 enum piglit_result
piglit_display(void)480 piglit_display(void)
481 {
482 	bool pass;
483 
484 	piglit_ortho_projection(piglit_width, piglit_height, false);
485 
486 	if (piglit_automatic) {
487 		pass = test_all_formats();
488 	} else {
489 		const struct test_desc *set = &test_sets[test_index];
490 		if (supported_format_set(set)) {
491 			pass = test_format(set, &set->format[format_index]);
492 		} else {
493 			/* unsupported format - not a failure */
494 			pass = true;
495 			glClear(GL_COLOR_BUFFER_BIT);
496 			piglit_present_results();
497 		}
498 	}
499 
500 	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
501 }
502 
503 void
piglit_init(int argc,char ** argv)504 piglit_init(int argc, char **argv)
505 {
506 	int i;
507 
508 	piglit_require_extension("GL_ARB_direct_state_access");
509 
510 	fbo_formats_init(1, argv, !piglit_automatic);
511 	(void) fbo_formats_display;
512 
513 	for (i = 1; i < argc; i++) {
514 		if (strcmp(argv[i], "init-by-rendering") == 0) {
515 			init_by_rendering = true;
516 			puts("The textures will be initialized by rendering "
517 			     "to them using glDrawPixels.");
518 			break;
519 		}
520 	}
521 
522 	glGenTextures(1, &texture_id);
523 	glBindTexture(GL_TEXTURE_2D, texture_id);
524 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
525 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
526 
527 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
528 
529 	glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
530 
531 	prog = dsa_create_program(GL_TEXTURE_2D);
532 }
533