summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/all.py1
-rw-r--r--tests/spec/gl-2.0/CMakeLists.gl.txt1
-rw-r--r--tests/spec/gl-2.0/two-sided-stencil.c751
3 files changed, 753 insertions, 0 deletions
diff --git a/tests/all.py b/tests/all.py
index 0db54ac72..8c291b8c5 100644
--- a/tests/all.py
+++ b/tests/all.py
@@ -1069,6 +1069,7 @@ with profile.group_manager(
g(['gl-2.0-edgeflag'])
g(['gl-2.0-edgeflag-immediate'])
g(['gl-2.0-large-point-fs'])
+ g(['gl-2.0-two-sided-stencil'])
g(['gl-2.0-vertexattribpointer'])
g(['gl-2.0-vertex-const-attr'])
g(['gl-2.0-reuse_fragment_shader'])
diff --git a/tests/spec/gl-2.0/CMakeLists.gl.txt b/tests/spec/gl-2.0/CMakeLists.gl.txt
index e10940b3b..20b315a5e 100644
--- a/tests/spec/gl-2.0/CMakeLists.gl.txt
+++ b/tests/spec/gl-2.0/CMakeLists.gl.txt
@@ -13,6 +13,7 @@ piglit_add_executable (vertex-program-two-side vertex-program-two-side.c)
piglit_add_executable (gl-2.0-edgeflag edgeflag.c)
piglit_add_executable (gl-2.0-edgeflag-immediate edgeflag-immediate.c)
piglit_add_executable (gl-2.0-large-point-fs large-point-fs.c)
+piglit_add_executable (gl-2.0-two-sided-stencil two-sided-stencil.c)
piglit_add_executable (gl-2.0-vertexattribpointer vertexattribpointer.c)
piglit_add_executable (gl-2.0-vertex-const-attr vertex-const-attr.c)
piglit_add_executable (gl-2.0-reuse_fragment_shader reuse_fragment_shader.c)
diff --git a/tests/spec/gl-2.0/two-sided-stencil.c b/tests/spec/gl-2.0/two-sided-stencil.c
new file mode 100644
index 000000000..2ae101970
--- /dev/null
+++ b/tests/spec/gl-2.0/two-sided-stencil.c
@@ -0,0 +1,751 @@
+/*
+ * BEGIN_COPYRIGHT -*- glean -*-
+ *
+ * Copyright (C) 1999 Allen Akin All Rights Reserved.
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2015 Intel Corporation All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * END_COPYRIGHT
+ */
+
+/** @file two-sided-stencil.c
+ *
+ * Test two-sided stencil extensions
+ *
+ * This test could be better:
+ * 1. Generate random state vectors, render and compare to expected values
+ * 2. Exercise separate front/back reference values and masks for the
+ * EXT and GL2 variations.
+ *
+ * Note: Must check writeMask of set_stencil_state to make sure it's correct
+ *
+ * Authors:
+ * Brian Paul <brianp@valinux.com>
+ * Adapted to Piglit by Juliet Fru <julietfru@gmail.com>, September 2015.
+ */
+
+#include "piglit-util-gl.h"
+
+#include <assert.h>
+#include <string.h>
+
+
+PIGLIT_GL_TEST_CONFIG_BEGIN config.supports_gl_compat_version = 20;
+
+config.window_visual =
+ PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DEPTH |
+ PIGLIT_GL_VISUAL_STENCIL;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+/* two-sided methods. */
+#define ATI 1
+#define EXT 2
+#define GL2 3
+
+GLint stencil_bits, stencil_max;
+
+
+static bool
+have_stencil_wrap(void)
+{
+ if (piglit_get_gl_version() >= 2.0) {
+ return true;
+ } else if (piglit_is_extension_supported("GL_EXT_stencil_wrap")) {
+ return true;
+ }
+ return false;
+}
+
+
+/* Draw four quads:
+ * Bottom row uses GL_CCW
+ * Top row uses GL_CW
+ * Left column is front-facing
+ * Right column is back-facing
+ * Check the values in the stencil buffer to see if they match
+ * the expected values.
+ */
+static bool
+render_test(GLuint expectedFront, GLuint expectedBack)
+{
+ GLint x0 = 0;
+ GLint x1 = piglit_width / 2;
+ GLint x2 = piglit_width;
+ GLint y0 = 0;
+ GLint y1 = piglit_width / 2;
+ GLint y2 = piglit_width;
+
+ glFrontFace(GL_CCW); /* this the GL default */
+
+ /* lower left quad = front-facing */
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(x0, y0);
+ glVertex2f(x1, y0);
+ glVertex2f(x1, y1);
+ glVertex2f(x0, y1);
+ glEnd();
+
+ /* lower right quad = back-facing */
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(x1, y0);
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y1);
+ glVertex2f(x2, y0);
+ glEnd();
+
+ glFrontFace(GL_CW);
+
+ /* upper left quad = front-facing */
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(x0, y1);
+ glVertex2f(x0, y2);
+ glVertex2f(x1, y2);
+ glVertex2f(x1, y1);
+ glEnd();
+
+ /* upper right quad = back-facing */
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y1);
+ glVertex2f(x2, y2);
+ glVertex2f(x1, y2);
+ glEnd();
+
+ GLint midXleft = (x0 + x1) / 2;
+ GLint midXright = (x1 + x2) / 2;
+ GLint midYlower = (y0 + y1) / 2;
+ GLint midYupper = (y1 + y2) / 2;
+ GLuint lowerLeftVal, lowerRightVal;
+ GLuint upperLeftVal, upperRightVal;
+
+ glReadPixels(midXleft, midYlower, 1, 1,
+ GL_STENCIL_INDEX, GL_UNSIGNED_INT, &lowerLeftVal);
+ glReadPixels(midXright, midYlower, 1, 1,
+ GL_STENCIL_INDEX, GL_UNSIGNED_INT, &lowerRightVal);
+
+ glReadPixels(midXleft, midYupper, 1, 1,
+ GL_STENCIL_INDEX, GL_UNSIGNED_INT, &upperLeftVal);
+ glReadPixels(midXright, midYupper, 1, 1,
+ GL_STENCIL_INDEX, GL_UNSIGNED_INT, &upperRightVal);
+
+ if (lowerLeftVal != upperLeftVal) {
+ printf(" FAIL:\n"
+ "\tLower-left value (%d) doesn't match upper-left "
+ "value (%d).\n \t Looks like a front/back "
+ "orientation bug.\n", lowerLeftVal, upperLeftVal);
+ return false;
+ }
+
+ if (lowerRightVal != upperRightVal) {
+ printf(" FAIL:\n\tLower-right value (%d) doesn't match"
+ " upper-right value (%d).\n\tLooks like "
+ "a front/back-face orientation bug.\n", lowerRightVal,
+ upperRightVal);
+ return false;
+ }
+
+
+ if (lowerLeftVal != expectedFront) {
+ printf("FAIL:\n\tExpected front-face stencil value is "
+ "%d but found %d \n", expectedFront, lowerLeftVal);
+ return false;
+ } else if (lowerRightVal != expectedBack) {
+ printf("FAIL:\n\tExpected back-face stencil value is "
+ "%d but found %d \n", expectedBack, lowerRightVal);
+ return false;
+ } else {
+ return true;
+ }
+}
+
+
+static bool
+compare_state(int method, GLenum found, GLenum expected, const char *msg)
+{
+ if (found != expected) {
+ printf(" FAIL:\n\tQuery of %s state failed for ", msg);
+ switch (method) {
+ case ATI:
+ printf("GL_ATI_separate_stencil\n");
+ break;
+ case EXT:
+ printf("GL_EXT_stencil_two_side\n");
+ break;
+ case GL2:
+ printf("GL 2.x two-sided stencil\n");
+ break;
+ default:
+ printf("\n");
+ assert(0);
+ }
+
+ printf("\tFound 0x%x, expected 0x%x\n", found, expected);
+ return false;
+ }
+ return true;
+}
+
+
+/* Set stencil state, plus read it back and check that it's correct.
+ * Note: we only test with one reference value and one mask value
+ * even though EXT and GL2 support separate front/back refs/masks
+ */
+static bool
+set_stencil_state(int method,
+ GLenum frontStencilFail,
+ GLenum backStencilFail,
+ GLenum frontZFail,
+ GLenum backZFail,
+ GLenum frontZPass,
+ GLenum backZPass,
+ GLenum frontFunc,
+ GLenum backFunc,
+ GLint frontRef,
+ GLint backRef,
+ GLuint frontMask,
+ GLuint backMask,
+ GLuint frontWriteMask, GLuint backWriteMask)
+{
+ GLint get_frontStencilFail;
+ GLint get_backStencilFail;
+ GLint get_frontZFail;
+ GLint get_backZFail;
+ GLint get_frontZPass;
+ GLint get_backZPass;
+ GLint get_frontFunc;
+ GLint get_backFunc;
+ GLint get_frontRef;
+ GLint get_backRef;
+ GLint get_frontMask;
+ GLint get_backMask;
+ GLint get_frontWriteMask;
+ GLint get_backWriteMask;
+ GLint twoEnabled;
+
+ switch (method) {
+ case ATI:
+ assert(frontRef == backRef);
+ assert(frontMask == backMask);
+ assert(frontWriteMask == backWriteMask);
+
+ /* set state */
+ glStencilOpSeparateATI(GL_FRONT,
+ frontStencilFail,
+ frontZFail, frontZPass);
+
+ glStencilOpSeparateATI(GL_BACK,
+ backStencilFail, backZFail, backZPass);
+
+ glStencilFuncSeparateATI(frontFunc, backFunc, frontRef,
+ frontMask);
+
+ glStencilMask(frontWriteMask);
+
+ /* get state */
+ glGetIntegerv(GL_STENCIL_FAIL, &get_frontStencilFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &get_frontZFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &get_frontZPass);
+ glGetIntegerv(GL_STENCIL_FUNC, &get_frontFunc);
+ glGetIntegerv(GL_STENCIL_REF, &get_frontRef);
+ glGetIntegerv(GL_STENCIL_VALUE_MASK, &get_frontMask);
+ glGetIntegerv(GL_STENCIL_WRITEMASK, &get_frontWriteMask);
+
+ glGetIntegerv(GL_STENCIL_BACK_FUNC_ATI, &get_backFunc);
+ glGetIntegerv(GL_STENCIL_BACK_FAIL_ATI, &get_backStencilFail);
+ glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI,
+ &get_backZFail);
+ glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI,
+ &get_backZPass);
+ get_backRef = get_frontRef;
+ get_backMask = get_frontMask;
+ get_backWriteMask = get_frontWriteMask;
+ twoEnabled = GL_TRUE;
+ break;
+
+ case EXT:
+ /* set state */
+ glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+
+ glActiveStencilFaceEXT(GL_FRONT);
+ glStencilOp(frontStencilFail, frontZFail, frontZPass);
+ glStencilFunc(frontFunc, frontRef, frontMask);
+ glStencilMask(frontWriteMask);
+
+ glActiveStencilFaceEXT(GL_BACK);
+ glStencilOp(backStencilFail, backZFail, backZPass);
+ glStencilFunc(backFunc, backRef, backMask);
+ glStencilMask(backWriteMask);
+
+ /* get state */
+ glActiveStencilFaceEXT(GL_FRONT);
+ glGetIntegerv(GL_STENCIL_FAIL, &get_frontStencilFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &get_frontZFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &get_frontZPass);
+ glGetIntegerv(GL_STENCIL_FUNC, &get_frontFunc);
+ glGetIntegerv(GL_STENCIL_REF, &get_frontRef);
+ glGetIntegerv(GL_STENCIL_VALUE_MASK, &get_frontMask);
+ glGetIntegerv(GL_STENCIL_WRITEMASK, &get_frontWriteMask);
+ glActiveStencilFaceEXT(GL_BACK);
+ glGetIntegerv(GL_STENCIL_FAIL, &get_backStencilFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &get_backZFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &get_backZPass);
+ glGetIntegerv(GL_STENCIL_FUNC, &get_backFunc);
+ glGetIntegerv(GL_STENCIL_REF, &get_backRef);
+ glGetIntegerv(GL_STENCIL_VALUE_MASK, &get_backMask);
+ glGetIntegerv(GL_STENCIL_WRITEMASK, &get_backWriteMask);
+ glGetIntegerv(GL_STENCIL_TEST_TWO_SIDE_EXT, &twoEnabled);
+ break;
+
+ case GL2:
+ /* set state */
+ glStencilOpSeparate(GL_FRONT,
+ frontStencilFail, frontZFail, frontZPass);
+ glStencilOpSeparate(GL_BACK,
+ backStencilFail, backZFail, backZPass);
+ glStencilFuncSeparate(GL_FRONT, frontFunc, frontRef,
+ frontMask);
+ glStencilFuncSeparate(GL_BACK, backFunc, backRef, backMask);
+ glStencilMaskSeparate(GL_FRONT, frontWriteMask);
+ glStencilMaskSeparate(GL_BACK, backWriteMask);
+
+ /* get state */
+ glGetIntegerv(GL_STENCIL_FAIL, &get_frontStencilFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &get_frontZFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &get_frontZPass);
+ glGetIntegerv(GL_STENCIL_FUNC, &get_frontFunc);
+ glGetIntegerv(GL_STENCIL_REF, &get_frontRef);
+ glGetIntegerv(GL_STENCIL_VALUE_MASK, &get_frontMask);
+ glGetIntegerv(GL_STENCIL_WRITEMASK, &get_frontWriteMask);
+
+ glGetIntegerv(GL_STENCIL_BACK_FUNC, &get_backFunc);
+ glGetIntegerv(GL_STENCIL_BACK_FAIL, &get_backStencilFail);
+ glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL,
+ &get_backZFail);
+ glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS,
+ &get_backZPass);
+ glGetIntegerv(GL_STENCIL_BACK_REF, &get_backRef);
+ glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &get_backMask);
+ glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &get_backWriteMask);
+ twoEnabled = GL_TRUE;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ /* mask off bits we don't care about */
+ get_frontMask &= stencil_max;
+ frontMask &= stencil_max;
+ get_backMask &= stencil_max;
+ backMask &= stencil_max;
+ get_frontWriteMask &= stencil_max;
+ frontWriteMask &= stencil_max;
+ get_backWriteMask &= stencil_max;
+ backWriteMask &= stencil_max;
+
+
+ if (!piglit_check_gl_error(GL_NO_ERROR)) {
+ return false;
+ }
+
+ /* see if state-get matches state-set */
+
+ if (!compare_state(method, get_frontStencilFail, frontStencilFail,
+ "front stencil fail"))
+ return false;
+
+ if (!compare_state(method, get_backStencilFail, backStencilFail,
+ "back stencil fail"))
+ return false;
+
+ if (!compare_state(method, get_frontZFail, frontZFail,
+ "front Z fail"))
+ return false;
+
+ if (!compare_state(method, get_backZFail, backZFail, "back Z fail"))
+ return false;
+
+ if (!compare_state(method, get_frontZPass, frontZPass,
+ "front Z pass"))
+ return false;
+
+ if (!compare_state(method, get_backZPass, backZPass, "back Z pass"))
+ return false;
+
+ if (!compare_state(method, get_frontFunc, frontFunc,
+ "front stencil func"))
+ return false;
+
+ if (!compare_state(method, get_backFunc, backFunc,
+ "back stencil func"))
+ return false;
+
+ if (!compare_state(method, get_frontRef, frontRef,
+ "front stencil ref"))
+ return false;
+
+ if (!compare_state(method, get_backRef, backRef, "back stencil ref"))
+ return false;
+
+ if (!compare_state(method, get_frontMask, frontMask,
+ "front stencil mask"))
+ return false;
+
+ if (!compare_state(method, get_backMask, backMask,
+ "back stencil mask"))
+ return false;
+
+ if (!compare_state(method, get_frontWriteMask, frontWriteMask,
+ "front stencil writemask"))
+ return false;
+
+ if (!compare_state(method, get_backWriteMask, backWriteMask,
+ "back stencil writemask"))
+ return false;
+
+ if (!compare_state(method, twoEnabled, GL_TRUE, "two-side enable"))
+ return false;
+
+ return true;
+}
+
+
+static bool
+set_stencil_state2(int method,
+ GLenum frontStencilFail,
+ GLenum backStencilFail,
+ GLenum frontZFail,
+ GLenum backZFail,
+ GLenum frontZPass,
+ GLenum backZPass,
+ GLenum frontFunc,
+ GLenum backFunc,
+ GLint ref,
+ GLuint mask,
+ GLuint writeMask)
+{
+ return set_stencil_state(method, frontStencilFail,
+ backStencilFail, frontZFail, backZFail,
+ frontZPass, backZPass, frontFunc, backFunc,
+ ref, /* frontRef */
+ ref, /* backRef */
+ mask, /* frontMask */
+ mask, /* backMask */
+ writeMask, /* frontWriteMask */
+ writeMask); /* backWriteMask */
+}
+
+
+void
+reset_stencil_state(int method)
+{
+ switch (method) {
+ case ATI:
+ break;
+ case EXT:
+ glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+ glActiveStencilFaceEXT(GL_FRONT);
+ break;
+ case GL2:
+ break;
+ default:
+ assert(0);
+ }
+}
+
+
+static bool
+test_stencil(int method)
+{
+ bool pass;
+
+ glEnable(GL_STENCIL_TEST);
+
+ /**
+ * No depth testing
+ */
+ glDisable(GL_DEPTH_TEST);
+
+ glClear(GL_COLOR_BUFFER_BIT |
+ GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+
+ /* set stencil buffer vals to 5 */
+ pass = set_stencil_state2(method, GL_KEEP, GL_KEEP, /* stencil fail */
+ GL_KEEP, GL_KEEP, /* z fail */
+ GL_REPLACE, GL_REPLACE, /* z pass */
+ GL_ALWAYS, GL_ALWAYS, /* stencil func */
+ 5, ~0, ~0); /* ref, mask, set write_mask to ~0 */
+ if (pass)
+ pass = render_test(5, 5);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+ /* incr front val to 6, decr back val to 4 */
+ pass = set_stencil_state2(method, GL_KEEP, GL_KEEP, /* stencil fail */
+ GL_KEEP, GL_KEEP, /* z fail */
+ GL_INCR, GL_DECR, /* z pass */
+ GL_ALWAYS, GL_ALWAYS, /* stencil func */
+ 5, ~0, ~0); /* ref, mask, set write_mask to ~0 */
+ if (pass)
+ pass = render_test(6, 4);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+ /* if front==6, keep
+ * if back<6, replace with zero
+ * final: front=6, back=0
+ */
+ pass = set_stencil_state2(method, GL_KEEP, GL_ZERO, /* stencil fail */
+ GL_KEEP, GL_KEEP, /* z fail */
+ GL_KEEP, GL_KEEP, /* z pass */
+ GL_EQUAL, GL_LESS, /* stencil func */
+ 6, ~0, ~0); /* ref, mask, set write_mask to ~0 */
+ if (pass)
+ pass = render_test(6, 0);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+ /* if front!=10, keep, else decr
+ * if back<10, keep, else incr
+ * final: front=6, back=1
+ */
+ pass = set_stencil_state2(method, GL_DECR, GL_INCR, /* stencil fail */
+ GL_KEEP, GL_KEEP, /* z fail */
+ GL_KEEP, GL_KEEP, /* z pass */
+ GL_NOTEQUAL, GL_LESS, /* stencil func */
+ 10, ~0, ~0); /* ref, mask, set write_mask to ~0 */
+ if (pass)
+ pass = render_test(6, 1);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+ if (method != ATI) {
+ /* if front!=10, keep, else decr
+ * if back<10, keep, else incr
+ * final: front=6, back=1
+ */
+ pass = set_stencil_state(method, GL_DECR, GL_INCR, /* stencil fail */
+ GL_KEEP, GL_KEEP, /* z fail */
+ GL_REPLACE, GL_REPLACE, /* z pass */
+ GL_ALWAYS, GL_ALWAYS, /* stencil func */
+ 0xf6, 0xf1, /* ref */
+ 0xff, 0xff, /* mask */
+ 0x60, 0x10); /* writeMask */
+ if (pass)
+ pass = render_test(0x66, 0x11);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+ }
+
+ /* reset write mask for clear */
+ set_stencil_state(method, GL_KEEP, GL_KEEP, /* stencil fail */
+ GL_KEEP, GL_KEEP, /* z fail */
+ GL_REPLACE, GL_REPLACE, /* z pass */
+ GL_ALWAYS, GL_ALWAYS, /* stencil func */
+ 0, 0, ~0, ~0, ~0, ~0);
+
+ /* ============================================================
+ * Now begin tests with depth test
+ */
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+
+ glClear(GL_COLOR_BUFFER_BIT |
+ GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ /* set stencil buffer vals to 7, set Z values */
+ pass = set_stencil_state2(method, GL_KEEP, GL_KEEP, /* stencil fail */
+ GL_KEEP, GL_KEEP, /* z fail */
+ GL_REPLACE, GL_REPLACE, /* z pass */
+ GL_ALWAYS, GL_ALWAYS, /* stencil func */
+ 7, ~0, ~0); /* ref, mask, set write_mask to ~0 */
+ if (pass)
+ pass = render_test(7, 7);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ /* GL_LESS test should fail everywhere
+ * decr front to 5, incr back to 2
+ */
+ pass = set_stencil_state2(method, GL_KEEP, GL_KEEP, /* stencil fail */
+ GL_DECR, GL_INCR, /* z fail */
+ GL_KEEP, GL_KEEP, /* z pass */
+ GL_ALWAYS, GL_ALWAYS, /* stencil func */
+ 99, ~0, ~0); /* ref, mask, set write_mask to ~0 */
+ if (pass)
+ pass = render_test(6, 8);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ /* set depth test = GL_EQUAL
+ * Z test should pass everywhere
+ * set front to 3
+ * decr back to 7
+ */
+ glDepthFunc(GL_EQUAL);
+ pass = set_stencil_state2(method, GL_KEEP, GL_KEEP, /* stencil fail */
+ GL_KEEP, GL_KEEP, /* z fail */
+ GL_REPLACE, GL_DECR, /* z pass */
+ GL_ALWAYS, GL_ALWAYS, /* stencil func */
+ 3, ~0, ~0); /* ref, mask, set write_mask to ~0 */
+ if (pass)
+ pass = render_test(3, 7);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ /* incr front to 4 (by z pass), decr back to 6 (by stencil fail) */
+ pass = set_stencil_state2(method, GL_DECR, GL_DECR, /* stencil fail */
+ GL_KEEP, GL_KEEP, /* z fail */
+ GL_INCR, GL_REPLACE, /* z pass */
+ GL_EQUAL, GL_EQUAL, /* stencil func */
+ 3, ~0, ~0); /* ref, mask, set write_mask to ~0 */
+ if (pass)
+ pass = render_test(4, 6);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ /* ============================================================
+ * Disable depth test
+ */
+ glDisable(GL_DEPTH_TEST);
+
+ /* test stencil value mask
+ * only test bit 1 in stencil values
+ * if !(front&0x2 == 15&0x2), decr to 3 (should happen)
+ * if !(back&0x2 == 15&0x2), incr to 7 (should not happen)
+ */
+ pass = set_stencil_state2(method, GL_DECR, GL_INCR, /* stencil fail */
+ GL_KEEP, GL_KEEP, /* z fail */
+ GL_KEEP, GL_KEEP, /* z pass */
+ GL_EQUAL, GL_EQUAL, /* stencil func */
+ 15, 0x2, ~0); /* ref, mask, set write_mask to ~0 */
+ if (pass)
+ pass = render_test(3, 6);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+ /* ============================================================
+ * Test common two-sided stencil modes for shadow volume rendering
+ * Requires stencil /- wrap feature.
+ */
+
+ if (!have_stencil_wrap())
+ return true;
+
+ glClear(GL_COLOR_BUFFER_BIT |
+ GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+
+ /* "traditional / Z-pass" method:
+ * front face: incr on zpass
+ * back face: decr on zpass
+ * both front and back Z-test should pass here
+ */
+ pass = set_stencil_state2(method, GL_KEEP, GL_KEEP, /* stencil fail */
+ GL_KEEP, GL_KEEP, /* z fail */
+ GL_INCR_WRAP_EXT, GL_DECR_WRAP_EXT, /* z pass */
+ GL_ALWAYS, GL_ALWAYS, /* stencil func */
+ 0, ~0, ~0); /* ref, mask, set write_mask to ~0 */
+ if (pass)
+ pass = render_test(1, stencil_max);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ /* "Z-fail" method:
+ * front face: decr on zfail
+ * back face: incr on zfail
+ * both front and back Z-test should fail here
+ */
+ pass = set_stencil_state2(method, GL_KEEP, GL_KEEP, /* stencil fail */
+ GL_DECR_WRAP_EXT, GL_INCR_WRAP_EXT, /* z fail */
+ GL_KEEP, GL_KEEP, /* z pass */
+ GL_ALWAYS, GL_ALWAYS, /* stencil func */
+ 0, ~0, ~0); /* ref, mask, set write_mask to ~0 */
+ if (pass)
+ pass = render_test(0, 0);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ return true;
+}
+
+
+void
+piglit_init(int argc, char **argv)
+{
+ /* no initialization */
+}
+
+
+enum piglit_result
+piglit_display(void)
+{
+ bool pass = true;
+
+ /* how many stencil bits (we assume at least 8 above) */
+ glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
+ stencil_max = (1 << stencil_bits) - 1;
+ assert(stencil_bits >= 8);
+
+ glViewport(0, 0, piglit_width, piglit_width);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, piglit_width, 0, piglit_width, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ if (piglit_is_extension_supported("GL_ATI_separate_stencil")) {
+ pass = test_stencil(ATI) && pass;
+ }
+
+ if (piglit_is_extension_supported("GL_EXT_stencil_two_side")) {
+ pass = test_stencil(EXT) && pass;
+ }
+
+ if (piglit_get_gl_version() >= 2.0) {
+ pass = test_stencil(GL2) && pass;
+ }
+
+ return pass ? PIGLIT_PASS : PIGLIT_FAIL;
+}