1 /*
2  * Copyright (c) 2011 VMware, Inc.
3  * Copyright © 2015 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  * Test rendering to a depth texture, sampling from it, and comparing the
27  * texture depth values against the fragment Z values when drawing the
28  * same object a second time.
29  *
30  * The left side of the window should be mostly black.  Red pixels indicate
31  * errors.
32  * The center and right parts of the window should show gray-scale spheres
33  * on a white background (they're just Z buffer images as gray-scale).
34  *
35  * Brian Paul
36  * 17 Feb 2011
37  */
38 
39 
40 #include <assert.h>
41 #include "piglit-util-gl.h"
42 
43 /** Set DEBUG to 1 to enable extra output when trying to debug failures */
44 #define DEBUG 0
45 
46 #define SIZE 256
47 
48 PIGLIT_GL_TEST_CONFIG_BEGIN
49 
50 	config.supports_gl_compat_version = 10;
51 
52 	config.window_width = 3*SIZE;
53 	config.window_height = SIZE;
54 	config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_DEPTH;
55 	config.khr_no_error_support = PIGLIT_NO_ERRORS;
56 
57 PIGLIT_GL_TEST_CONFIG_END
58 
59 static GLfloat ErrorScale = 0.0;
60 static GLuint ColorTex, DepthTex, FBO;
61 static GLuint ShaderProg;
62 static GLint Zbits;
63 static GLenum TexTarget = GL_TEXTURE_2D;
64 
65 
66 static void
create_fbo(void)67 create_fbo(void)
68 {
69    GLenum depthIntFormat = GL_DEPTH_COMPONENT24;
70    GLenum status;
71 
72    /* depth texture */
73    glGenTextures(1, &DepthTex);
74    glBindTexture(TexTarget, DepthTex);
75    glTexParameteri(TexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
76    glTexParameteri(TexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
77    glTexImage2D(TexTarget, 0, depthIntFormat,
78                 SIZE, SIZE, 0,
79                 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
80    if (!piglit_check_gl_error(GL_NO_ERROR))
81            piglit_report_result(PIGLIT_FAIL);
82    glGetTexLevelParameteriv(TexTarget, 0, GL_TEXTURE_DEPTH_SIZE, &Zbits);
83 
84    /* color texture */
85    glGenTextures(1, &ColorTex);
86    glBindTexture(TexTarget, ColorTex);
87    glTexParameteri(TexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
88    glTexParameteri(TexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
89    glTexImage2D(TexTarget, 0, GL_RGBA,
90                 SIZE, SIZE, 0,
91                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
92    if (!piglit_check_gl_error(GL_NO_ERROR))
93 	    piglit_report_result(PIGLIT_FAIL);
94 
95    /* Create FBO */
96    glGenFramebuffersEXT(1, &FBO);
97    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
98 
99    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
100                              GL_COLOR_ATTACHMENT0_EXT,
101                              TexTarget,
102                              ColorTex,
103                              0);
104 
105    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
106                              GL_DEPTH_ATTACHMENT_EXT,
107                              TexTarget,
108                              DepthTex,
109                              0);
110 
111    if (!piglit_check_gl_error(GL_NO_ERROR))
112 	    piglit_report_result(PIGLIT_FAIL);
113 
114    status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
115    if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
116       piglit_report_result(PIGLIT_SKIP);
117    }
118 }
119 
120 
121 static void
create_frag_shader(void)122 create_frag_shader(void)
123 {
124    /* This shader samples the currently bound depth texture, then compares
125     * that value to the current fragment Z value to produce a shade of red
126     * indicating error/difference.
127     *
128     * E.g:  gl_FragColor = scale * abs(texture.Z - fragment.Z);
129     *
130     * Note that we have to be pretty careful with converting gl_FragCoord
131     * into a 2D texture coordinate.  There's a -0.5 bias and scale factor.
132     */
133    static const char *text_2d =
134       "uniform sampler2D zTex; \n"
135       "uniform float sizeScale; \n"
136       "uniform float errorScale; \n"
137       "void main() \n"
138       "{ \n"
139       "   vec2 coord = (gl_FragCoord.xy - vec2(0.5)) / sizeScale; \n"
140       "   vec4 z = texture2D(zTex, coord); \n"
141       "   float diff = errorScale * abs(z.r - gl_FragCoord.z); \n"
142       "   //gl_FragColor = vec4(gl_FragCoord.z, 0, 0, 0); \n"
143       "   //gl_FragColor = z; \n"
144       "   gl_FragColor = vec4(diff, 0, 0, 0); \n"
145       "   gl_FragDepth = gl_FragCoord.z; \n"
146       "} \n";
147    static const char *text_rect =
148       "#extension GL_ARB_texture_rectangle: require \n"
149       "uniform sampler2DRect zTex; \n"
150       "uniform float sizeScale; \n"
151       "uniform float errorScale; \n"
152       "void main() \n"
153       "{ \n"
154       "   vec2 coord = gl_FragCoord.xy; \n"
155       "   vec4 z = texture2DRect(zTex, coord); \n"
156       "   float diff = errorScale * abs(z.r - gl_FragCoord.z); \n"
157       "   //gl_FragColor = vec4(gl_FragCoord.z, 0, 0, 0); \n"
158       "   //gl_FragColor = z; \n"
159       "   gl_FragColor = vec4(diff, 0, 0, 0); \n"
160       "   gl_FragDepth = gl_FragCoord.z; \n"
161       "} \n";
162    GLint zTex, errorScale, sizeScale;
163    const char *const fs_source = (TexTarget == GL_TEXTURE_2D)
164 	   ? text_2d : text_rect;
165 
166    ShaderProg = piglit_build_simple_program(NULL, fs_source);
167    assert(ShaderProg);
168 
169    glUseProgram(ShaderProg);
170 
171    zTex = glGetUniformLocation(ShaderProg, "zTex");
172    glUniform1i(zTex, 0);  /* unit 0 */
173 
174    errorScale = glGetUniformLocation(ShaderProg, "errorScale");
175    glUniform1f(errorScale, ErrorScale);
176 
177    sizeScale = glGetUniformLocation(ShaderProg, "sizeScale");
178    glUniform1f(sizeScale, (float) (SIZE - 1));
179 
180    glUseProgram(0);
181 }
182 
183 
184 #if DEBUG
185 static void
find_float_min_max_center(const GLfloat * buf,GLuint n,GLfloat * min,GLfloat * max,GLfloat * center)186 find_float_min_max_center(const GLfloat *buf, GLuint n,
187 			  GLfloat *min, GLfloat *max, GLfloat *center)
188 {
189    GLint cx = SIZE/4, cy = SIZE/4;
190    GLuint i;
191 
192    *min = 1.0e20;
193    *max = -1.0e20;
194 
195    for (i = 0; i < n; i++) {
196       if (buf[i] != 1.0) {
197          if (buf[i] < *min)
198             *min = buf[i];
199          if (buf[i] > *max)
200             *max = buf[i];
201       }
202    }
203 
204    *center = buf[cy * SIZE + cx];
205 }
206 
207 static void
find_uint_min_max_center(const GLuint * buf,GLuint n,GLuint * min,GLuint * max,GLuint * center)208 find_uint_min_max_center(const GLuint *buf, GLuint n,
209 			 GLuint *min, GLuint *max, GLuint *center)
210 {
211    GLint cx = SIZE/4, cy = SIZE/4;
212    GLuint i;
213 
214    *min = ~0U;
215    *max = 0;
216 
217    for (i = 0; i < n; i++) {
218       if (buf[i] != ~0U) {
219          if (buf[i] < *min)
220             *min = buf[i];
221          if (buf[i] > *max)
222             *max = buf[i];
223       }
224    }
225 
226    *center = buf[cy * SIZE + cx];
227 }
228 #endif /* DEBUG */
229 
230 
231 static void
draw_sphere(void)232 draw_sphere(void)
233 {
234    /* Without this enum hack, GCC complains about variable length arrays
235     * below... even if you make the variables const.
236     */
237    enum {
238       slices = 40,
239       stacks = 20,
240 
241       /* There are (stacks - 1) interior stacks (see the comment before y
242        * below).  Each interior stack is (slices + 1) vertices.  There is on
243        * additional vertex at the top, and there is one at the bottom.
244        */
245       num_vertices = (stacks - 1) * (slices + 1) + 2,
246 
247       /* Each slice is a single triangle strip.  There is a triangle at the
248        * top (3 elements), and there is one at the bottom (1 element).
249        * Between is (stacks - 2) quadrilaterals (2 elements each).
250        */
251       elements_per_slice = 3 + ((stacks - 2) * 2) + 1,
252    };
253 
254    const GLdouble radius = 0.95;
255    unsigned i;
256 
257    static float vertex_data[num_vertices * 4];
258    static unsigned element_data[elements_per_slice * slices];
259    static bool generated = false;
260 
261    if (!generated) {
262       float *v = vertex_data;
263       unsigned *e = element_data;
264       unsigned j;
265 
266       assert(num_vertices < 65535);
267 
268       for (i = 1; i < stacks; i++) {
269 	 /* The y values of the sphere interpolate from -radius to radius.
270 	  * The two extrema have a single point (in terms of the "circular
271 	  * slice" mentioned below, r_c = 0).  Those points are generated at
272 	  * the very end.  If there are N slices of the sphere, there are N+1
273 	  * layers of data.  This loop generates data for layers 1 through
274 	  * N-1, inclusive.  Layers 0 and N are the extrema previously
275 	  * mentioned.
276 	  *
277 	  * NOTE: Then angle range from the north pole to the south pole is
278 	  * PI.  When going around the equator (inner loop below), the angle
279 	  * range is 0 to 2PI.
280 	  */
281 	 const double y = -cos(i * M_PI / stacks) * radius;
282 
283 	 /* The radius of the sphere is, r_s, sqrt(x**2 + y**2 + z**2).  The
284 	  * radius of the circular slice of the sphere parallel to the X/Z
285 	  * plane, r_c, is sqrt(x**2 + z**2).  r_s and y are known.  Solve for
286 	  * r_c.
287 	  *
288 	  *     r_s**2 = x**2 + y**2 + z**2
289 	  *     r_s**2 = r_c**2 + y**2
290 	  *     r_c**2 = r_s**2 - y**2
291 	  *     r_c = sqrt(r_s**2 - y**2)
292 	  */
293 	 const double r_c = sqrt((radius * radius) - (y * y));
294 
295 	 for (j = 0; j <= slices; j++) {
296 	    const double angle = j * 2.0 * M_PI / slices;
297 
298 	    v[0] = r_c * sin(angle);
299 	    v[1] = y;
300 	    v[2] = r_c * cos(angle);
301 	    v[3] = 1.0;
302 
303 	    assert(fabs(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] -
304 			radius * radius) < 1e-6);
305 	    v += 4;
306 	    assert(v < &vertex_data[ARRAY_SIZE(vertex_data)]);
307 	 }
308       }
309 
310       v[0] = 0.0;
311       v[1] = -radius;
312       v[2] = 0.0;
313       v[3] = 1.0;
314 
315       v[4] = 0.0;
316       v[5] = radius;
317       v[6] = 0.0;
318       v[7] = 1.0;
319       assert(&v[8] == &vertex_data[ARRAY_SIZE(vertex_data)]);
320 
321       for (i = 0; i < slices; i++) {
322 	 /* The outer loop walks around the first circluar slice of vertex
323 	  * data.  This occupies vertices [0, slices].  Looking at the sphere,
324 	  * there is a vertex on the left side of the polygon being emitted,
325 	  * and the next vertex in the sequence is on the right.
326 	  */
327 	 unsigned left = i;
328 
329 	 /* Emit the "base" triangle. */
330 	 e[0] = num_vertices - 2;
331 	 e++;
332 	 assert(e < &element_data[ARRAY_SIZE(element_data)]);
333 
334 	 for (j = 0; j < (stacks - 1); j++) {
335 	    const unsigned right = left + 1;
336 
337 	    e[0] = left;
338 	    e[1] = right;
339 	    e += 2;
340 	    assert(e < &element_data[ARRAY_SIZE(element_data)]);
341 
342 	    left += (slices + 1);
343 	 }
344 
345 	 /* Emit the bottom vertex for the final triangle. */
346 	 e[0] = num_vertices - 1;
347 	 e++;
348 	 assert(e <= &element_data[ARRAY_SIZE(element_data)]);
349       }
350 
351       assert(e == &element_data[ARRAY_SIZE(element_data)]);
352       generated = true;
353    }
354 
355    glVertexPointer(4, GL_FLOAT, 4 * sizeof(float), vertex_data);
356    glEnableClientState(GL_VERTEX_ARRAY);
357    for (i = 0; i < slices; i++) {
358       glDrawElements(GL_TRIANGLE_STRIP,
359 		     elements_per_slice,
360 		     GL_UNSIGNED_INT,
361 		     &element_data[i * elements_per_slice]);
362    }
363 }
364 
365 
366 static void
render_to_fbo(void)367 render_to_fbo(void)
368 {
369    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
370 
371    glViewport(0, 0, SIZE, SIZE);
372 
373    glEnable(GL_DEPTH_TEST);
374 
375    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
376 
377    glMatrixMode(GL_MODELVIEW);
378    glLoadIdentity();
379    glMatrixMode(GL_PROJECTION);
380    glLoadIdentity();
381    glOrtho(-1.0, 1.0, -1.0, 1.0, -1, 1.0);
382 
383    glColor4f(1.0, 0.0, 0.0, 0.0);
384    draw_sphere();
385 
386    glDisable(GL_DEPTH_TEST);
387 
388    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
389 }
390 
391 
392 static GLfloat *
read_float_z_image(GLint x,GLint y)393 read_float_z_image(GLint x, GLint y)
394 {
395    GLfloat *z = (GLfloat *) malloc(SIZE * SIZE * sizeof(GLfloat));
396 
397    glReadPixels(x, y, SIZE, SIZE, GL_DEPTH_COMPONENT, GL_FLOAT, z);
398 
399    return z;
400 }
401 
402 
403 #if DEBUG
404 static GLuint *
read_uint_z_image(GLint x,GLint y)405 read_uint_z_image(GLint x, GLint y)
406 {
407    GLuint *z = (GLuint *) malloc(SIZE * SIZE * sizeof(GLuint));
408 
409    glReadPixels(x, y, SIZE, SIZE, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, z);
410 
411    return z;
412 }
413 #endif /* DEBUG */
414 
415 
416 /** Show contents of depth buffer in middle of window */
417 static void
show_depth_fbo(void)418 show_depth_fbo(void)
419 {
420    GLfloat *zf;
421 
422    glViewport(1 * SIZE, 0, SIZE, SIZE); /* not really needed */
423 
424    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
425    zf = read_float_z_image(0, 0);
426 
427    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
428 
429    glWindowPos2i(SIZE, 0);
430    glDrawPixels(SIZE, SIZE, GL_LUMINANCE, GL_FLOAT, zf);
431    if (!piglit_check_gl_error(GL_NO_ERROR))
432 	    piglit_report_result(PIGLIT_FAIL);
433 
434 #if DEBUG
435    {
436       GLfloat min, max, center;
437       find_float_min_max_center(zf, SIZE * SIZE, &min, &max, &center);
438       printf("depth fbo min %f  max %f  center %f\n", min, max, center);
439    }
440 
441    {
442       GLuint min, max, center;
443       GLuint *zi;
444 
445       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
446       zi = read_uint_z_image(0, 0);
447       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
448 
449       find_uint_min_max_center(zi, SIZE * SIZE, &min, &max, &center);
450       printf("depth fbo min 0x%x  max 0x%x  center 0x%x\n", min, max, center);
451       free(zi);
452    }
453 #endif /* DEBUG */
454 
455    free(zf);
456 }
457 
458 
459 /** Draw quad textured with depth image on right side of window */
460 static void
draw_quad_with_depth_texture(void)461 draw_quad_with_depth_texture(void)
462 {
463    GLfloat s1, t1;
464 
465    if (TexTarget == GL_TEXTURE_2D) {
466       s1 = t1 = 1.0;
467    }
468    else {
469       s1 = SIZE;
470       t1 = SIZE;
471    }
472 
473    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
474 
475    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
476 
477    glViewport(2 * SIZE, 0, SIZE, SIZE);
478 
479    glMatrixMode(GL_MODELVIEW);
480    glLoadIdentity();
481    glMatrixMode(GL_PROJECTION);
482    glLoadIdentity();
483    glOrtho(-1.0, 1.0, -1.0, 1.0, -1, 1.0);
484 
485    glBindTexture(TexTarget, DepthTex);
486    glEnable(TexTarget);
487 
488    piglit_draw_rect_tex(-1, -1, 2, 2, 0, 0, s1, t1);
489 
490    glDisable(TexTarget);
491 }
492 
493 
494 /**
495  * Draw quad with fragment shader that compares fragment.z against the
496  * depth texture value (draw on left side of window).
497  * We draw on the left side of the window to easily convert gl_FragCoord
498  * into a texture coordinate.
499  */
500 static void
draw_sphere_with_fragment_shader_compare(void)501 draw_sphere_with_fragment_shader_compare(void)
502 {
503    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
504 
505    glViewport(0 * SIZE, 0, SIZE, SIZE);
506 
507    glMatrixMode(GL_MODELVIEW);
508    glLoadIdentity();
509    glMatrixMode(GL_PROJECTION);
510    glLoadIdentity();
511    glOrtho(-1.0, 1.0, -1.0, 1.0, -1, 1.0);
512 
513    glBindTexture(TexTarget, DepthTex);
514 
515    glUseProgram(ShaderProg);
516 
517    glEnable(GL_DEPTH_TEST);
518 
519    if (1) {
520       draw_sphere();
521    }
522    else {
523       /* To test using gl_TexCoord[0].xy instead of gl_FragCoord.xy in the shader
524        */
525       static const GLfloat sPlane[4] = {0.5, 0, 0, 0.5};
526       static const GLfloat tPlane[4] = {0, 0.5, 0, 0.5};
527 
528       glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
529       glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
530       glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
531       glTexGenfv(GL_T, GL_EYE_PLANE, tPlane);
532       glEnable(GL_TEXTURE_GEN_S);
533       glEnable(GL_TEXTURE_GEN_T);
534 
535       draw_sphere();
536 
537       glDisable(GL_TEXTURE_GEN_S);
538       glDisable(GL_TEXTURE_GEN_T);
539    }
540 
541    glDisable(GL_DEPTH_TEST);
542 
543    glUseProgram(0);
544 
545 #if DEBUG
546    {
547       GLfloat *z = read_float_z_image(0, 0);
548       GLfloat min, max, center;
549 
550       find_float_min_max_center(z, SIZE * SIZE, &min, &max, &center);
551       printf("rendered  min %f  max %f  center %f\n", min, max, center);
552 
553       free(z);
554    }
555    {
556       GLuint *z = read_uint_z_image(0, 0);
557       GLuint min, max, center;
558 
559       find_uint_min_max_center(z, SIZE * SIZE, &min, &max, &center);
560       printf("rendered  min 0x%x  max 0x%x  center 0x%x\n", min, max, center);
561 
562       free(z);
563    }
564 #endif /* DEBUG */
565 }
566 
567 
568 static enum piglit_result
count_and_report_bad_pixels(void)569 count_and_report_bad_pixels(void)
570 {
571    GLubyte *z;
572    GLuint error = 0;
573    int i;
574 
575    z = (GLubyte *) malloc(SIZE * SIZE * 4 * sizeof(GLubyte));
576    glReadPixels(0, 0, SIZE, SIZE, GL_RGBA, GL_UNSIGNED_BYTE, z);
577 
578    for (i = 0; i < SIZE * SIZE * 4; i += 4) {
579       error += z[i];
580    }
581    free(z);
582 
583    if (!piglit_automatic)
584       printf("total error = %u\n", error);
585 
586    /* XXX this error test is a total hack for now */
587    if (error > ErrorScale)
588       return PIGLIT_FAIL;
589    else
590       return PIGLIT_PASS;
591 }
592 
593 
594 enum piglit_result
piglit_display(void)595 piglit_display(void)
596 {
597    enum piglit_result result;
598 
599    render_to_fbo();
600 
601    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
602 
603    show_depth_fbo();
604 
605    draw_quad_with_depth_texture();
606 
607    draw_sphere_with_fragment_shader_compare();
608 
609    result = count_and_report_bad_pixels();
610 
611    piglit_present_results();
612 
613    return result;
614 }
615 
616 
617 void
piglit_init(int argc,char ** argv)618 piglit_init(int argc, char **argv)
619 {
620    int i = 1;
621 
622    if (i < argc && strcmp(argv[i], "rect") == 0) {
623       TexTarget = GL_TEXTURE_RECTANGLE;
624       i++;
625    }
626    if (i < argc) {
627       ErrorScale = atof(argv[i]);
628    }
629 
630    piglit_require_extension("GL_EXT_framebuffer_object");
631    piglit_require_fragment_shader();
632    if (TexTarget == GL_TEXTURE_RECTANGLE) {
633       piglit_require_extension("GL_ARB_texture_rectangle");
634    }
635 
636    create_fbo();
637 
638    if (ErrorScale == 0.0) {
639       /* A 1-bit error/difference in Z values results in a delta of 64 in
640        * pixel intensity (where pixels are in [0,255]).
641        */
642       ErrorScale = ((double) (1ull << Zbits)) * 64.0 / 255.0;
643    }
644 
645    create_frag_shader();
646 
647    if (!piglit_automatic) {
648       printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
649       printf("Left: Shader showing difference pixels (black=good, red=error)\n");
650       printf("Middle: Depth buffer of FBO\n");
651       printf("Right: Quad textured with depth values\n");
652       printf("Z bits = %d\n", Zbits);
653       printf("ErrorScale = %f\n", ErrorScale);
654       printf("Texture target: %s\n",
655 	     TexTarget == GL_TEXTURE_RECTANGLE ? "RECTANGLE" : "2D" );
656    }
657 }
658