2 * BEGIN_COPYRIGHT -*- glean -*-
4 * Copyright (C) 2001 Allen Akin All Rights Reserved.
5 * Copyright (C) 2014 Intel Corporation All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person
8 * obtaining a copy of this software and associated documentation
9 * files (the "Software"), to deal in the Software without
10 * restriction, including without limitation the rights to use,
11 * copy, modify, merge, publish, distribute, sublicense, and/or
12 * sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
31 /** @file polygon-offset.c
33 * Implementation of polygon offset tests.
35 * This test verifies glPolygonOffset. It is run on every OpenGL-capable
36 * drawing surface configuration that supports creation of a window, has a
37 * depth buffer, and is RGB.
39 * The first subtest verifies that the OpenGL implementation is using a
40 * plausible value for the "minimum resolvable difference" (MRD). This is the
41 * offset in window coordinates that is sufficient to provide separation in
42 * depth (Z) for any two parallel surfaces. The subtest searches for the MRD
43 * by drawing two surfaces at a distance from each other and checking the
44 * resulting image to see if they were cleanly separated. The distance is
45 * then modified (using a binary search) until a minimum value is found. This
46 * is the so-called "ideal" MRD. Then two surfaces are drawn using
47 * glPolygonOffset to produce a separation that should equal one MRD. The
48 * depth values at corresponding points on each surface are subtracted to form
49 * the "actual" MRD. The subtest performs these checks twice, once close to
50 * the viewpoint and once far away from it, and passes if the largest of the
51 * ideal MRDs and the largest of the actual MRDs are nearly the same.
53 * The second subtest verifies that the OpenGL implementation is producing
54 * plausible values for slope-dependent offsets. The OpenGL spec requires
55 * that the depth slope of a surface be computed by an approximation that is
56 * at least as large as max(abs(dz/dx),abs(dz/dy)) and no larger than
57 * sqrt((dz/dx)**2+(dz/dy)**2). The subtest draws a quad rotated by various
58 * angles along various axes, samples three points on the quad's surface, and
59 * computes dz/dx and dz/dy. Then it draws two additional quads offset by one
60 * and two times the depth slope, respectively. The base quad and the two new
61 * quads are sampled and their actual depths read from the depth buffer. The
62 * subtest passes if the quads are offset by amounts that are within one and
63 * two times the allowable range, respectively.
65 * Derived in part from tests written by Angus Dorbie <dorbie@sgi.com> in
66 * September 2000 and Rickard E. (Rik) Faith <faith@valinux.com> in October
69 * Ported to Piglit by Laura Ekstrand.
72 #include "piglit-util-gl.h"
75 PIGLIT_GL_TEST_CONFIG_BEGIN
77 config
.supports_gl_compat_version
= 11;
79 config
.window_visual
= PIGLIT_GL_VISUAL_RGBA
|
80 PIGLIT_GL_VISUAL_DOUBLE
| PIGLIT_GL_VISUAL_DEPTH
;
82 PIGLIT_GL_TEST_CONFIG_END
91 multiply_matrix_with_vector(const double *matrix
, double *vector
)
96 /* The matrix is stored in the natural OpenGL order: column-major. In
97 * GLSL, this would be:
99 * vp.x = m[0] * v.xxxx;
100 * vp.y = m[1] * v.yyyy;
101 * vp.z = m[2] * v.zzzz;
102 * vp.w = m[3] * v.wwww;
105 for (i
= 0; i
< 4; i
++)
106 tmp
[i
] = matrix
[i
] * vector
[0];
108 for (i
= 0; i
< 4; i
++)
109 tmp
[i
] += matrix
[i
+ 4] * vector
[1];
111 for (i
= 0; i
< 4; i
++)
112 tmp
[i
] += matrix
[i
+ 8] * vector
[2];
114 for (i
= 0; i
< 4; i
++)
115 tmp
[i
] += matrix
[i
+ 12] * vector
[3];
117 memcpy(vector
, tmp
, sizeof(tmp
));
121 project(double x
, double y
, double z
, const double *modelview
,
122 const double *projection
, const int *viewport
, double *result
)
124 double vp
[4] = { x
, y
, z
, 1.0 };
126 /* Calculate v' as P * M * v. */
127 multiply_matrix_with_vector(modelview
, vp
);
128 multiply_matrix_with_vector(projection
, vp
);
131 fprintf(stderr
, "Cannot perspective divide by zero.\n");
132 piglit_report_result(PIGLIT_FAIL
);
139 /* Calculate the screen position using the same formula a gluProject. */
140 result
[0] = viewport
[0] + (viewport
[2] * ((vp
[0] + 1.0) / 2.0));
141 result
[1] = viewport
[1] + (viewport
[3] * ((vp
[1] + 1.0) / 2.0));
142 result
[2] = (vp
[2] + 1.0) / 2.0;
146 draw_quad_at_distance(GLdouble dist
)
149 glVertex3d(-dist
, -dist
, -dist
);
150 glVertex3d( dist
, -dist
, -dist
);
151 glVertex3d( dist
, dist
, -dist
);
152 glVertex3d(-dist
, dist
, -dist
);
157 window_coord_depth(GLdouble dist
)
159 /* Assumes we're using the "far at infinity" projection matrix and
160 * simple viewport transformation.
162 return 0.5 * (dist
- 2.0) / dist
+ 0.5;
166 red_quad_was_drawn(void)
168 static const float expected
[] = {1.0f
, 0.0f
, 0.0f
};
169 return piglit_probe_rect_rgb_silent(0, 0, piglit_width
, piglit_height
,
174 piglit_init(int argc
, char **argv
)
176 glEnable(GL_DEPTH_TEST
);
177 glDisable(GL_DITHER
);
178 glEnable(GL_CULL_FACE
);
179 glShadeModel(GL_FLAT
);
183 find_ideal_mrd(GLdouble
*ideal_mrd_near
, GLdouble
*ideal_mrd_far
,
184 GLdouble
*next_to_near
, GLdouble
*next_to_far
)
186 /* MRD stands for Minimum Resolvable Difference, the smallest distance
187 * in depth that suffices to separate any two polygons (or a polygon
188 * and the near or far clipping planes).
190 * This function tries to determine the "ideal" MRD for the current
191 * rendering context. It's expressed in window coordinates, because
192 * the value in model or clipping coordinates depends on the scale
193 * factors in the modelview and projection matrices and on the
194 * distances to the near and far clipping planes.
196 * For simple unsigned-integer depth buffers that aren't too deep (so
197 * that precision isn't an issue during coordinate transformations),
198 * it should be about one least-significant bit. For deep or
199 * floating-point or compressed depth buffers the situation may be
200 * more complicated, so we don't pass or fail an implementation solely
201 * on the basis of its ideal MRD.
203 * There are two subtle parts of this function. The first is the
204 * projection matrix we use for rendering. This matrix places the far
205 * clip plane at infinity (so that we don't run into arbitrary limits
206 * during our search process). The second is the method used for
207 * drawing the polygon. We scale the x and y coords of the polygon
208 * vertices by the polygon's depth, so that it always occupies the
209 * full view frustum. This makes it easier to verify that the polygon
210 * was resolved completely -- we just read back the entire window and
211 * see if any background pixels appear.
213 * To insure that we get reasonable results on machines with unusual
214 * depth buffers (floating-point, or compressed), we determine the MRD
215 * twice, once close to the near clipping plane and once as far away
216 * from the eye as possible. On a simple integer depth buffer these
217 * two values should be essentially the same. For other depth-buffer
218 * formats, the ideal MRD is simply the largest of the two.
221 GLdouble near_dist
, far_dist
, half_dist
;
224 /* First, find a distance that is as far away as possible, yet a quad
225 * at that distance can be distinguished from the background. Start
226 * by pushing quads away from the eye until we find an interval where
227 * the closer quad can be resolved, but the farther quad cannot. Then
228 * binary-search to find the threshold.
231 glDepthFunc(GL_LESS
);
233 glColor3f(1.0, 0.0, 0.0); /* red */
237 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
238 draw_quad_at_distance(far_dist
);
239 if (!red_quad_was_drawn())
241 piglit_present_results();
242 near_dist
= far_dist
;
245 for (i
= 0; i
< 64; ++i
) {
246 half_dist
= 0.5 * (near_dist
+ far_dist
);
247 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
248 draw_quad_at_distance(half_dist
);
249 if (red_quad_was_drawn())
250 near_dist
= half_dist
;
252 far_dist
= half_dist
;
253 piglit_present_results();
255 *next_to_far
= near_dist
;
257 /* We can derive a resolvable difference from the value next_to_far,
258 * but it's not necessarily the one we want. Consider mapping the
259 * object coordinate range [0,1] onto the integer window coordinate
260 * range [0,2]. A natural way to do this is with a linear function,
261 * windowCoord = 2*objectCoord. With rounding, this maps [0,0.25) to
262 * 0, [0.25,0.75) to 1, and [0.75,1] to 2. Note that the intervals at
263 * either end are 0.25 wide, but the one in the middle is 0.5 wide.
264 * The difference we can derive from next_to_far is related to the
265 * width of the final interval. We want to back up just a bit so that
266 * we can get a (possibly much larger) difference that will work for
267 * the larger interval. To do this we need to find a difference that
268 * allows us to distinguish two quads when the more distant one is at
269 * distance next_to_far.
273 far_dist
= *next_to_far
;
274 for (i
= 0; i
< 64; ++i
) {
275 half_dist
= 0.5 * (near_dist
+ far_dist
);
276 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
278 glColor3f(0.0, 0.0, 0.0); /* black */
279 glDepthFunc(GL_ALWAYS
);
280 draw_quad_at_distance(*next_to_far
);
282 glColor3f(1.0, 0.0, 0.0); /* red */
283 glDepthFunc(GL_LESS
);
284 draw_quad_at_distance(half_dist
);
286 if (red_quad_was_drawn())
287 near_dist
= half_dist
;
289 far_dist
= half_dist
;
290 piglit_present_results();
293 *ideal_mrd_far
= window_coord_depth(*next_to_far
)
294 - window_coord_depth(near_dist
);
296 /* Now we apply a similar strategy at the near end of the depth range,
297 * but swapping the senses of various comparisons so that we approach
298 * the near clipping plane rather than the far.
302 glDepthFunc(GL_GREATER
);
303 glColor3f(1.0, 0.0, 0.0); /* red */
305 far_dist
= *next_to_far
;
306 for (i
= 0; i
< 64; ++i
) {
307 half_dist
= 0.5 * (near_dist
+ far_dist
);
308 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
309 draw_quad_at_distance(half_dist
);
310 if (red_quad_was_drawn())
311 far_dist
= half_dist
;
313 near_dist
= half_dist
;
314 piglit_present_results();
316 *next_to_near
= far_dist
;
318 near_dist
= *next_to_near
;
319 far_dist
= *next_to_far
;
320 for (i
= 0; i
< 64; ++i
) {
321 half_dist
= 0.5 * (near_dist
+ far_dist
);
322 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
324 glColor3f(0.0, 0.0, 0.0); /* black */
325 glDepthFunc(GL_ALWAYS
);
326 draw_quad_at_distance(*next_to_near
);
328 glColor3f(1.0, 0.0, 0.0); /* red */
329 glDepthFunc(GL_GREATER
);
330 draw_quad_at_distance(half_dist
);
332 if (red_quad_was_drawn())
333 far_dist
= half_dist
;
335 near_dist
= half_dist
;
336 piglit_present_results();
339 *ideal_mrd_near
= window_coord_depth(far_dist
)
340 - window_coord_depth(*next_to_near
);
344 read_depth(int x
, int y
)
347 glReadPixels(x
, y
, 1, 1, GL_DEPTH_COMPONENT
, GL_UNSIGNED_INT
, &depth
);
349 /* This normalization of "depth" is correct even on 64-bit
350 * machines because GL types have machine-independent ranges.
352 return ((double) depth
) / 4294967295.0;
356 find_actual_mrd(GLdouble
*next_to_near
, GLdouble
*next_to_far
,
357 GLdouble
*actual_mrd_near
, GLdouble
*actual_mrd_far
)
359 /* Here we use polygon offset to determine the implementation's actual
365 glDepthFunc(GL_ALWAYS
);
367 /* Draw a quad far away from the eye and read the depth at its
370 glDisable(GL_POLYGON_OFFSET_FILL
);
371 draw_quad_at_distance(*next_to_far
);
372 base_depth
= read_depth(piglit_width
/2, piglit_height
/2);
374 /* Now draw a quad that's one MRD closer to the eye: */
375 glEnable(GL_POLYGON_OFFSET_FILL
);
376 glPolygonOffset(0.0, -1.0);
377 draw_quad_at_distance(*next_to_far
);
379 /* The difference between the depths of the two quads is the value the
380 * implementation is actually using for one MRD:
382 *actual_mrd_far
= base_depth
383 - read_depth(piglit_width
/2, piglit_height
/2);
385 /* Repeat the process for a quad close to the eye: */
386 glDisable(GL_POLYGON_OFFSET_FILL
);
387 draw_quad_at_distance(*next_to_near
);
388 base_depth
= read_depth(piglit_width
/ 2, piglit_height
/ 2);
389 glEnable(GL_POLYGON_OFFSET_FILL
);
390 glPolygonOffset(0.0, 1.0); /* 1 MRD further away */
391 draw_quad_at_distance(*next_to_near
);
392 *actual_mrd_near
= read_depth(piglit_width
/ 2, piglit_height
/ 2)
397 check_slope_offset(const struct angle_axis
*aa
, GLdouble
*ideal_mrd_near
)
399 /* This function checks for correct slope-based offsets for a quad
400 * rotated to a given angle around a given axis.
402 * The basic strategy is to:
403 * Draw the quad. (Note: the quad's size and position
404 * are chosen so that it won't ever be clipped.)
405 * Sample three points in the quad's interior.
406 * Compute dz/dx and dz/dy based on those samples.
407 * Compute the range of allowable offsets; must be between
408 * max(abs(dz/dx), abs(dz/dy)) and
409 * sqrt((dz/dx)**2, (dz/dy)**2)
410 * Sample the depth of the quad at its center.
411 * Use PolygonOffset to produce an offset equal to one
412 * times the depth slope of the base quad.
413 * Draw another quad with the same orientation as the first.
414 * Sample the second quad at its center.
415 * Compute the difference in depths between the first quad
417 * Verify that the difference is within the allowable range.
418 * Repeat for a third quad at twice the offset from the first.
419 * (This verifies that the implementation is scaling
420 * the depth offset correctly.)
422 const GLfloat quad_dist
= 2.5; /* must be > 1+sqrt(2) to avoid */
423 /* clipping by the near plane */
424 GLdouble modelview_mat
[16];
425 GLdouble projection_mat
[16];
432 double det
, dzdx
, dzdy
, mmax
, mmin
;
433 GLdouble offset_depth
, offset
;
437 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
438 glEnable(GL_DEPTH_TEST
);
439 glDepthFunc(GL_LESS
);
441 glColor3f(1.0, 0.0, 0.0); /* red */
443 glMatrixMode(GL_MODELVIEW
);
445 glTranslatef(0.0, 0.0, -quad_dist
);
446 glRotatef(aa
->angle
, aa
->axis
[0], aa
->axis
[1], aa
->axis
[2]);
448 glGetDoublev(GL_MODELVIEW_MATRIX
, modelview_mat
);
449 glGetDoublev(GL_PROJECTION_MATRIX
, projection_mat
);
450 glGetIntegerv(GL_VIEWPORT
, viewport
);
452 glDisable(GL_POLYGON_OFFSET_FILL
);
454 piglit_draw_rect(-1.0, -1.0, 2.0, 2.0);
456 project(0.0, 0.0, 0.0, modelview_mat
, projection_mat
, viewport
,
458 base_depth
= read_depth(centerw
[0], centerw
[1]);
460 project(-0.9, -0.9, 0.0, modelview_mat
, projection_mat
, viewport
, p0
);
461 p0
[2] = read_depth(p0
[0], p0
[1]);
463 project( 0.9, -0.9, 0.0, modelview_mat
, projection_mat
, viewport
, p1
);
464 p1
[2] = read_depth(p1
[0], p1
[1]);
466 project( 0.9, 0.9, 0.0, modelview_mat
, projection_mat
, viewport
, p2
);
467 p2
[2] = read_depth(p2
[0], p2
[1]);
469 det
= (p0
[0] - p1
[0]) * (p0
[1] - p2
[1])
470 - (p0
[0] - p2
[0]) * (p0
[1] - p1
[1]);
471 if (fabs(det
) < 0.001)
472 return false; /* too close to colinear to evaluate */
474 dzdx
= ((p0
[2] - p1
[2]) * (p0
[1] - p2
[1])
475 - (p0
[2] - p2
[2]) * (p0
[1] - p1
[1])) / det
;
476 dzdy
= ((p0
[0] - p1
[0]) * (p0
[2] - p2
[2])
477 - (p0
[0] - p2
[0]) * (p0
[2] - p1
[2])) / det
;
479 mmax
= 1.1 * sqrt(dzdx
* dzdx
+ dzdy
* dzdy
) + (*ideal_mrd_near
);
480 /* (adding ideal_mrd_near is a fudge for roundoff error */
481 /* when the slope is extremely close to zero) */
482 mmin
= 0.9 * fmax(fabs(dzdx
), fabs(dzdy
));
484 glEnable(GL_POLYGON_OFFSET_FILL
);
485 glPolygonOffset(-1.0, 0.0);
486 piglit_present_results();
487 piglit_draw_rect(-1.0, -1.0, 2.0, 2.0);
488 offset_depth
= read_depth(centerw
[0], centerw
[1]);
489 offset
= fmax(base_depth
- offset_depth
, 0.0);
490 if (offset
< mmin
|| offset
> mmax
) {
492 printf("Depth-slope related offset was too small");
494 printf("Depth-slope related offset was too large");
495 printf("; first failure at:\n");
496 printf("\tAngle = %f degrees, axis = (%f, %f, %f)\n",
497 aa
->angle
, aa
->axis
[0], aa
->axis
[1], aa
->axis
[2]);
498 printf("\tFailing offset was %.16f\n", offset
);
499 printf("\tAllowable range is (%f, %f)\n", mmin
, mmax
);
500 printf("\tglPolygonOffset(-1.0, 0.0);\n");
501 printf("\tglReadPixels returned %f\n", offset_depth
);
505 glPolygonOffset(-2.0, 0.0);
506 piglit_present_results();
507 piglit_draw_rect(-1.0, -1.0, 2.0, 2.0);
508 offset_depth
= read_depth(centerw
[0], centerw
[1]);
509 offset
= fmax(base_depth
- offset_depth
, 0.0);
510 if (offset
< 2.0 * mmin
|| offset
> 2.0 * mmax
) {
511 if (offset
< 2.0 * mmin
)
512 printf("Depth-slope related offset was too small");
514 printf("Depth-slope related offset was too large");
515 printf("; first failure at:\n");
516 printf("\tAngle = %f degrees, axis = (%f, %f, %f)\n",
517 aa
->angle
, aa
->axis
[0], aa
->axis
[1], aa
->axis
[2]);
518 printf("\tFailing offset was %.16f\n", offset
);
519 printf("\tAllowable range is (%f, %f)\n", 2.0 * mmin
,
521 printf("\tglPolygonOffset(-2.0, 0.0);\n");
522 printf("\tglReadPixels returned %f\n", offset_depth
);
530 check_slope_offsets(GLdouble
* ideal_mrd_near
)
532 /* This function checks that the implementation is offsetting
533 * primitives correctly according to their depth slopes. (Note that
534 * it uses some values computed by find_ideal_mrd, so that function
535 * must be run first.)
539 /* Rotation angles (degrees) and axes for which offset will be checked
541 static const struct angle_axis aa
[] = {
564 for (i
= 0; i
< ARRAY_SIZE(aa
); ++i
)
565 if (!check_slope_offset(aa
+ i
, ideal_mrd_near
))
569 } /* check_slope_offsets */
572 log_mrd(const char *pre
, double mrd
, GLint dbits
)
575 bits
= (int)(0.5 + (pow(2.0, dbits
) - 1.0) * mrd
);
576 printf("%s %e (nominally %i %s)\n", pre
, mrd
, bits
,
577 (bits
== 1) ? "bit": "bits");
584 double ideal_mrd
, actual_mrd
;
585 GLdouble ideal_mrd_near
, ideal_mrd_far
, next_to_near
, next_to_far
;
586 GLdouble actual_mrd_near
, actual_mrd_far
;
587 bool big_enough_mrd
, small_enough_mrd
;
590 /* The following projection matrix places the near clipping plane at
591 * distance 1.0, and the far clipping plane at infinity. This allows
592 * us to stress depth-buffer resolution as far away from the eye as
593 * possible, without introducing code that depends on the size or
594 * format of the depth buffer.
596 * To derive this matrix, start with the matrix generated by glFrustum
597 * with near-plane distance equal to 1.0, and take the limit of the
598 * matrix elements as the far-plane distance goes to infinity.
600 static const GLfloat near_1_far_infinity
[] = {
603 0.0, 0.0, -1.0, -1.0,
607 glViewport(0, 0, piglit_width
, piglit_height
);
609 glMatrixMode(GL_PROJECTION
);
610 glLoadMatrixf(near_1_far_infinity
);
612 glMatrixMode(GL_MODELVIEW
);
615 glDepthFunc(GL_LESS
);
616 glDisable(GL_POLYGON_OFFSET_FILL
);
619 find_ideal_mrd(&ideal_mrd_near
, &ideal_mrd_far
,
620 &next_to_near
, &next_to_far
);
621 find_actual_mrd(&next_to_near
, &next_to_far
,
622 &actual_mrd_near
, &actual_mrd_far
);
623 ideal_mrd
= fmax(ideal_mrd_near
, ideal_mrd_far
);
624 actual_mrd
= fmax(actual_mrd_near
, actual_mrd_far
);
625 big_enough_mrd
= (actual_mrd
>= 0.99 * ideal_mrd
);
626 small_enough_mrd
= (actual_mrd
<= 2.0 * ideal_mrd
);
628 pass
= big_enough_mrd
&& small_enough_mrd
&& pass
;
629 pass
= check_slope_offsets(&ideal_mrd_near
) && pass
;
631 /* Print the results */
632 if (!big_enough_mrd
) {
633 printf("Actual MRD is too small ");
634 printf("(may cause incorrect results)\n");
637 if (!small_enough_mrd
) {
638 printf("Actual MRD is too large ");
639 printf("(may waste depth-buffer range)\n\n");
642 glGetIntegerv(GL_DEPTH_BITS
, &dbits
);
643 printf("GL_DEPTH_BITS = %d\n", dbits
);
644 log_mrd("Ideal MRD at near plane is", ideal_mrd_near
, dbits
);
645 log_mrd("Actual MRD at near plane is", actual_mrd_near
, dbits
);
646 log_mrd("Ideal MRD at infinity is", ideal_mrd_far
, dbits
);
647 log_mrd("Actual MRD at infinity is", actual_mrd_far
, dbits
);
649 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;