arb_copy_image: test copying of different mipmap levels of a texture
[piglit.git] / tests / fbo / fbo-generatemipmap-cubemap.c
blob963825d5420984b2e26fdf17f753ba104f1f9339
1 /*
2 * Copyright © 2014 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
23 * Authors:
24 * Marek Olšák <maraeo@gmail.com>
27 #include "piglit-util-gl.h"
29 #define TEX_SIZE 32
30 #define TEX_HALF (TEX_SIZE / 2)
31 #define TEX_LEVELS 6
33 #define DRAW_SIZE 32
35 PIGLIT_GL_TEST_CONFIG_BEGIN
37 config.supports_gl_compat_version = 20;
39 config.window_width = 680;
40 config.window_height = 620;
41 config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGBA;
42 config.khr_no_error_support = PIGLIT_NO_ERRORS;
44 PIGLIT_GL_TEST_CONFIG_END
46 static const char *fs_cube =
47 "uniform samplerCube tex; \n"
48 "void main() \n"
49 "{ \n"
50 " gl_FragColor = textureCube(tex, gl_TexCoord[0].xyz); \n"
51 "} \n";
53 static const char *fs_cube_array =
54 "#version 130\n"
55 "#extension GL_ARB_texture_cube_map_array : enable\n"
56 "uniform samplerCubeArray tex; \n"
57 "void main() \n"
58 "{ \n"
59 " gl_FragColor = texture(tex, gl_TexCoord[0]); \n"
60 "} \n";
62 static GLboolean test_array;
63 static GLenum target;
64 static GLenum num_layers;
65 static GLuint prog;
66 static GLenum format;
68 static float colors[][4] = {
69 {0.0, 0.0, 0.0, 1.0},
70 {1.0, 0.0, 0.0, 1.0},
71 {0.0, 1.0, 0.0, 1.0},
72 {1.0, 1.0, 0.0, 1.0},
73 {0.0, 0.0, 1.0, 1.0},
74 {1.0, 0.0, 1.0, 1.0},
75 {0.0, 1.0, 1.0, 1.0},
77 #define NUM_COLORS ARRAY_SIZE(colors)
79 static void
80 load_texcube(void)
82 float *p = malloc(TEX_SIZE * TEX_SIZE * num_layers * 4 * sizeof(float));
83 int x,y,z;
85 for (z = 0; z < num_layers; z++) {
86 for (y = 0; y < TEX_SIZE; y++) {
87 for (x = 0; x < TEX_SIZE; x++) {
88 int quadrant = y < TEX_SIZE/2 ? (x < TEX_SIZE/2 ? 0 : 1) :
89 (x < TEX_SIZE/2 ? 2 : 3);
90 float *dest = &p[(z*TEX_SIZE*TEX_SIZE + y*TEX_SIZE + x)*4];
92 memcpy(dest, colors[(z + quadrant*2) % NUM_COLORS],
93 4 * sizeof(float));
98 if (test_array) {
99 glTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, 0, 0, 0,
100 TEX_SIZE, TEX_SIZE, num_layers, GL_RGBA, GL_FLOAT, p);
102 else {
103 int i;
105 for (i = 0; i < 6; i++) {
106 glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0,
107 TEX_SIZE, TEX_SIZE, GL_RGBA, GL_FLOAT,
108 p + i*TEX_SIZE*TEX_SIZE*4);
111 free(p);
114 static GLuint
115 create_texcube(void)
117 GLuint tex, fb;
118 GLenum status;
119 int layer;
121 glGenTextures(1, &tex);
122 glBindTexture(target, tex);
123 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
124 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
125 if (test_array)
126 glTexStorage3D(target, TEX_LEVELS, format,
127 TEX_SIZE, TEX_SIZE, num_layers);
128 else
129 glTexStorage2D(target, TEX_LEVELS, format,
130 TEX_SIZE, TEX_SIZE);
132 glGenFramebuffers(1, &fb);
133 glBindFramebuffer(GL_FRAMEBUFFER, fb);
135 for (layer = 0; layer < num_layers; layer++) {
136 if (test_array)
137 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
138 tex, 0, layer);
139 else
140 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
141 GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer,
142 tex, 0);
144 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
145 if (status != GL_FRAMEBUFFER_COMPLETE) {
146 load_texcube();
147 goto done;
150 glViewport(0, 0, TEX_SIZE, TEX_SIZE);
151 piglit_ortho_projection(TEX_SIZE, TEX_SIZE, GL_FALSE);
153 glColor4fv(colors[(layer + 0) % NUM_COLORS]);
154 piglit_draw_rect(0, 0, TEX_HALF, TEX_HALF);
156 glColor4fv(colors[(layer + 2) % NUM_COLORS]);
157 piglit_draw_rect(TEX_HALF, 0, TEX_HALF, TEX_HALF);
159 glColor4fv(colors[(layer + 4) % NUM_COLORS]);
160 piglit_draw_rect(0, TEX_HALF, TEX_HALF, TEX_HALF);
162 glColor4fv(colors[(layer + 6) % NUM_COLORS]);
163 piglit_draw_rect(TEX_HALF, TEX_HALF, TEX_HALF, TEX_HALF);
166 done:
167 glGenerateMipmap(target);
168 glDeleteFramebuffers(1, &fb);
169 return tex;
172 #define FACE(x) (GL_TEXTURE_CUBE_MAP_##x - GL_TEXTURE_CUBE_MAP_POSITIVE_X)
174 static void
175 piglit_draw_rect_face(float x, float y, float w, float h, int face, int cube_layer)
177 float verts[4][4];
178 float tex[4][4];
179 float sign = face % 2 ? -1 : 1;
181 verts[0][0] = x;
182 verts[0][1] = y;
183 verts[0][2] = 0.0;
184 verts[0][3] = 1.0;
185 verts[1][0] = x + w;
186 verts[1][1] = y;
187 verts[1][2] = 0.0;
188 verts[1][3] = 1.0;
189 verts[2][0] = x + w;
190 verts[2][1] = y + h;
191 verts[2][2] = 0.0;
192 verts[2][3] = 1.0;
193 verts[3][0] = x;
194 verts[3][1] = y + h;
195 verts[3][2] = 0.0;
196 verts[3][3] = 1.0;
198 switch (face) {
199 case FACE(POSITIVE_X):
200 case FACE(NEGATIVE_X):
201 tex[0][0] = sign;
202 tex[1][0] = sign;
203 tex[2][0] = sign;
204 tex[3][0] = sign;
206 tex[3][1] = -1 * sign;
207 tex[3][2] = 1;
209 tex[0][1] = -1 * sign;
210 tex[0][2] = -1;
212 tex[1][1] = 1 * sign;
213 tex[1][2] = -1;
215 tex[2][1] = 1 * sign;
216 tex[2][2] = 1;
217 break;
219 case FACE(POSITIVE_Y):
220 case FACE(NEGATIVE_Y):
221 tex[0][1] = sign;
222 tex[1][1] = sign;
223 tex[2][1] = sign;
224 tex[3][1] = sign;
226 tex[0][0] = 1 * sign;
227 tex[0][2] = -1;
229 tex[1][0] = -1 * sign;
230 tex[1][2] = -1;
232 tex[2][0] = -1 * sign;
233 tex[2][2] = 1;
235 tex[3][0] = 1 * sign;
236 tex[3][2] = 1;
237 break;
239 case FACE(POSITIVE_Z):
240 case FACE(NEGATIVE_Z):
241 tex[0][2] = sign;
242 tex[1][2] = sign;
243 tex[2][2] = sign;
244 tex[3][2] = sign;
246 tex[0][0] = 1;
247 tex[0][1] = 1 * sign;
249 tex[1][0] = -1;
250 tex[1][1] = 1 * sign;
252 tex[2][0] = -1;
253 tex[2][1] = -1 * sign;
255 tex[3][0] = 1;
256 tex[3][1] = -1 * sign;
257 break;
259 default:
260 assert(0);
263 tex[0][3] = cube_layer;
264 tex[1][3] = cube_layer;
265 tex[2][3] = cube_layer;
266 tex[3][3] = cube_layer;
268 glVertexPointer(4, GL_FLOAT, 0, verts);
269 glTexCoordPointer(4, GL_FLOAT, 0, tex);
270 glEnableClientState(GL_VERTEX_ARRAY);
271 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
273 glDrawArrays(GL_QUADS, 0, 4);
275 glDisableClientState(GL_VERTEX_ARRAY);
276 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
279 static void
280 draw_face(int face, int cube_layer, int x, int y)
282 int loc;
284 glUseProgram(prog);
285 loc = glGetUniformLocation(prog, "tex");
286 glUniform1i(loc, 0); /* texture unit p */
288 glViewport(0, 0, piglit_width, piglit_height);
289 piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
291 glBindFramebuffer(GL_FRAMEBUFFER, piglit_winsys_fbo);
293 piglit_draw_rect_face(x, y, DRAW_SIZE, DRAW_SIZE, face, cube_layer);
294 glUseProgram(0);
297 static void
298 draw_cube(int x, int y, int level, int cube_layer)
300 glTexParameteri(target, GL_TEXTURE_MIN_LOD, level);
301 glTexParameteri(target, GL_TEXTURE_MAX_LOD, level);
303 draw_face(FACE(POSITIVE_X), cube_layer, x, y+DRAW_SIZE);
304 draw_face(FACE(POSITIVE_Y), cube_layer, x+DRAW_SIZE, y+DRAW_SIZE);
305 draw_face(FACE(NEGATIVE_X), cube_layer, x+DRAW_SIZE*2, y+DRAW_SIZE);
306 draw_face(FACE(NEGATIVE_Y), cube_layer, x+DRAW_SIZE*3, y+DRAW_SIZE);
307 draw_face(FACE(POSITIVE_Z), cube_layer, x+DRAW_SIZE, y+DRAW_SIZE*2);
308 draw_face(FACE(NEGATIVE_Z), cube_layer, x+DRAW_SIZE, y);
311 static void
312 draw_mipmap_tree(int x, int y)
314 int i,j;
316 for (i = 0; i < TEX_LEVELS; i++) {
317 int cubes = num_layers / 6;
319 for (j = 0; j < cubes; j++) {
320 draw_cube(x + j*(DRAW_SIZE * 4 + 5),
321 y + i*(DRAW_SIZE * 3 + 5), i, j);
326 static bool
327 test_face(int face, int level, int cube, float *observed)
329 int size = TEX_SIZE >> level;
330 int layer = cube*6 + face;
331 int x,y,i,c;
332 bool pass = true;
333 float *e;
335 e = malloc(size * size * 4 * sizeof(float));
337 if (size == 1) {
338 memset(e, 0, 4 * sizeof(float));
340 for (i = 0; i < 4; i++)
341 for (c = 0; c < 4; c++)
342 e[c] += colors[(layer + i*2) % NUM_COLORS][c] * 0.25;
344 else {
345 for (y = 0; y < size; y++) {
346 for (x = 0; x < size; x++) {
347 int quadrant = y < size/2 ? (x < size/2 ? 0 : 1) :
348 (x < size/2 ? 2 : 3);
349 float *color = colors[(layer + quadrant*2) % NUM_COLORS];
351 memcpy(&e[(y*size+x)*4], color, sizeof(float) * 4);
357 for (y = 0; y < size; y++) {
358 for (x = 0; x < size; x++) {
359 float *probe = &observed[(y*size+x)*4];
360 float *expected = &e[(y*size+x)*4];
362 for (i = 0; i < 4; ++i) {
363 if (fabs(probe[i] - expected[i]) >= piglit_tolerance[i]) {
364 printf("Probe color at (%i,%i)\n", x, y);
365 printf(" Expected: %f %f %f %f\n",
366 expected[0], expected[1], expected[2], expected[3]);
367 printf(" Observed: %f %f %f %f\n",
368 probe[0], probe[1], probe[2], probe[3]);
369 printf(" when testing face %i, level %i, cube %i\n",
370 face, level, cube);
371 pass = false;
372 goto done;
378 done:
379 free(e);
380 return pass;
383 static bool
384 test_mipmap_tree(void)
386 bool pass = true;
387 int layer, level;
389 for (level = 0; level < TEX_LEVELS; level++) {
390 int size = TEX_SIZE >> level;
391 float *observed;
393 /* With a compressed texture, skip checking the second and
394 * third last levels, because one DXTC block cannot contain
395 * more than 2 colors.
397 * However, always test the last level, which should only
398 * contain one color, which is the average of all 4.
400 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT &&
401 level >= TEX_LEVELS-3 && level <= TEX_LEVELS-2)
402 continue;
404 if (test_array) {
405 observed = malloc(num_layers * size * size * 4 * sizeof(float));
406 glGetTexImage(target, level, GL_RGBA, GL_FLOAT, observed);
408 for (layer = 0; layer < num_layers; layer++) {
409 pass = pass && test_face(layer % 6, level, layer / 6,
410 observed + layer * size * size * 4);
413 free(observed);
415 else {
416 for (layer = 0; layer < num_layers; layer++) {
417 observed = malloc(size * size * 4 * sizeof(float));
418 glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer,
419 level, GL_RGBA, GL_FLOAT, observed);
421 pass = pass && test_face(layer, level, 0, observed);
423 free(observed);
428 return pass;
431 enum piglit_result
432 piglit_display(void)
434 GLboolean pass = GL_TRUE;
435 GLuint tex;
437 glClear(GL_COLOR_BUFFER_BIT);
439 tex = create_texcube();
441 draw_mipmap_tree(5, 5);
443 pass = test_mipmap_tree();
445 glDeleteTextures(1, &tex);
446 piglit_present_results();
447 return pass ? PIGLIT_PASS : PIGLIT_FAIL;
450 void piglit_init(int argc, char **argv)
452 int i;
454 piglit_require_extension("GL_ARB_framebuffer_object");
455 piglit_require_extension("GL_ARB_texture_storage");
456 piglit_require_GLSL_version(120);
458 format = GL_RGBA8;
459 target = GL_TEXTURE_CUBE_MAP;
460 num_layers = 6;
462 for (i = 1; i < argc; i++) {
463 if (strcmp(argv[i], "array") == 0) {
464 piglit_require_GLSL_version(130);
465 piglit_require_extension("GL_ARB_texture_cube_map_array");
466 test_array = GL_TRUE;
467 target = GL_TEXTURE_CUBE_MAP_ARRAY;
468 num_layers = 6 * 5;
470 else if (strcmp(argv[i], "RGB9_E5") == 0) {
471 /* Test a non-renderable format. */
472 piglit_require_extension("GL_EXT_texture_shared_exponent");
473 format = GL_RGB9_E5;
475 else if (strcmp(argv[i], "S3TC_DXT1") == 0) {
476 /* Test a compressed format. */
477 piglit_require_extension("GL_EXT_texture_compression_s3tc");
478 format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
479 piglit_set_tolerance_for_bits(5, 6, 5, 8);
481 else {
482 assert(0);
486 prog = piglit_build_simple_program(NULL, test_array ? fs_cube_array :
487 fs_cube);
489 glClearColor(0.25, 0.25, 0.25, 0.25);