1 // BEGIN_COPYRIGHT -*- glean -*-
3 // Copyright (C) 2009 VMware, Inc. All Rights Reserved.
5 // Permission is hereby granted, free of charge, to any person
6 // obtaining a copy of this software and associated documentation
7 // files (the "Software"), to deal in the Software without
8 // restriction, including without limitation the rights to use,
9 // copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL VMWARE BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 // DEALINGS IN THE SOFTWARE.
30 // Test two-sided stencil extensions
35 // This test could be better:
36 // 1. Generate random state vectors, render and compare to expected values
37 // 2. Exercise separate front/back reference values and masks for the
38 // EXT and GL2 variations.
44 #include "tstencil2.h"
50 static PFNGLSTENCILOPSEPARATEATIPROC glStencilOpSeparateATI_func
;
51 static PFNGLSTENCILFUNCSEPARATEATIPROC glStencilFuncSeparateATI_func
;
54 static PFNGLACTIVESTENCILFACEEXTPROC glActiveStencilFaceEXT_func
;
57 static PFNGLSTENCILOPSEPARATEPROC glStencilOpSeparate_func
;
58 static PFNGLSTENCILFUNCSEPARATEPROC glStencilFuncSeparate_func
;
59 static PFNGLSTENCILMASKSEPARATEPROC glStencilMaskSeparate_func
;
68 Stencil2Result::Stencil2Result()
75 Stencil2Test::get_ext_functions(void)
78 glStencilOpSeparateATI_func
= (PFNGLSTENCILOPSEPARATEATIPROC
)
79 GLUtils::getProcAddress("glStencilOpSeparateATI");
80 glStencilFuncSeparateATI_func
= (PFNGLSTENCILFUNCSEPARATEATIPROC
)
81 GLUtils::getProcAddress("glStencilFuncSeparateATI");
84 glActiveStencilFaceEXT_func
= (PFNGLACTIVESTENCILFACEEXTPROC
)
85 GLUtils::getProcAddress("glActiveStencilFaceEXT");
88 glStencilOpSeparate_func
= (PFNGLSTENCILOPSEPARATEPROC
)
89 GLUtils::getProcAddress("glStencilOpSeparate");
91 glStencilFuncSeparate_func
= (PFNGLSTENCILFUNCSEPARATEPROC
)
92 GLUtils::getProcAddress("glStencilFuncSeparate");
94 glStencilMaskSeparate_func
= (PFNGLSTENCILMASKSEPARATEPROC
)
95 GLUtils::getProcAddress("glStencilMaskSeparate");
100 Stencil2Test::have_ATI_separate_stencil(void) const
102 return GLUtils::haveExtension("GL_ATI_separate_stencil");
106 Stencil2Test::have_EXT_stencil_two_side(void) const
108 return GLUtils::haveExtension("GL_EXT_stencil_two_side");
112 Stencil2Test::have_GL2_stencil_two_side(void) const
114 const char *version
= (const char *) glGetString(GL_VERSION
);
115 if (strncmp(version
, "2.", 2) == 0 ||
116 strncmp(version
, "3.0", 3) == 0) {
123 Stencil2Test::have_stencil_wrap(void) const
125 const char *version
= (const char *) glGetString(GL_VERSION
);
126 if (strncmp(version
, "2.", 2) == 0 ||
127 strncmp(version
, "3.0", 3) == 0) {
130 else if (GLUtils::haveExtension("GL_EXT_stencil_wrap")) {
138 // Bottom row uses GL_CCW
139 // Top row uses GL_CW
140 // Left column is front-facing
141 // Right column is back-facing
142 // Check the values in the stencil buffer to see if they match
143 // the expected values.
145 Stencil2Test::render_test(GLuint expectedFront
, GLuint expectedBack
)
148 GLint x1
= windowSize
/ 2;
149 GLint x2
= windowSize
;
151 GLint y1
= windowSize
/ 2;
152 GLint y2
= windowSize
;
154 glFrontFace(GL_CCW
); // this the GL default
156 // lower left quad = front-facing
157 glBegin(GL_TRIANGLE_FAN
);
164 // lower right quad = back-facing
165 glBegin(GL_TRIANGLE_FAN
);
174 // upper left quad = front-facing
175 glBegin(GL_TRIANGLE_FAN
);
182 // upper right quad = back-facing
183 glBegin(GL_TRIANGLE_FAN
);
190 GLint midXleft
= (x0
+ x1
) / 2;
191 GLint midXright
= (x1
+ x2
) / 2;
192 GLint midYlower
= (y0
+ y1
) / 2;
193 GLint midYupper
= (y1
+ y2
) / 2;
194 GLuint lowerLeftVal
, lowerRightVal
;
195 GLuint upperLeftVal
, upperRightVal
;
197 glReadPixels(midXleft
, midYlower
, 1, 1,
198 GL_STENCIL_INDEX
, GL_UNSIGNED_INT
, &lowerLeftVal
);
199 glReadPixels(midXright
, midYlower
, 1, 1,
200 GL_STENCIL_INDEX
, GL_UNSIGNED_INT
, &lowerRightVal
);
202 glReadPixels(midXleft
, midYupper
, 1, 1,
203 GL_STENCIL_INDEX
, GL_UNSIGNED_INT
, &upperLeftVal
);
204 glReadPixels(midXright
, midYupper
, 1, 1,
205 GL_STENCIL_INDEX
, GL_UNSIGNED_INT
, &upperRightVal
);
207 if (lowerLeftVal
!= upperLeftVal
) {
208 env
->log
<< "FAIL:\n";
209 env
->log
<< "\tLower-left value (" << lowerLeftVal
210 << ") doesn't match upper-left value ("
213 env
->log
<< "\tLooks like a front/back-face orientation bug.\n";
217 if (lowerRightVal
!= upperRightVal
) {
218 env
->log
<< "FAIL:\n";
219 env
->log
<< "\tLower-right value (" << lowerRightVal
220 << ") doesn't match upper-right value ("
223 env
->log
<< "\tLooks like a front/back-face orientation bug.\n";
228 if (lowerLeftVal
!= expectedFront
) {
229 env
->log
<< "FAIL:\n";
230 env
->log
<< "\tExpected front-face stencil value is "
232 << " but found " << lowerLeftVal
<< "\n";
235 else if (lowerRightVal
!= expectedBack
) {
236 env
->log
<< "FAIL:\n";
237 env
->log
<< "\tExpected back-face stencil value is " << expectedBack
238 << " but found " << lowerRightVal
<< "\n";
248 Stencil2Test::compare_state(int method
, GLenum found
, GLenum expected
,
251 if (found
!= expected
) {
252 env
->log
<< "FAIL:\n";
253 env
->log
<< "\tQuery of " << msg
<< " state failed for ";
256 env
->log
<< "GL_ATI_separate_stencil";
259 env
->log
<< "GL_EXT_stencil_two_side";
262 env
->log
<< "GL 2.x two-sided stencil";
269 sprintf(s
, "\tFound 0x%x, expected 0x%x\n", found
, expected
);
277 // Set stencil state, plus read it back and check that it's correct.
278 // Note: we only test with one reference value and one mask value
279 // even though EXT and GL2 support separate front/back refs/masks
281 Stencil2Test::set_stencil_state(int method
,
282 GLenum frontStencilFail
,
283 GLenum backStencilFail
,
293 GLint get_frontStencilFail
;
294 GLint get_backStencilFail
;
295 GLint get_frontZFail
;
297 GLint get_frontZPass
;
308 glStencilOpSeparateATI_func(GL_FRONT
,
313 glStencilOpSeparateATI_func(GL_BACK
,
318 glStencilFuncSeparateATI_func(frontFunc
, backFunc
, ref
, mask
);
321 glGetIntegerv(GL_STENCIL_FAIL
, &get_frontStencilFail
);
322 glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL
, &get_frontZFail
);
323 glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS
, &get_frontZPass
);
324 glGetIntegerv(GL_STENCIL_FUNC
, &get_frontFunc
);
325 glGetIntegerv(GL_STENCIL_REF
, &get_ref
);
326 glGetIntegerv(GL_STENCIL_VALUE_MASK
, &get_mask
);
328 glGetIntegerv(GL_STENCIL_BACK_FUNC_ATI
, &get_backFunc
);
329 glGetIntegerv(GL_STENCIL_BACK_FAIL_ATI
, &get_backStencilFail
);
330 glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI
, &get_backZFail
);
331 glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI
, &get_backZPass
);
332 twoEnabled
= GL_TRUE
;
337 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
339 glActiveStencilFaceEXT_func(GL_FRONT
);
340 glStencilOp(frontStencilFail
, frontZFail
, frontZPass
);
341 glStencilFunc(frontFunc
, ref
, mask
);
343 glActiveStencilFaceEXT_func(GL_BACK
);
344 glStencilOp(backStencilFail
, backZFail
, backZPass
);
345 glStencilFunc(backFunc
, ref
, mask
);
348 glActiveStencilFaceEXT_func(GL_FRONT
);
349 glGetIntegerv(GL_STENCIL_FAIL
, &get_frontStencilFail
);
350 glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL
, &get_frontZFail
);
351 glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS
, &get_frontZPass
);
352 glGetIntegerv(GL_STENCIL_FUNC
, &get_frontFunc
);
353 glGetIntegerv(GL_STENCIL_REF
, &get_ref
);
354 glGetIntegerv(GL_STENCIL_VALUE_MASK
, &get_mask
);
355 glActiveStencilFaceEXT_func(GL_BACK
);
356 glGetIntegerv(GL_STENCIL_FAIL
, &get_backStencilFail
);
357 glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL
, &get_backZFail
);
358 glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS
, &get_backZPass
);
359 glGetIntegerv(GL_STENCIL_FUNC
, &get_backFunc
);
360 glGetIntegerv(GL_STENCIL_REF
, &get_ref
);
361 glGetIntegerv(GL_STENCIL_VALUE_MASK
, &get_mask
);
362 glGetIntegerv(GL_STENCIL_TEST_TWO_SIDE_EXT
, &twoEnabled
);
367 glStencilOpSeparate_func(GL_FRONT
,
371 glStencilOpSeparate_func(GL_BACK
,
375 glStencilFuncSeparate_func(GL_FRONT
, frontFunc
, ref
, mask
);
376 glStencilFuncSeparate_func(GL_BACK
, backFunc
, ref
, mask
);
379 glGetIntegerv(GL_STENCIL_FAIL
, &get_frontStencilFail
);
380 glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL
, &get_frontZFail
);
381 glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS
, &get_frontZPass
);
382 glGetIntegerv(GL_STENCIL_FUNC
, &get_frontFunc
);
383 glGetIntegerv(GL_STENCIL_REF
, &get_ref
);
384 glGetIntegerv(GL_STENCIL_VALUE_MASK
, &get_mask
);
386 glGetIntegerv(GL_STENCIL_BACK_FUNC
, &get_backFunc
);
387 glGetIntegerv(GL_STENCIL_BACK_FAIL
, &get_backStencilFail
);
388 glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL
, &get_backZFail
);
389 glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS
, &get_backZPass
);
390 twoEnabled
= GL_TRUE
;
397 // mask off bits we don't care about
398 get_mask
&= stencilMax
;
401 GLenum err
= glGetError();
402 if (err
!= GL_NO_ERROR
) {
403 env
->log
<< "FAIL:\n";
404 env
->log
<< "\tGL error " << err
<< " detected.\n";
408 // see if state-get matches state-set
410 if (!compare_state(method
, get_frontStencilFail
, frontStencilFail
,
411 "front stencil fail"))
414 if (!compare_state(method
, get_backStencilFail
, backStencilFail
,
415 "back stencil fail"))
418 if (!compare_state(method
, get_frontZFail
, frontZFail
,
422 if (!compare_state(method
, get_backZFail
, backZFail
,
426 if (!compare_state(method
, get_frontZPass
, frontZPass
,
430 if (!compare_state(method
, get_backZPass
, backZPass
,
434 if (!compare_state(method
, get_frontFunc
, frontFunc
,
435 "front stencil func"))
438 if (!compare_state(method
, get_backFunc
, backFunc
,
439 "back stencil func"))
442 if (!compare_state(method
, get_ref
, ref
, "stencil ref"))
445 if (!compare_state(method
, get_mask
, mask
, "stencil mask"))
448 if (!compare_state(method
, twoEnabled
, GL_TRUE
, "two-side enable"))
456 Stencil2Test::reset_stencil_state(int method
)
462 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
463 glActiveStencilFaceEXT_func(GL_FRONT
);
474 Stencil2Test::test_stencil(int method
)
478 glEnable(GL_STENCIL_TEST
);
480 //============================================================
482 glDisable(GL_DEPTH_TEST
);
484 glClear(GL_COLOR_BUFFER_BIT
|
485 GL_STENCIL_BUFFER_BIT
|
486 GL_DEPTH_BUFFER_BIT
);
489 // set stencil buffer vals to 5
490 pass
= set_stencil_state(method
,
491 GL_KEEP
, GL_KEEP
, // stencil fail
492 GL_KEEP
, GL_KEEP
, // z fail
493 GL_REPLACE
, GL_REPLACE
, // z pass
494 GL_ALWAYS
, GL_ALWAYS
, // stencil func
497 pass
= render_test(5, 5);
498 reset_stencil_state(method
);
502 // incr front val to 6, decr back val to 4
503 pass
= set_stencil_state(method
,
504 GL_KEEP
, GL_KEEP
, // stencil fail
505 GL_KEEP
, GL_KEEP
, // z fail
506 GL_INCR
, GL_DECR
, // z pass
507 GL_ALWAYS
, GL_ALWAYS
, // stencil func
510 pass
= render_test(6, 4);
511 reset_stencil_state(method
);
516 // if back<6, replace with zero
517 // final: front=6, back=0
518 pass
= set_stencil_state(method
,
519 GL_KEEP
, GL_ZERO
, // stencil fail
520 GL_KEEP
, GL_KEEP
, // z fail
521 GL_KEEP
, GL_KEEP
, // z pass
522 GL_EQUAL
, GL_LESS
, // stencil func
525 pass
= render_test(6, 0);
526 reset_stencil_state(method
);
530 // if front!=10, keep, else decr
531 // if back<10, keep, else incr
532 // final: front=6, back=1
533 pass
= set_stencil_state(method
,
534 GL_DECR
, GL_INCR
, // stencil fail
535 GL_KEEP
, GL_KEEP
, // z fail
536 GL_KEEP
, GL_KEEP
, // z pass
537 GL_NOTEQUAL
, GL_LESS
, // stencil func
538 10, ~0); // ref, mask
540 pass
= render_test(6, 1);
541 reset_stencil_state(method
);
546 //============================================================
547 // Now begin tests with depth test
548 glEnable(GL_DEPTH_TEST
);
549 glDepthFunc(GL_LESS
);
551 glClear(GL_COLOR_BUFFER_BIT
|
552 GL_STENCIL_BUFFER_BIT
|
553 GL_DEPTH_BUFFER_BIT
);
555 // set stencil buffer vals to 7, set Z values
556 pass
= set_stencil_state(method
,
557 GL_KEEP
, GL_KEEP
, // stencil fail
558 GL_KEEP
, GL_KEEP
, // z fail
559 GL_REPLACE
, GL_REPLACE
, // z pass
560 GL_ALWAYS
, GL_ALWAYS
, // stencil func
563 pass
= render_test(7, 7);
564 reset_stencil_state(method
);
569 // GL_LESS test should fail everywhere
570 // decr front to 5, incr back to 2
571 pass
= set_stencil_state(method
,
572 GL_KEEP
, GL_KEEP
, // stencil fail
573 GL_DECR
, GL_INCR
, // z fail
574 GL_KEEP
, GL_KEEP
, // z pass
575 GL_ALWAYS
, GL_ALWAYS
, // stencil func
576 99, ~0); // ref, mask
578 pass
= render_test(6, 8);
579 reset_stencil_state(method
);
584 // set depth test = GL_EQUAL
585 // Z test should pass everywhere
588 glDepthFunc(GL_EQUAL
);
589 pass
= set_stencil_state(method
,
590 GL_KEEP
, GL_KEEP
, // stencil fail
591 GL_KEEP
, GL_KEEP
, // z fail
592 GL_REPLACE
, GL_DECR
, // z pass
593 GL_ALWAYS
, GL_ALWAYS
, // stencil func
596 pass
= render_test(3, 7);
597 reset_stencil_state(method
);
602 // incr front to 4 (by z pass), decr back to 6 (by stencil fail)
603 pass
= set_stencil_state(method
,
604 GL_DECR
, GL_INCR
, // stencil fail
605 GL_KEEP
, GL_KEEP
, // z fail
606 GL_INCR
, GL_DECR
, // z pass
607 GL_EQUAL
, GL_NOTEQUAL
, // stencil func
610 pass
= render_test(4, 6);
611 reset_stencil_state(method
);
616 //============================================================
617 // Disable depth test
618 glDisable(GL_DEPTH_TEST
);
620 // test stencil value mask
621 // only test bit 1 in stencil values
622 // if !(front&0x2 == 15&0x2), decr to 3 (should happen)
623 // if !(back&0x2 == 15&0x2), incr to 7 (should not happen)
624 pass
= set_stencil_state(method
,
625 GL_DECR
, GL_INCR
, // stencil fail
626 GL_KEEP
, GL_KEEP
, // z fail
627 GL_KEEP
, GL_KEEP
, // z pass
628 GL_EQUAL
, GL_EQUAL
, // stencil func
629 15, 0x2); // ref, mask
631 pass
= render_test(3, 6);
632 reset_stencil_state(method
);
637 //============================================================
638 // Test common two-sided stencil modes for shadow volume rendering
639 // Requires stencil +/- wrap feature.
641 if (!have_stencil_wrap())
644 glClear(GL_COLOR_BUFFER_BIT
|
645 GL_STENCIL_BUFFER_BIT
|
646 GL_DEPTH_BUFFER_BIT
);
648 glEnable(GL_DEPTH_TEST
);
649 glDepthFunc(GL_LESS
);
651 // "traditional / Z-pass" method:
652 // front face: incr on zpass
653 // back face: decr on zpass
654 // both front and back Z-test should pass here
655 pass
= set_stencil_state(method
,
656 GL_KEEP
, GL_KEEP
, // stencil fail
657 GL_KEEP
, GL_KEEP
, // z fail
658 GL_INCR_WRAP_EXT
, GL_DECR_WRAP_EXT
, // z pass
659 GL_ALWAYS
, GL_ALWAYS
, // stencil func
662 pass
= render_test(1, stencilMax
);
663 reset_stencil_state(method
);
669 // front face: decr on zfail
670 // back face: incr on zfail
671 // both front and back Z-test should fail here
672 pass
= set_stencil_state(method
,
673 GL_KEEP
, GL_KEEP
, // stencil fail
674 GL_DECR_WRAP_EXT
, GL_INCR_WRAP_EXT
, // z fail
675 GL_KEEP
, GL_KEEP
, // z pass
676 GL_ALWAYS
, GL_ALWAYS
, // stencil func
679 pass
= render_test(0, 0);
680 reset_stencil_state(method
);
690 Stencil2Test::runOne(Stencil2Result
&r
, Window
&w
)
692 (void) w
; // silence warning
697 // how many stencil bits (we assume at least 8 above)
698 glGetIntegerv(GL_STENCIL_BITS
, &stencilBits
);
699 stencilMax
= (1 << stencilBits
) - 1;
700 assert(stencilBits
>= 8);
702 glViewport(0, 0, windowSize
, windowSize
);
703 glMatrixMode(GL_PROJECTION
);
705 glOrtho(0, windowSize
, 0, windowSize
, -1, 1);
706 glMatrixMode(GL_MODELVIEW
);
709 if (have_ATI_separate_stencil()) {
710 r
.pass
&= test_stencil(ATI
);
713 if (have_EXT_stencil_two_side()) {
714 r
.pass
&= test_stencil(EXT
);
717 if (have_GL2_stencil_two_side()) {
718 r
.pass
&= test_stencil(GL2
);
724 Stencil2Test::logOne(Stencil2Result
&r
)
732 Stencil2Test::compareOne(Stencil2Result
&oldR
,
733 Stencil2Result
&stencil2R
)
735 comparePassFail(oldR
, stencil2R
);
740 Stencil2Result::putresults(ostream
&s
) const
752 Stencil2Result::getresults(istream
&s
)
757 if (strcmp(result
, "FAIL") == 0) {
768 Stencil2Test::isApplicable() const
770 return (have_ATI_separate_stencil() ||
771 have_EXT_stencil_two_side() ||
772 have_EXT_stencil_two_side());
777 // The test object itself:
778 Stencil2Test
stencil2Test("stencil2",
779 "window, rgb, s, z", // we need stencil and Z
780 "", // no extension filter, but see isApplicable()
781 "Test two-sided stencil features\n");