1 /* $Id: stencil.c,v 1.19 2000/09/26 20:53:53 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.
45 _mesa_ClearStencil( GLint s
)
47 GET_CURRENT_CONTEXT(ctx
);
48 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glClearStencil");
49 ctx
->Stencil
.Clear
= (GLstencil
) s
;
51 if (ctx
->Driver
.ClearStencil
) {
52 (*ctx
->Driver
.ClearStencil
)( ctx
, s
);
59 _mesa_StencilFunc( GLenum func
, GLint ref
, GLuint mask
)
61 GET_CURRENT_CONTEXT(ctx
);
64 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glStencilFunc");
75 ctx
->Stencil
.Function
= func
;
78 gl_error( ctx
, GL_INVALID_ENUM
, "glStencilFunc" );
82 maxref
= (1 << STENCIL_BITS
) - 1;
83 ctx
->Stencil
.Ref
= (GLstencil
) CLAMP( ref
, 0, maxref
);
84 ctx
->Stencil
.ValueMask
= (GLstencil
) mask
;
86 if (ctx
->Driver
.StencilFunc
) {
87 (*ctx
->Driver
.StencilFunc
)( ctx
, func
, ctx
->Stencil
.Ref
, mask
);
94 _mesa_StencilMask( GLuint mask
)
96 GET_CURRENT_CONTEXT(ctx
);
97 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glStencilMask");
98 ctx
->Stencil
.WriteMask
= (GLstencil
) mask
;
100 if (ctx
->Driver
.StencilMask
) {
101 (*ctx
->Driver
.StencilMask
)( ctx
, mask
);
108 _mesa_StencilOp(GLenum fail
, GLenum zfail
, GLenum zpass
)
110 GET_CURRENT_CONTEXT(ctx
);
111 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glStencilOp");
119 ctx
->Stencil
.FailFunc
= fail
;
121 case GL_INCR_WRAP_EXT
:
122 case GL_DECR_WRAP_EXT
:
123 if (ctx
->Extensions
.HaveStencilWrap
) {
124 ctx
->Stencil
.FailFunc
= fail
;
129 gl_error(ctx
, GL_INVALID_ENUM
, "glStencilOp");
139 ctx
->Stencil
.ZFailFunc
= zfail
;
141 case GL_INCR_WRAP_EXT
:
142 case GL_DECR_WRAP_EXT
:
143 if (ctx
->Extensions
.HaveStencilWrap
) {
144 ctx
->Stencil
.ZFailFunc
= zfail
;
149 gl_error(ctx
, GL_INVALID_ENUM
, "glStencilOp");
159 ctx
->Stencil
.ZPassFunc
= zpass
;
161 case GL_INCR_WRAP_EXT
:
162 case GL_DECR_WRAP_EXT
:
163 if (ctx
->Extensions
.HaveStencilWrap
) {
164 ctx
->Stencil
.ZPassFunc
= zpass
;
169 gl_error(ctx
, GL_INVALID_ENUM
, "glStencilOp");
173 if (ctx
->Driver
.StencilOp
) {
174 (*ctx
->Driver
.StencilOp
)(ctx
, fail
, zfail
, zpass
);
182 IF stencil test fails THEN
183 Apply fail-op to stencil value
184 Don't write the pixel (RGBA,Z)
186 IF doing depth test && depth test fails THEN
187 Apply zfail-op to stencil value
188 Write RGBA and Z to appropriate buffers
190 Apply zpass-op to stencil value
199 * Return the address of a stencil buffer value given the window coords:
201 #define STENCIL_ADDRESS(X,Y) \
202 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
207 * Apply the given stencil operator to the array of stencil values.
208 * Don't touch stencil[i] if mask[i] is zero.
209 * Input: n - size of stencil array
210 * oper - the stencil buffer operator
211 * stencil - array of stencil values
212 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
213 * Output: stencil - modified values
215 static void apply_stencil_op( const GLcontext
*ctx
, GLenum oper
,
216 GLuint n
, GLstencil stencil
[],
217 const GLubyte mask
[] )
219 const GLstencil ref
= ctx
->Stencil
.Ref
;
220 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
221 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
239 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
255 GLstencil s
= stencil
[i
];
256 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
265 GLstencil s
= stencil
[i
];
266 if (s
< STENCIL_MAX
) {
267 stencil
[i
] = (GLstencil
) (s
+1);
275 /* VERIFY logic of adding 1 to a write-masked value */
276 GLstencil s
= stencil
[i
];
277 if (s
< STENCIL_MAX
) {
278 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
288 GLstencil s
= stencil
[i
];
290 stencil
[i
] = (GLstencil
) (s
-1);
298 /* VERIFY logic of subtracting 1 to a write-masked value */
299 GLstencil s
= stencil
[i
];
301 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
307 case GL_INCR_WRAP_EXT
:
318 GLstencil s
= stencil
[i
];
319 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
324 case GL_DECR_WRAP_EXT
:
335 GLstencil s
= stencil
[i
];
336 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
345 GLstencil s
= stencil
[i
];
346 stencil
[i
] = (GLstencil
) ~s
;
353 GLstencil s
= stencil
[i
];
354 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
360 gl_problem(ctx
, "Bad stencil op in apply_stencil_op");
368 * Apply stencil test to an array of stencil values (before depth buffering).
369 * Input: n - number of pixels in the array
370 * stencil - array of [n] stencil values
371 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
372 * Output: mask - pixels which fail the stencil test will have their
373 * mask flag set to 0.
374 * stencil - updated stencil values (where the test passed)
375 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
378 do_stencil_test( GLcontext
*ctx
, GLuint n
, GLstencil stencil
[],
381 GLubyte fail
[PB_SIZE
];
382 GLboolean allfail
= GL_FALSE
;
386 ASSERT(n
<= PB_SIZE
);
389 * Perform stencil test. The results of this operation are stored
390 * in the fail[] array:
391 * IF fail[i] is non-zero THEN
392 * the stencil fail operator is to be applied
394 * the stencil fail operator is not to be applied
397 switch (ctx
->Stencil
.Function
) {
412 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
415 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
431 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
434 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
450 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
453 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
469 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
472 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
488 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
491 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
507 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
510 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
532 gl_problem(ctx
, "Bad stencil func in gl_stencil_span");
536 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
537 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
, n
, stencil
, fail
);
547 * Apply stencil and depth testing to an array of pixels.
548 * Hardware or software stencil buffer acceptable.
549 * Input: n - number of pixels in the span
550 * z - array [n] of z values
551 * stencil - array [n] of stencil values
552 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
553 * Output: stencil - modified stencil values
554 * mask - array [n] of flags (1=stencil and depth test passed)
555 * Return: GL_TRUE - all fragments failed the testing
556 * GL_FALSE - one or more fragments passed the testing
560 stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
561 const GLdepth z
[], GLstencil stencil
[],
564 ASSERT(ctx
->Stencil
.Enabled
);
565 ASSERT(n
<= PB_SIZE
);
568 * Apply the stencil test to the fragments.
569 * failMask[i] is 1 if the stencil test failed.
571 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
572 /* all fragments failed the stencil test, we're done. */
578 * Some fragments passed the stencil test, apply depth test to them
579 * and apply Zpass and Zfail stencil ops.
581 if (ctx
->Depth
.Test
==GL_FALSE
) {
583 * No depth buffer, just apply zpass stencil function to active pixels.
585 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
589 * Perform depth buffering, then apply zpass or zfail stencil function.
591 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
594 /* save the current mask bits */
595 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
597 /* apply the depth test */
598 _mesa_depth_test_span(ctx
, n
, x
, y
, z
, mask
);
600 /* Set the stencil pass/fail flags according to result of depth testing.
601 * if oldmask[i] == 0 then
602 * Don't touch the stencil value
603 * else if oldmask[i] and newmask[i] then
606 * assert(oldmask[i] && !newmask[i])
611 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
612 passmask
[i
] = oldmask
[i
] & mask
[i
];
613 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
616 /* apply the pass and fail operations */
617 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
618 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
620 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
621 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
625 return GL_TRUE
; /* one or more fragments passed both tests */
631 * Apply stencil and depth testing to the span of pixels.
632 * Both software and hardware stencil buffers are acceptable.
633 * Input: n - number of pixels in the span
634 * x, y - location of leftmost pixel in span
635 * z - array [n] of z values
636 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
637 * Output: mask - array [n] of flags (1=stencil and depth test passed)
638 * Return: GL_TRUE - all fragments failed the testing
639 * GL_FALSE - one or more fragments passed the testing
643 _mesa_stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
644 const GLdepth z
[], GLubyte mask
[] )
646 GLstencil stencilRow
[MAX_WIDTH
];
650 ASSERT(ctx
->Stencil
.Enabled
);
651 ASSERT(n
<= MAX_WIDTH
);
653 /* Get initial stencil values */
654 if (ctx
->Driver
.WriteStencilSpan
) {
655 ASSERT(ctx
->Driver
.ReadStencilSpan
);
656 /* Get stencil values from the hardware stencil buffer */
657 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, n
, x
, y
, stencilRow
);
658 stencil
= stencilRow
;
661 /* software stencil buffer */
662 stencil
= STENCIL_ADDRESS(x
, y
);
665 /* do all the stencil/depth testing/updating */
666 result
= stencil_and_ztest_span( ctx
, n
, x
, y
, z
, stencil
, mask
);
668 if (ctx
->Driver
.WriteStencilSpan
) {
669 /* Write updated stencil values into hardware stencil buffer */
670 (ctx
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
680 * Apply the given stencil operator for each pixel in the array whose
681 * mask flag is set. This is for software stencil buffers only.
682 * Input: n - number of pixels in the span
683 * x, y - array of [n] pixels
684 * operator - the stencil buffer operator
685 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
688 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
689 GLuint n
, const GLint x
[], const GLint y
[],
690 GLenum oper
, const GLubyte mask
[] )
692 const GLstencil ref
= ctx
->Stencil
.Ref
;
693 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
694 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
697 ASSERT(!ctx
->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
707 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
715 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
716 *sptr
= (GLstencil
) (invmask
& *sptr
);
725 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
733 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
734 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
743 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
744 if (*sptr
< STENCIL_MAX
) {
745 *sptr
= (GLstencil
) (*sptr
+ 1);
753 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
754 if (*sptr
< STENCIL_MAX
) {
755 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
765 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
767 *sptr
= (GLstencil
) (*sptr
- 1);
775 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
777 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
783 case GL_INCR_WRAP_EXT
:
787 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
788 *sptr
= (GLstencil
) (*sptr
+ 1);
795 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
796 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
801 case GL_DECR_WRAP_EXT
:
805 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
806 *sptr
= (GLstencil
) (*sptr
- 1);
813 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
814 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
823 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
824 *sptr
= (GLstencil
) (~*sptr
);
831 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
832 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
838 gl_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
845 * Apply stencil test to an array of pixels before depth buffering.
846 * Used for software stencil buffer only.
847 * Input: n - number of pixels in the span
848 * x, y - array of [n] pixels to stencil
849 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
850 * Output: mask - pixels which fail the stencil test will have their
851 * mask flag set to 0.
852 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
855 stencil_test_pixels( GLcontext
*ctx
, GLuint n
,
856 const GLint x
[], const GLint y
[], GLubyte mask
[] )
858 GLubyte fail
[PB_SIZE
];
861 GLboolean allfail
= GL_FALSE
;
863 ASSERT(!ctx
->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
866 * Perform stencil test. The results of this operation are stored
867 * in the fail[] array:
868 * IF fail[i] is non-zero THEN
869 * the stencil fail operator is to be applied
871 * the stencil fail operator is not to be applied
875 switch (ctx
->Stencil
.Function
) {
890 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
893 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
894 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
910 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
913 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
914 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
930 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
933 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
934 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
950 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
953 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
954 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
970 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
973 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
974 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
990 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
993 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
994 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
1016 gl_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
1020 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
1021 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
, fail
);
1031 * Apply stencil and depth testing to an array of pixels.
1032 * This is used both for software and hardware stencil buffers.
1034 * The comments in this function are a bit sparse but the code is
1035 * almost identical to stencil_and_ztest_span(), which is well
1038 * Input: n - number of pixels in the array
1039 * x, y - array of [n] pixel positions
1040 * z - array [n] of z values
1041 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
1042 * Output: mask - array [n] of flags (1=stencil and depth test passed)
1043 * Return: GL_TRUE - all fragments failed the testing
1044 * GL_FALSE - one or more fragments passed the testing
1047 _mesa_stencil_and_ztest_pixels( GLcontext
*ctx
,
1048 GLuint n
, const GLint x
[], const GLint y
[],
1049 const GLdepth z
[], GLubyte mask
[] )
1051 ASSERT(ctx
->Stencil
.Enabled
);
1052 ASSERT(n
<= PB_SIZE
);
1054 if (ctx
->Driver
.WriteStencilPixels
) {
1055 /*** Hardware stencil buffer ***/
1056 GLstencil stencil
[PB_SIZE
];
1057 GLubyte mask
[PB_SIZE
];
1059 ASSERT(ctx
->Driver
.ReadStencilPixels
);
1060 (*ctx
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
1063 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
1064 /* all fragments failed the stencil test, we're done. */
1068 if (ctx
->Depth
.Test
== GL_FALSE
) {
1069 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
1072 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
1075 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
1077 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
1080 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
1081 passmask
[i
] = oldmask
[i
] & mask
[i
];
1082 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
1085 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
1086 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
1088 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
1089 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
1093 /* Write updated stencil values into hardware stencil buffer */
1094 (ctx
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, mask
);
1100 /*** Software stencil buffer ***/
1102 if (stencil_test_pixels(ctx
, n
, x
, y
, mask
) == GL_FALSE
) {
1103 /* all fragments failed the stencil test, we're done. */
1108 if (ctx
->Depth
.Test
==GL_FALSE
) {
1109 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.ZPassFunc
, mask
);
1112 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
1115 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
1117 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
1120 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
1121 passmask
[i
] = oldmask
[i
] & mask
[i
];
1122 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
1125 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
1126 apply_stencil_op_to_pixels( ctx
, n
, x
, y
,
1127 ctx
->Stencil
.ZFailFunc
, failmask
);
1129 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
1130 apply_stencil_op_to_pixels( ctx
, n
, x
, y
,
1131 ctx
->Stencil
.ZPassFunc
, passmask
);
1135 return GL_TRUE
; /* one or more fragments passed both tests */
1142 * Return a span of stencil values from the stencil buffer.
1143 * Used for glRead/CopyPixels
1144 * Input: n - how many pixels
1145 * x,y - location of first pixel
1146 * Output: stencil - the array of stencil values
1149 _mesa_read_stencil_span( GLcontext
*ctx
,
1150 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1152 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1153 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1154 /* span is completely outside framebuffer */
1155 return; /* undefined values OK */
1164 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1165 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1174 if (ctx
->Driver
.ReadStencilSpan
) {
1175 (*ctx
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1177 else if (ctx
->DrawBuffer
->Stencil
) {
1178 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1179 #if STENCIL_BITS == 8
1180 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1192 * Write a span of stencil values to the stencil buffer.
1193 * Used for glDraw/CopyPixels
1194 * Input: n - how many pixels
1195 * x, y - location of first pixel
1196 * stencil - the array of stencil values
1199 _mesa_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1200 const GLstencil stencil
[] )
1202 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1203 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1204 /* span is completely outside framebuffer */
1205 return; /* undefined values OK */
1214 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1215 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1222 if (ctx
->Driver
.WriteStencilSpan
) {
1223 (*ctx
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, stencil
, NULL
);
1225 else if (ctx
->DrawBuffer
->Stencil
) {
1226 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1227 #if STENCIL_BITS == 8
1228 MEMCPY( s
, stencil
, n
* sizeof(GLstencil
) );
1240 * Allocate a new stencil buffer. If there's an old one it will be
1241 * deallocated first. The new stencil buffer will be uninitialized.
1244 _mesa_alloc_stencil_buffer( GLcontext
*ctx
)
1246 GLuint buffersize
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1248 /* deallocate current stencil buffer if present */
1249 if (ctx
->DrawBuffer
->Stencil
) {
1250 FREE(ctx
->DrawBuffer
->Stencil
);
1251 ctx
->DrawBuffer
->Stencil
= NULL
;
1254 /* allocate new stencil buffer */
1255 ctx
->DrawBuffer
->Stencil
= (GLstencil
*) MALLOC(buffersize
* sizeof(GLstencil
));
1256 if (!ctx
->DrawBuffer
->Stencil
) {
1258 _mesa_set_enable( ctx
, GL_STENCIL_TEST
, GL_FALSE
);
1259 gl_error( ctx
, GL_OUT_OF_MEMORY
, "_mesa_alloc_stencil_buffer" );
1266 * Clear the software (malloc'd) stencil buffer.
1269 clear_software_stencil_buffer( GLcontext
*ctx
)
1271 if (ctx
->Visual
.StencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1272 /* no stencil buffer */
1276 if (ctx
->Scissor
.Enabled
) {
1277 /* clear scissor region only */
1278 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
;
1279 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1280 /* must apply mask to the clear */
1282 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1283 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1284 const GLstencil invMask
= ~mask
;
1285 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1286 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1288 for (i
= 0; i
< width
; i
++) {
1289 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1296 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1297 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1299 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1302 for (i
= 0; i
< width
; i
++)
1303 stencil
[x
] = ctx
->Stencil
.Clear
;
1309 /* clear whole stencil buffer */
1310 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1311 /* must apply mask to the clear */
1312 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1313 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1314 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1315 const GLstencil invMask
= ~mask
;
1316 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1318 for (i
= 0; i
< n
; i
++) {
1319 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1323 /* clear whole buffer without masking */
1324 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1325 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1328 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1331 for (i
= 0; i
< n
; i
++) {
1332 stencil
[i
] = ctx
->Stencil
.Clear
;
1342 * Clear the hardware (in graphics card) stencil buffer.
1343 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1345 * Actually, if there is a hardware stencil buffer it really should have
1346 * been cleared in Driver.Clear()! However, if the hardware does not
1347 * support scissored clears or masked clears (i.e. glStencilMask) then
1348 * we have to use the span-based functions.
1351 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1353 ASSERT(ctx
->Driver
.WriteStencilSpan
);
1354 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1356 if (ctx
->Scissor
.Enabled
) {
1357 /* clear scissor region only */
1358 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1359 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
;
1360 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1361 /* must apply mask to the clear */
1363 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1364 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1365 const GLstencil invMask
= ~mask
;
1366 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1367 GLstencil stencil
[MAX_WIDTH
];
1369 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1370 for (i
= 0; i
< width
; i
++) {
1371 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1373 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1378 GLstencil stencil
[MAX_WIDTH
];
1380 for (i
= 0; i
< width
; i
++) {
1381 stencil
[i
] = ctx
->Stencil
.Clear
;
1383 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1384 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1389 /* clear whole stencil buffer */
1390 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1391 /* must apply mask to the clear */
1392 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1393 const GLstencil invMask
= ~mask
;
1394 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1395 const GLint width
= ctx
->DrawBuffer
->Width
;
1396 const GLint height
= ctx
->DrawBuffer
->Height
;
1397 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1399 for (y
= 0; y
< height
; y
++) {
1400 GLstencil stencil
[MAX_WIDTH
];
1402 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1403 for (i
= 0; i
< width
; i
++) {
1404 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1406 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1410 /* clear whole buffer without masking */
1411 const GLint width
= ctx
->DrawBuffer
->Width
;
1412 const GLint height
= ctx
->DrawBuffer
->Width
;
1413 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1414 GLstencil stencil
[MAX_WIDTH
];
1416 for (i
= 0; i
< width
; i
++) {
1417 stencil
[i
] = ctx
->Stencil
.Clear
;
1419 for (y
= 0; y
< height
; y
++) {
1420 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1429 * Clear the stencil buffer.
1432 _mesa_clear_stencil_buffer( GLcontext
*ctx
)
1434 if (ctx
->Driver
.WriteStencilSpan
) {
1435 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1436 clear_hardware_stencil_buffer(ctx
);
1439 clear_software_stencil_buffer(ctx
);