summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric R. Smith <eric.smith@collabora.com>2024-04-04 17:10:21 -0300
committerMarge Bot <emma+marge@anholt.net>2024-04-24 12:45:51 +0000
commit2c64a91bb0a1d983beb6d9ae1085b10cf2aa89a5 (patch)
tree14a6198fafe0a846a647453fcd31c087f246f2a7
parent869a1b6e83b921671ac3439fd5f56ef357899645 (diff)
read_depth_offset: new test to check depth offset calculation
We have tests to validate depth offsets in general, but these apply to the default depth buffer (usually 24 bit fixed point). This test checks the details of the depth offset calculation by using NV_read_pixel to read back the written values, and verifies that e.g. the minimum resolvable difference used for floating point buffers matches the spec. This revealed a bug on panfrost. Signed-off-by: Eric R. Smith <eric.smith@collabora.com> Reviewed-by: Erik Faye-Lund <erik.faye-lund@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/piglit/-/merge_requests/900>
-rw-r--r--tests/spec/gles-3.0/CMakeLists.gles3.txt1
-rw-r--r--tests/spec/gles-3.0/read-depth-offset.c252
2 files changed, 253 insertions, 0 deletions
diff --git a/tests/spec/gles-3.0/CMakeLists.gles3.txt b/tests/spec/gles-3.0/CMakeLists.gles3.txt
index 9f7ffe8ce..73410f6f3 100644
--- a/tests/spec/gles-3.0/CMakeLists.gles3.txt
+++ b/tests/spec/gles-3.0/CMakeLists.gles3.txt
@@ -7,6 +7,7 @@ piglit_add_executable(minmax_${piglit_target_api} minmax.c)
piglit_add_executable(oes_compressed_etc2_texture-miptree_gles3 oes_compressed_etc2_texture-miptree.c)
piglit_add_executable(texture-immutable-levels_gles3 texture-immutable-levels.c)
piglit_add_executable(read_depth_gles3 read-depth.c)
+piglit_add_executable(read_depth_offset_gles3 read-depth-offset.c)
piglit_add_executable(gles-3.0-transform-feedback-uniform-buffer-object transform-feedback-uniform-buffer-object.c)
piglit_add_executable(gles-3.0-attribute-aliasing attribute-aliasing.c)
diff --git a/tests/spec/gles-3.0/read-depth-offset.c b/tests/spec/gles-3.0/read-depth-offset.c
new file mode 100644
index 000000000..970db8d1e
--- /dev/null
+++ b/tests/spec/gles-3.0/read-depth-offset.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright © 2024 Collabora Ltd
+ *
+ * Based on read-depth, which has
+ * Copyright © 2015 Intel Corporation
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+/** @file read-depth-offset.c
+ *
+ * Tests glPolygonOffset calculations
+ *
+ * Test iterates over table of depth buffer formats and expected types to
+ * read values back from each format. For each format it renders a rectangle at
+ * different depth levels, reads back a pixel and verifies expected depth value.
+ *
+ * The spec is fairly clear on the calculations for floating point depth
+ * buffers, but for fixed point it merely specifies that the value r
+ * used for the minimum resolvable difference is "implementation defined".
+ * But it must be the same for all depth values, so we can at least
+ * check that.
+ */
+
+#include "piglit-util-gl.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+ config.supports_gl_es_version = 30;
+ config.window_visual = PIGLIT_GL_VISUAL_DEPTH;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+static GLint prog;
+
+const char *vs_source =
+ "attribute vec4 vertex;\n"
+ "uniform float depth;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(vertex.xy, depth, 1.0);\n"
+ "}\n";
+
+const char *fs_source =
+ "void main()\n"
+ "{\n"
+ "}\n";
+
+/* this is a fairly arbitrary test for floats being "close" together.
+ we don't want to make too many assumptions about how the GPU hardware
+ does floating point calculations, so we don't even assume IEEE binary
+ compliance
+*/
+static bool
+equals(float a, float b)
+{
+ return fabs(a - b) < 0.00001;
+}
+
+#define DEPTH_BIAS_UNITS 256.0
+
+/*
+ * Calculate the expected depth after offset applied.
+ * We assume the polygon is facing the screen and
+ * that glPolygonOffsetClamp factor is 0.0.
+ * For fixed point formats, the minimum resolvable
+ * difference in depth values is passed as a
+ * pointer; if this value is 0, we do no
+ * offsetting and instead return the raw value read
+ * (so that the caller can calculate what mrd is
+ * being used by the fixed point hardware).
+ */
+
+static GLfloat
+offset_depth(GLenum type, GLfloat inputZ, double mrd)
+{
+ GLfloat near = -1.0;
+ GLfloat far = 1.0;
+ GLfloat zw, offset;
+ double work;
+ int exp;
+
+ zw = inputZ * (far-near)/2.0 + (far+near)/2.0;
+
+ /* for floats, find the minimum resolvable difference near inputZ */
+ if (type == GL_FLOAT) {
+ double mant;
+ work = (double) zw;
+ mant = frexp(work, &exp);
+ if (mant == 0)
+ mrd = 0; /* 0 has no exponent, really */
+ else {
+ mrd = exp2(exp-24);
+ }
+ }
+ offset = (GLfloat)(mrd * DEPTH_BIAS_UNITS);
+
+ zw += offset;
+
+ if (zw < near) zw = near;
+ if (zw > far) zw = far;
+ return zw;
+}
+
+static GLuint
+create_depth_fbo(GLenum depth_type)
+{
+ GLuint fbo, buffer;
+ GLenum status;
+
+ glGenRenderbuffers(1, &buffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, buffer);
+ glRenderbufferStorage(GL_RENDERBUFFER,
+ depth_type, piglit_width, piglit_height);
+
+ glGenFramebuffers(1, &fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+ GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, buffer);
+
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ fprintf(stderr, "error creating framebuffer, status 0x%x\n",
+ status);
+ return 0;
+ }
+ return fbo;
+}
+
+static bool
+check_depth(GLenum type, float source_depth, double *mrd_ptr)
+{
+ float expect;
+ GLfloat data;
+ GLuint uint_pixel;
+ double mrd;
+
+ if (type == GL_FLOAT) {
+ glReadPixels(0, 0, 1, 1, GL_DEPTH_COMPONENT, type,
+ (void *) &data);
+ } else {
+ glReadPixels(0, 0, 1, 1, GL_DEPTH_COMPONENT, type,
+ (void *) &uint_pixel);
+ uint_pixel = uint_pixel >> 8;
+ data = (1.0 * ((float) uint_pixel)) / 16777215.0;
+ }
+
+ if (!piglit_check_gl_error(GL_NO_ERROR))
+ return false;
+
+ mrd = *mrd_ptr;
+ expect = offset_depth(type, source_depth, mrd);
+ /* if we haven't computed the minimum resolvable difference yet,
+ then figure it out here */
+ if (type != GL_FLOAT && mrd == 0.0) {
+ double delta = fabs(data - source_depth);
+ mrd = delta / DEPTH_BIAS_UNITS;
+#if 0
+ /* useful for debugging failures, but #if'd out for normal usage */
+ printf("orig: %a read: %a delta: %a mrd: %a\n", source_depth, data, delta, mrd);
+#endif
+ *mrd_ptr = mrd;
+ expect = data; /* no failure on first time through */
+ }
+
+ if (!equals(data, expect)) {
+ if (type == GL_FLOAT && source_depth == 0.0 && fabs(data - source_depth)/DEPTH_BIAS_UNITS < 0.000001 ) {
+ /* floating point 0.0 upsets some hardware, just accept
+ whatever it gave us */
+ } else {
+ fprintf(stderr, "%s Z source: %f expected: %f actual: %f\n",
+ (type == GL_FLOAT) ? "float" : "fixed", source_depth, expect, data);
+ return false;
+ }
+ }
+ return true;
+}
+
+const GLenum tests[] = {
+ GL_DEPTH_COMPONENT16, GL_UNSIGNED_INT_24_8_OES,
+ GL_DEPTH_COMPONENT24, GL_UNSIGNED_INT_24_8_OES,
+ GL_DEPTH_COMPONENT32F, GL_FLOAT,
+};
+
+static bool
+test_format(GLenum depth_format, GLenum read_type)
+{
+ const float step = 0.1;
+ int steps = (int)round(1.0 / step);
+ double mrd = 0.0; /* minimum resolvable difference */
+ float expect = 0.0;
+ int i;
+ bool test_ok;
+
+ GLuint fbo = create_depth_fbo(depth_format);
+ if (!fbo)
+ return PIGLIT_FAIL;
+
+ /* Step from -1.0 to 1.0, linear depth. Render a rectangle at
+ * depth i, read pixel and verify expected depth value.
+ */
+ for (i = -steps; i <= steps; i++) {
+ GLfloat depth = (GLfloat)i / steps;
+ glDepthRangef(-1.0, 1.0);
+ glPolygonOffset(0, DEPTH_BIAS_UNITS);
+ glEnable(GL_POLYGON_OFFSET_FILL);
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+ glUniform1f(glGetUniformLocation(prog, "depth"), depth);
+
+ piglit_draw_rect(-1, -1, 2, 2);
+
+ test_ok = check_depth(read_type, expect, &mrd);
+
+ glPolygonOffset(0, 0);
+ glDisable(GL_POLYGON_OFFSET_FILL);
+ glDepthRangef(0.0, 1.0);
+
+ if (!test_ok)
+ return false;
+
+ expect += step / 2.0;
+ }
+ glDeleteFramebuffers(1, &fbo);
+ return true;
+}
+
+enum piglit_result
+piglit_display(void)
+{
+ unsigned j;
+
+ glEnable(GL_DEPTH_TEST);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ /* Loop through formats listed in 'tests'. */
+ for (j = 0; j < ARRAY_SIZE(tests); j += 2) {
+
+ if (!test_format(tests[j], tests[j+1]))
+ return PIGLIT_FAIL;
+ }
+ return PIGLIT_PASS;
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+ piglit_require_extension("GL_NV_read_depth");
+ prog = piglit_build_simple_program(vs_source, fs_source);
+ glUseProgram(prog);
+}