1 /* $Id: stencil.c,v 1.20 2000/10/29 18:23:16 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
46 _mesa_ClearStencil( GLint s
)
48 GET_CURRENT_CONTEXT(ctx
);
49 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glClearStencil");
50 ctx
->Stencil
.Clear
= (GLstencil
) s
;
52 if (ctx
->Driver
.ClearStencil
) {
53 (*ctx
->Driver
.ClearStencil
)( ctx
, s
);
60 _mesa_StencilFunc( GLenum func
, GLint ref
, GLuint mask
)
62 GET_CURRENT_CONTEXT(ctx
);
65 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glStencilFunc");
76 ctx
->Stencil
.Function
= func
;
79 gl_error( ctx
, GL_INVALID_ENUM
, "glStencilFunc" );
83 maxref
= (1 << STENCIL_BITS
) - 1;
84 ctx
->Stencil
.Ref
= (GLstencil
) CLAMP( ref
, 0, maxref
);
85 ctx
->Stencil
.ValueMask
= (GLstencil
) mask
;
87 if (ctx
->Driver
.StencilFunc
) {
88 (*ctx
->Driver
.StencilFunc
)( ctx
, func
, ctx
->Stencil
.Ref
, mask
);
95 _mesa_StencilMask( GLuint mask
)
97 GET_CURRENT_CONTEXT(ctx
);
98 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glStencilMask");
99 ctx
->Stencil
.WriteMask
= (GLstencil
) mask
;
101 if (ctx
->Driver
.StencilMask
) {
102 (*ctx
->Driver
.StencilMask
)( ctx
, mask
);
109 _mesa_StencilOp(GLenum fail
, GLenum zfail
, GLenum zpass
)
111 GET_CURRENT_CONTEXT(ctx
);
112 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glStencilOp");
120 ctx
->Stencil
.FailFunc
= fail
;
122 case GL_INCR_WRAP_EXT
:
123 case GL_DECR_WRAP_EXT
:
124 if (ctx
->Extensions
.HaveStencilWrap
) {
125 ctx
->Stencil
.FailFunc
= fail
;
130 gl_error(ctx
, GL_INVALID_ENUM
, "glStencilOp");
140 ctx
->Stencil
.ZFailFunc
= zfail
;
142 case GL_INCR_WRAP_EXT
:
143 case GL_DECR_WRAP_EXT
:
144 if (ctx
->Extensions
.HaveStencilWrap
) {
145 ctx
->Stencil
.ZFailFunc
= zfail
;
150 gl_error(ctx
, GL_INVALID_ENUM
, "glStencilOp");
160 ctx
->Stencil
.ZPassFunc
= zpass
;
162 case GL_INCR_WRAP_EXT
:
163 case GL_DECR_WRAP_EXT
:
164 if (ctx
->Extensions
.HaveStencilWrap
) {
165 ctx
->Stencil
.ZPassFunc
= zpass
;
170 gl_error(ctx
, GL_INVALID_ENUM
, "glStencilOp");
174 if (ctx
->Driver
.StencilOp
) {
175 (*ctx
->Driver
.StencilOp
)(ctx
, fail
, zfail
, zpass
);
183 IF stencil test fails THEN
184 Apply fail-op to stencil value
185 Don't write the pixel (RGBA,Z)
187 IF doing depth test && depth test fails THEN
188 Apply zfail-op to stencil value
189 Write RGBA and Z to appropriate buffers
191 Apply zpass-op to stencil value
200 * Return the address of a stencil buffer value given the window coords:
202 #define STENCIL_ADDRESS(X,Y) \
203 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
208 * Apply the given stencil operator to the array of stencil values.
209 * Don't touch stencil[i] if mask[i] is zero.
210 * Input: n - size of stencil array
211 * oper - the stencil buffer operator
212 * stencil - array of stencil values
213 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
214 * Output: stencil - modified values
216 static void apply_stencil_op( const GLcontext
*ctx
, GLenum oper
,
217 GLuint n
, GLstencil stencil
[],
218 const GLubyte mask
[] )
220 const GLstencil ref
= ctx
->Stencil
.Ref
;
221 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
222 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
240 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
256 GLstencil s
= stencil
[i
];
257 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
266 GLstencil s
= stencil
[i
];
267 if (s
< STENCIL_MAX
) {
268 stencil
[i
] = (GLstencil
) (s
+1);
276 /* VERIFY logic of adding 1 to a write-masked value */
277 GLstencil s
= stencil
[i
];
278 if (s
< STENCIL_MAX
) {
279 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
289 GLstencil s
= stencil
[i
];
291 stencil
[i
] = (GLstencil
) (s
-1);
299 /* VERIFY logic of subtracting 1 to a write-masked value */
300 GLstencil s
= stencil
[i
];
302 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
308 case GL_INCR_WRAP_EXT
:
319 GLstencil s
= stencil
[i
];
320 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
325 case GL_DECR_WRAP_EXT
:
336 GLstencil s
= stencil
[i
];
337 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
346 GLstencil s
= stencil
[i
];
347 stencil
[i
] = (GLstencil
) ~s
;
354 GLstencil s
= stencil
[i
];
355 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
361 gl_problem(ctx
, "Bad stencil op in apply_stencil_op");
369 * Apply stencil test to an array of stencil values (before depth buffering).
370 * Input: n - number of pixels in the array
371 * stencil - array of [n] stencil values
372 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
373 * Output: mask - pixels which fail the stencil test will have their
374 * mask flag set to 0.
375 * stencil - updated stencil values (where the test passed)
376 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
379 do_stencil_test( GLcontext
*ctx
, GLuint n
, GLstencil stencil
[],
382 GLubyte fail
[PB_SIZE
];
383 GLboolean allfail
= GL_FALSE
;
387 ASSERT(n
<= PB_SIZE
);
390 * Perform stencil test. The results of this operation are stored
391 * in the fail[] array:
392 * IF fail[i] is non-zero THEN
393 * the stencil fail operator is to be applied
395 * the stencil fail operator is not to be applied
398 switch (ctx
->Stencil
.Function
) {
413 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
416 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
432 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
435 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
451 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
454 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
470 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
473 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
489 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
492 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
508 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
511 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
533 gl_problem(ctx
, "Bad stencil func in gl_stencil_span");
537 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
538 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
, n
, stencil
, fail
);
548 * Apply stencil and depth testing to an array of pixels.
549 * Hardware or software stencil buffer acceptable.
550 * Input: n - number of pixels in the span
551 * z - array [n] of z values
552 * stencil - array [n] of stencil values
553 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
554 * Output: stencil - modified stencil values
555 * mask - array [n] of flags (1=stencil and depth test passed)
556 * Return: GL_TRUE - all fragments failed the testing
557 * GL_FALSE - one or more fragments passed the testing
561 stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
562 const GLdepth z
[], GLstencil stencil
[],
565 ASSERT(ctx
->Stencil
.Enabled
);
566 ASSERT(n
<= PB_SIZE
);
569 * Apply the stencil test to the fragments.
570 * failMask[i] is 1 if the stencil test failed.
572 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
573 /* all fragments failed the stencil test, we're done. */
579 * Some fragments passed the stencil test, apply depth test to them
580 * and apply Zpass and Zfail stencil ops.
582 if (ctx
->Depth
.Test
==GL_FALSE
) {
584 * No depth buffer, just apply zpass stencil function to active pixels.
586 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
590 * Perform depth buffering, then apply zpass or zfail stencil function.
592 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
595 /* save the current mask bits */
596 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
598 /* apply the depth test */
599 _mesa_depth_test_span(ctx
, n
, x
, y
, z
, mask
);
601 /* Set the stencil pass/fail flags according to result of depth testing.
602 * if oldmask[i] == 0 then
603 * Don't touch the stencil value
604 * else if oldmask[i] and newmask[i] then
607 * assert(oldmask[i] && !newmask[i])
612 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
613 passmask
[i
] = oldmask
[i
] & mask
[i
];
614 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
617 /* apply the pass and fail operations */
618 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
619 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
621 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
622 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
626 return GL_TRUE
; /* one or more fragments passed both tests */
632 * Apply stencil and depth testing to the span of pixels.
633 * Both software and hardware stencil buffers are acceptable.
634 * Input: n - number of pixels in the span
635 * x, y - location of leftmost pixel in span
636 * z - array [n] of z values
637 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
638 * Output: mask - array [n] of flags (1=stencil and depth test passed)
639 * Return: GL_TRUE - all fragments failed the testing
640 * GL_FALSE - one or more fragments passed the testing
644 _mesa_stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
645 const GLdepth z
[], GLubyte mask
[] )
647 GLstencil stencilRow
[MAX_WIDTH
];
651 ASSERT(ctx
->Stencil
.Enabled
);
652 ASSERT(n
<= MAX_WIDTH
);
654 /* Get initial stencil values */
655 if (ctx
->Driver
.WriteStencilSpan
) {
656 ASSERT(ctx
->Driver
.ReadStencilSpan
);
657 /* Get stencil values from the hardware stencil buffer */
658 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, n
, x
, y
, stencilRow
);
659 stencil
= stencilRow
;
662 /* software stencil buffer */
663 stencil
= STENCIL_ADDRESS(x
, y
);
666 /* do all the stencil/depth testing/updating */
667 result
= stencil_and_ztest_span( ctx
, n
, x
, y
, z
, stencil
, mask
);
669 if (ctx
->Driver
.WriteStencilSpan
) {
670 /* Write updated stencil values into hardware stencil buffer */
671 (ctx
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
681 * Apply the given stencil operator for each pixel in the array whose
682 * mask flag is set. This is for software stencil buffers only.
683 * Input: n - number of pixels in the span
684 * x, y - array of [n] pixels
685 * operator - the stencil buffer operator
686 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
689 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
690 GLuint n
, const GLint x
[], const GLint y
[],
691 GLenum oper
, const GLubyte mask
[] )
693 const GLstencil ref
= ctx
->Stencil
.Ref
;
694 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
695 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
698 ASSERT(!ctx
->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
708 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
716 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
717 *sptr
= (GLstencil
) (invmask
& *sptr
);
726 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
734 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
735 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
744 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
745 if (*sptr
< STENCIL_MAX
) {
746 *sptr
= (GLstencil
) (*sptr
+ 1);
754 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
755 if (*sptr
< STENCIL_MAX
) {
756 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
766 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
768 *sptr
= (GLstencil
) (*sptr
- 1);
776 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
778 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
784 case GL_INCR_WRAP_EXT
:
788 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
789 *sptr
= (GLstencil
) (*sptr
+ 1);
796 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
797 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
802 case GL_DECR_WRAP_EXT
:
806 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
807 *sptr
= (GLstencil
) (*sptr
- 1);
814 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
815 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
824 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
825 *sptr
= (GLstencil
) (~*sptr
);
832 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
833 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
839 gl_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
846 * Apply stencil test to an array of pixels before depth buffering.
847 * Used for software stencil buffer only.
848 * Input: n - number of pixels in the span
849 * x, y - array of [n] pixels to stencil
850 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
851 * Output: mask - pixels which fail the stencil test will have their
852 * mask flag set to 0.
853 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
856 stencil_test_pixels( GLcontext
*ctx
, GLuint n
,
857 const GLint x
[], const GLint y
[], GLubyte mask
[] )
859 GLubyte fail
[PB_SIZE
];
862 GLboolean allfail
= GL_FALSE
;
864 ASSERT(!ctx
->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
867 * Perform stencil test. The results of this operation are stored
868 * in the fail[] array:
869 * IF fail[i] is non-zero THEN
870 * the stencil fail operator is to be applied
872 * the stencil fail operator is not to be applied
876 switch (ctx
->Stencil
.Function
) {
891 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
894 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
895 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
911 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
914 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
915 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
931 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
934 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
935 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
951 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
954 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
955 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
971 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
974 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
975 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
991 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
994 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
995 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
1017 gl_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
1021 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
1022 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
, fail
);
1032 * Apply stencil and depth testing to an array of pixels.
1033 * This is used both for software and hardware stencil buffers.
1035 * The comments in this function are a bit sparse but the code is
1036 * almost identical to stencil_and_ztest_span(), which is well
1039 * Input: n - number of pixels in the array
1040 * x, y - array of [n] pixel positions
1041 * z - array [n] of z values
1042 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
1043 * Output: mask - array [n] of flags (1=stencil and depth test passed)
1044 * Return: GL_TRUE - all fragments failed the testing
1045 * GL_FALSE - one or more fragments passed the testing
1048 _mesa_stencil_and_ztest_pixels( GLcontext
*ctx
,
1049 GLuint n
, const GLint x
[], const GLint y
[],
1050 const GLdepth z
[], GLubyte mask
[] )
1052 ASSERT(ctx
->Stencil
.Enabled
);
1053 ASSERT(n
<= PB_SIZE
);
1055 if (ctx
->Driver
.WriteStencilPixels
) {
1056 /*** Hardware stencil buffer ***/
1057 GLstencil stencil
[PB_SIZE
];
1058 GLubyte mask
[PB_SIZE
];
1060 ASSERT(ctx
->Driver
.ReadStencilPixels
);
1061 (*ctx
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
1064 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
1065 /* all fragments failed the stencil test, we're done. */
1069 if (ctx
->Depth
.Test
== GL_FALSE
) {
1070 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
1073 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
1076 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
1078 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
1081 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
1082 passmask
[i
] = oldmask
[i
] & mask
[i
];
1083 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
1086 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
1087 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
1089 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
1090 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
1094 /* Write updated stencil values into hardware stencil buffer */
1095 (ctx
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, mask
);
1101 /*** Software stencil buffer ***/
1103 if (stencil_test_pixels(ctx
, n
, x
, y
, mask
) == GL_FALSE
) {
1104 /* all fragments failed the stencil test, we're done. */
1109 if (ctx
->Depth
.Test
==GL_FALSE
) {
1110 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.ZPassFunc
, mask
);
1113 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
1116 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
1118 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
1121 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
1122 passmask
[i
] = oldmask
[i
] & mask
[i
];
1123 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
1126 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
1127 apply_stencil_op_to_pixels( ctx
, n
, x
, y
,
1128 ctx
->Stencil
.ZFailFunc
, failmask
);
1130 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
1131 apply_stencil_op_to_pixels( ctx
, n
, x
, y
,
1132 ctx
->Stencil
.ZPassFunc
, passmask
);
1136 return GL_TRUE
; /* one or more fragments passed both tests */
1143 * Return a span of stencil values from the stencil buffer.
1144 * Used for glRead/CopyPixels
1145 * Input: n - how many pixels
1146 * x,y - location of first pixel
1147 * Output: stencil - the array of stencil values
1150 _mesa_read_stencil_span( GLcontext
*ctx
,
1151 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1153 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1154 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1155 /* span is completely outside framebuffer */
1156 return; /* undefined values OK */
1165 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1166 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1175 if (ctx
->Driver
.ReadStencilSpan
) {
1176 (*ctx
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1178 else if (ctx
->DrawBuffer
->Stencil
) {
1179 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1180 #if STENCIL_BITS == 8
1181 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1193 * Write a span of stencil values to the stencil buffer.
1194 * Used for glDraw/CopyPixels
1195 * Input: n - how many pixels
1196 * x, y - location of first pixel
1197 * stencil - the array of stencil values
1200 _mesa_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1201 const GLstencil stencil
[] )
1203 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1204 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1205 /* span is completely outside framebuffer */
1206 return; /* undefined values OK */
1215 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1216 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1223 if (ctx
->Driver
.WriteStencilSpan
) {
1224 (*ctx
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, stencil
, NULL
);
1226 else if (ctx
->DrawBuffer
->Stencil
) {
1227 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1228 #if STENCIL_BITS == 8
1229 MEMCPY( s
, stencil
, n
* sizeof(GLstencil
) );
1241 * Allocate a new stencil buffer. If there's an old one it will be
1242 * deallocated first. The new stencil buffer will be uninitialized.
1245 _mesa_alloc_stencil_buffer( GLcontext
*ctx
)
1247 GLuint buffersize
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1249 /* deallocate current stencil buffer if present */
1250 if (ctx
->DrawBuffer
->Stencil
) {
1251 FREE(ctx
->DrawBuffer
->Stencil
);
1252 ctx
->DrawBuffer
->Stencil
= NULL
;
1255 /* allocate new stencil buffer */
1256 ctx
->DrawBuffer
->Stencil
= (GLstencil
*) MALLOC(buffersize
* sizeof(GLstencil
));
1257 if (!ctx
->DrawBuffer
->Stencil
) {
1259 _mesa_set_enable( ctx
, GL_STENCIL_TEST
, GL_FALSE
);
1260 gl_error( ctx
, GL_OUT_OF_MEMORY
, "_mesa_alloc_stencil_buffer" );
1267 * Clear the software (malloc'd) stencil buffer.
1270 clear_software_stencil_buffer( GLcontext
*ctx
)
1272 if (ctx
->Visual
.StencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1273 /* no stencil buffer */
1277 if (ctx
->Scissor
.Enabled
) {
1278 /* clear scissor region only */
1279 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
;
1280 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1281 /* must apply mask to the clear */
1283 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1284 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1285 const GLstencil invMask
= ~mask
;
1286 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1287 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1289 for (i
= 0; i
< width
; i
++) {
1290 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1297 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1298 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1300 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1303 for (i
= 0; i
< width
; i
++)
1304 stencil
[x
] = ctx
->Stencil
.Clear
;
1310 /* clear whole stencil buffer */
1311 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1312 /* must apply mask to the clear */
1313 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1314 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1315 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1316 const GLstencil invMask
= ~mask
;
1317 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1319 for (i
= 0; i
< n
; i
++) {
1320 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1324 /* clear whole buffer without masking */
1325 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1326 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1329 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1332 for (i
= 0; i
< n
; i
++) {
1333 stencil
[i
] = ctx
->Stencil
.Clear
;
1343 * Clear the hardware (in graphics card) stencil buffer.
1344 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1346 * Actually, if there is a hardware stencil buffer it really should have
1347 * been cleared in Driver.Clear()! However, if the hardware does not
1348 * support scissored clears or masked clears (i.e. glStencilMask) then
1349 * we have to use the span-based functions.
1352 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1354 ASSERT(ctx
->Driver
.WriteStencilSpan
);
1355 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1357 if (ctx
->Scissor
.Enabled
) {
1358 /* clear scissor region only */
1359 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1360 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
;
1361 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1362 /* must apply mask to the clear */
1364 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1365 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1366 const GLstencil invMask
= ~mask
;
1367 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1368 GLstencil stencil
[MAX_WIDTH
];
1370 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1371 for (i
= 0; i
< width
; i
++) {
1372 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1374 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1379 GLstencil stencil
[MAX_WIDTH
];
1381 for (i
= 0; i
< width
; i
++) {
1382 stencil
[i
] = ctx
->Stencil
.Clear
;
1384 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1385 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1390 /* clear whole stencil buffer */
1391 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1392 /* must apply mask to the clear */
1393 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1394 const GLstencil invMask
= ~mask
;
1395 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1396 const GLint width
= ctx
->DrawBuffer
->Width
;
1397 const GLint height
= ctx
->DrawBuffer
->Height
;
1398 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1400 for (y
= 0; y
< height
; y
++) {
1401 GLstencil stencil
[MAX_WIDTH
];
1403 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1404 for (i
= 0; i
< width
; i
++) {
1405 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1407 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1411 /* clear whole buffer without masking */
1412 const GLint width
= ctx
->DrawBuffer
->Width
;
1413 const GLint height
= ctx
->DrawBuffer
->Width
;
1414 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1415 GLstencil stencil
[MAX_WIDTH
];
1417 for (i
= 0; i
< width
; i
++) {
1418 stencil
[i
] = ctx
->Stencil
.Clear
;
1420 for (y
= 0; y
< height
; y
++) {
1421 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1430 * Clear the stencil buffer.
1433 _mesa_clear_stencil_buffer( GLcontext
*ctx
)
1435 if (ctx
->Driver
.WriteStencilSpan
) {
1436 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1437 clear_hardware_stencil_buffer(ctx
);
1440 clear_software_stencil_buffer(ctx
);