1 /* $Id: stencil.c,v 1.21 2000/10/30 13:32:01 keithw 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
;
51 ctx
->NewState
|= _NEW_STENCIL
;
53 if (ctx
->Driver
.ClearStencil
) {
54 (*ctx
->Driver
.ClearStencil
)( ctx
, s
);
61 _mesa_StencilFunc( GLenum func
, GLint ref
, GLuint mask
)
63 GET_CURRENT_CONTEXT(ctx
);
66 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glStencilFunc");
77 ctx
->Stencil
.Function
= func
;
80 gl_error( ctx
, GL_INVALID_ENUM
, "glStencilFunc" );
84 maxref
= (1 << STENCIL_BITS
) - 1;
85 ctx
->Stencil
.Ref
= (GLstencil
) CLAMP( ref
, 0, maxref
);
86 ctx
->Stencil
.ValueMask
= (GLstencil
) mask
;
87 ctx
->NewState
|= _NEW_STENCIL
;
89 if (ctx
->Driver
.StencilFunc
) {
90 (*ctx
->Driver
.StencilFunc
)( ctx
, func
, ctx
->Stencil
.Ref
, mask
);
97 _mesa_StencilMask( GLuint mask
)
99 GET_CURRENT_CONTEXT(ctx
);
100 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glStencilMask");
101 ctx
->Stencil
.WriteMask
= (GLstencil
) mask
;
102 ctx
->NewState
|= _NEW_STENCIL
;
104 if (ctx
->Driver
.StencilMask
) {
105 (*ctx
->Driver
.StencilMask
)( ctx
, mask
);
112 _mesa_StencilOp(GLenum fail
, GLenum zfail
, GLenum zpass
)
114 GET_CURRENT_CONTEXT(ctx
);
115 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glStencilOp");
123 ctx
->Stencil
.FailFunc
= fail
;
125 case GL_INCR_WRAP_EXT
:
126 case GL_DECR_WRAP_EXT
:
127 if (ctx
->Extensions
.EXT_stencil_wrap
) {
128 ctx
->Stencil
.FailFunc
= fail
;
133 gl_error(ctx
, GL_INVALID_ENUM
, "glStencilOp");
143 ctx
->Stencil
.ZFailFunc
= zfail
;
145 case GL_INCR_WRAP_EXT
:
146 case GL_DECR_WRAP_EXT
:
147 if (ctx
->Extensions
.EXT_stencil_wrap
) {
148 ctx
->Stencil
.ZFailFunc
= zfail
;
153 gl_error(ctx
, GL_INVALID_ENUM
, "glStencilOp");
163 ctx
->Stencil
.ZPassFunc
= zpass
;
165 case GL_INCR_WRAP_EXT
:
166 case GL_DECR_WRAP_EXT
:
167 if (ctx
->Extensions
.EXT_stencil_wrap
) {
168 ctx
->Stencil
.ZPassFunc
= zpass
;
173 gl_error(ctx
, GL_INVALID_ENUM
, "glStencilOp");
177 ctx
->NewState
|= _NEW_STENCIL
;
179 if (ctx
->Driver
.StencilOp
) {
180 (*ctx
->Driver
.StencilOp
)(ctx
, fail
, zfail
, zpass
);
188 IF stencil test fails THEN
189 Apply fail-op to stencil value
190 Don't write the pixel (RGBA,Z)
192 IF doing depth test && depth test fails THEN
193 Apply zfail-op to stencil value
194 Write RGBA and Z to appropriate buffers
196 Apply zpass-op to stencil value
205 * Return the address of a stencil buffer value given the window coords:
207 #define STENCIL_ADDRESS(X,Y) \
208 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
213 * Apply the given stencil operator to the array of stencil values.
214 * Don't touch stencil[i] if mask[i] is zero.
215 * Input: n - size of stencil array
216 * oper - the stencil buffer operator
217 * stencil - array of stencil values
218 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
219 * Output: stencil - modified values
221 static void apply_stencil_op( const GLcontext
*ctx
, GLenum oper
,
222 GLuint n
, GLstencil stencil
[],
223 const GLubyte mask
[] )
225 const GLstencil ref
= ctx
->Stencil
.Ref
;
226 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
227 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
245 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
261 GLstencil s
= stencil
[i
];
262 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
271 GLstencil s
= stencil
[i
];
272 if (s
< STENCIL_MAX
) {
273 stencil
[i
] = (GLstencil
) (s
+1);
281 /* VERIFY logic of adding 1 to a write-masked value */
282 GLstencil s
= stencil
[i
];
283 if (s
< STENCIL_MAX
) {
284 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
294 GLstencil s
= stencil
[i
];
296 stencil
[i
] = (GLstencil
) (s
-1);
304 /* VERIFY logic of subtracting 1 to a write-masked value */
305 GLstencil s
= stencil
[i
];
307 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
313 case GL_INCR_WRAP_EXT
:
324 GLstencil s
= stencil
[i
];
325 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
330 case GL_DECR_WRAP_EXT
:
341 GLstencil s
= stencil
[i
];
342 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
351 GLstencil s
= stencil
[i
];
352 stencil
[i
] = (GLstencil
) ~s
;
359 GLstencil s
= stencil
[i
];
360 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
366 gl_problem(ctx
, "Bad stencil op in apply_stencil_op");
374 * Apply stencil test to an array of stencil values (before depth buffering).
375 * Input: n - number of pixels in the array
376 * stencil - array of [n] stencil values
377 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
378 * Output: mask - pixels which fail the stencil test will have their
379 * mask flag set to 0.
380 * stencil - updated stencil values (where the test passed)
381 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
384 do_stencil_test( GLcontext
*ctx
, GLuint n
, GLstencil stencil
[],
387 GLubyte fail
[PB_SIZE
];
388 GLboolean allfail
= GL_FALSE
;
392 ASSERT(n
<= PB_SIZE
);
395 * Perform stencil test. The results of this operation are stored
396 * in the fail[] array:
397 * IF fail[i] is non-zero THEN
398 * the stencil fail operator is to be applied
400 * the stencil fail operator is not to be applied
403 switch (ctx
->Stencil
.Function
) {
418 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
421 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
437 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
440 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
456 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
459 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
475 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
478 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
494 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
497 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
513 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
516 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
538 gl_problem(ctx
, "Bad stencil func in gl_stencil_span");
542 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
543 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
, n
, stencil
, fail
);
553 * Apply stencil and depth testing to an array of pixels.
554 * Hardware or software stencil buffer acceptable.
555 * Input: n - number of pixels in the span
556 * z - array [n] of z values
557 * stencil - array [n] of stencil values
558 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
559 * Output: stencil - modified stencil values
560 * mask - array [n] of flags (1=stencil and depth test passed)
561 * Return: GL_TRUE - all fragments failed the testing
562 * GL_FALSE - one or more fragments passed the testing
566 stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
567 const GLdepth z
[], GLstencil stencil
[],
570 ASSERT(ctx
->Stencil
.Enabled
);
571 ASSERT(n
<= PB_SIZE
);
574 * Apply the stencil test to the fragments.
575 * failMask[i] is 1 if the stencil test failed.
577 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
578 /* all fragments failed the stencil test, we're done. */
584 * Some fragments passed the stencil test, apply depth test to them
585 * and apply Zpass and Zfail stencil ops.
587 if (ctx
->Depth
.Test
==GL_FALSE
) {
589 * No depth buffer, just apply zpass stencil function to active pixels.
591 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
595 * Perform depth buffering, then apply zpass or zfail stencil function.
597 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
600 /* save the current mask bits */
601 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
603 /* apply the depth test */
604 _mesa_depth_test_span(ctx
, n
, x
, y
, z
, mask
);
606 /* Set the stencil pass/fail flags according to result of depth testing.
607 * if oldmask[i] == 0 then
608 * Don't touch the stencil value
609 * else if oldmask[i] and newmask[i] then
612 * assert(oldmask[i] && !newmask[i])
617 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
618 passmask
[i
] = oldmask
[i
] & mask
[i
];
619 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
622 /* apply the pass and fail operations */
623 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
624 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
626 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
627 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
631 return GL_TRUE
; /* one or more fragments passed both tests */
637 * Apply stencil and depth testing to the span of pixels.
638 * Both software and hardware stencil buffers are acceptable.
639 * Input: n - number of pixels in the span
640 * x, y - location of leftmost pixel in span
641 * z - array [n] of z values
642 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
643 * Output: mask - array [n] of flags (1=stencil and depth test passed)
644 * Return: GL_TRUE - all fragments failed the testing
645 * GL_FALSE - one or more fragments passed the testing
649 _mesa_stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
650 const GLdepth z
[], GLubyte mask
[] )
652 GLstencil stencilRow
[MAX_WIDTH
];
656 ASSERT(ctx
->Stencil
.Enabled
);
657 ASSERT(n
<= MAX_WIDTH
);
659 /* Get initial stencil values */
660 if (ctx
->Driver
.WriteStencilSpan
) {
661 ASSERT(ctx
->Driver
.ReadStencilSpan
);
662 /* Get stencil values from the hardware stencil buffer */
663 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, n
, x
, y
, stencilRow
);
664 stencil
= stencilRow
;
667 /* software stencil buffer */
668 stencil
= STENCIL_ADDRESS(x
, y
);
671 /* do all the stencil/depth testing/updating */
672 result
= stencil_and_ztest_span( ctx
, n
, x
, y
, z
, stencil
, mask
);
674 if (ctx
->Driver
.WriteStencilSpan
) {
675 /* Write updated stencil values into hardware stencil buffer */
676 (ctx
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
686 * Apply the given stencil operator for each pixel in the array whose
687 * mask flag is set. This is for software stencil buffers only.
688 * Input: n - number of pixels in the span
689 * x, y - array of [n] pixels
690 * operator - the stencil buffer operator
691 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
694 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
695 GLuint n
, const GLint x
[], const GLint y
[],
696 GLenum oper
, const GLubyte mask
[] )
698 const GLstencil ref
= ctx
->Stencil
.Ref
;
699 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
700 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
703 ASSERT(!ctx
->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
713 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
721 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
722 *sptr
= (GLstencil
) (invmask
& *sptr
);
731 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
739 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
740 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
749 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
750 if (*sptr
< STENCIL_MAX
) {
751 *sptr
= (GLstencil
) (*sptr
+ 1);
759 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
760 if (*sptr
< STENCIL_MAX
) {
761 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
771 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
773 *sptr
= (GLstencil
) (*sptr
- 1);
781 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
783 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
789 case GL_INCR_WRAP_EXT
:
793 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
794 *sptr
= (GLstencil
) (*sptr
+ 1);
801 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
802 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
807 case GL_DECR_WRAP_EXT
:
811 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
812 *sptr
= (GLstencil
) (*sptr
- 1);
819 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
820 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
829 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
830 *sptr
= (GLstencil
) (~*sptr
);
837 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
838 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
844 gl_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
851 * Apply stencil test to an array of pixels before depth buffering.
852 * Used for software stencil buffer only.
853 * Input: n - number of pixels in the span
854 * x, y - array of [n] pixels to stencil
855 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
856 * Output: mask - pixels which fail the stencil test will have their
857 * mask flag set to 0.
858 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
861 stencil_test_pixels( GLcontext
*ctx
, GLuint n
,
862 const GLint x
[], const GLint y
[], GLubyte mask
[] )
864 GLubyte fail
[PB_SIZE
];
867 GLboolean allfail
= GL_FALSE
;
869 ASSERT(!ctx
->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
872 * Perform stencil test. The results of this operation are stored
873 * in the fail[] array:
874 * IF fail[i] is non-zero THEN
875 * the stencil fail operator is to be applied
877 * the stencil fail operator is not to be applied
881 switch (ctx
->Stencil
.Function
) {
896 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
899 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
900 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
916 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
919 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
920 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
936 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
939 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
940 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
956 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
959 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
960 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
976 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
979 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
980 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
996 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
999 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
1000 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
1022 gl_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
1026 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
1027 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
, fail
);
1037 * Apply stencil and depth testing to an array of pixels.
1038 * This is used both for software and hardware stencil buffers.
1040 * The comments in this function are a bit sparse but the code is
1041 * almost identical to stencil_and_ztest_span(), which is well
1044 * Input: n - number of pixels in the array
1045 * x, y - array of [n] pixel positions
1046 * z - array [n] of z values
1047 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
1048 * Output: mask - array [n] of flags (1=stencil and depth test passed)
1049 * Return: GL_TRUE - all fragments failed the testing
1050 * GL_FALSE - one or more fragments passed the testing
1053 _mesa_stencil_and_ztest_pixels( GLcontext
*ctx
,
1054 GLuint n
, const GLint x
[], const GLint y
[],
1055 const GLdepth z
[], GLubyte mask
[] )
1057 ASSERT(ctx
->Stencil
.Enabled
);
1058 ASSERT(n
<= PB_SIZE
);
1060 if (ctx
->Driver
.WriteStencilPixels
) {
1061 /*** Hardware stencil buffer ***/
1062 GLstencil stencil
[PB_SIZE
];
1063 GLubyte mask
[PB_SIZE
];
1065 ASSERT(ctx
->Driver
.ReadStencilPixels
);
1066 (*ctx
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
1069 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
1070 /* all fragments failed the stencil test, we're done. */
1074 if (ctx
->Depth
.Test
== GL_FALSE
) {
1075 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
1078 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
1081 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
1083 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
1086 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
1087 passmask
[i
] = oldmask
[i
] & mask
[i
];
1088 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
1091 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
1092 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
1094 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
1095 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
1099 /* Write updated stencil values into hardware stencil buffer */
1100 (ctx
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, mask
);
1106 /*** Software stencil buffer ***/
1108 if (stencil_test_pixels(ctx
, n
, x
, y
, mask
) == GL_FALSE
) {
1109 /* all fragments failed the stencil test, we're done. */
1114 if (ctx
->Depth
.Test
==GL_FALSE
) {
1115 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.ZPassFunc
, mask
);
1118 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
1121 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
1123 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
1126 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
1127 passmask
[i
] = oldmask
[i
] & mask
[i
];
1128 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
1131 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
1132 apply_stencil_op_to_pixels( ctx
, n
, x
, y
,
1133 ctx
->Stencil
.ZFailFunc
, failmask
);
1135 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
1136 apply_stencil_op_to_pixels( ctx
, n
, x
, y
,
1137 ctx
->Stencil
.ZPassFunc
, passmask
);
1141 return GL_TRUE
; /* one or more fragments passed both tests */
1148 * Return a span of stencil values from the stencil buffer.
1149 * Used for glRead/CopyPixels
1150 * Input: n - how many pixels
1151 * x,y - location of first pixel
1152 * Output: stencil - the array of stencil values
1155 _mesa_read_stencil_span( GLcontext
*ctx
,
1156 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1158 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1159 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1160 /* span is completely outside framebuffer */
1161 return; /* undefined values OK */
1170 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1171 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1180 if (ctx
->Driver
.ReadStencilSpan
) {
1181 (*ctx
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1183 else if (ctx
->DrawBuffer
->Stencil
) {
1184 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1185 #if STENCIL_BITS == 8
1186 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1198 * Write a span of stencil values to the stencil buffer.
1199 * Used for glDraw/CopyPixels
1200 * Input: n - how many pixels
1201 * x, y - location of first pixel
1202 * stencil - the array of stencil values
1205 _mesa_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1206 const GLstencil stencil
[] )
1208 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1209 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1210 /* span is completely outside framebuffer */
1211 return; /* undefined values OK */
1220 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1221 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1228 if (ctx
->Driver
.WriteStencilSpan
) {
1229 (*ctx
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, stencil
, NULL
);
1231 else if (ctx
->DrawBuffer
->Stencil
) {
1232 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1233 #if STENCIL_BITS == 8
1234 MEMCPY( s
, stencil
, n
* sizeof(GLstencil
) );
1246 * Allocate a new stencil buffer. If there's an old one it will be
1247 * deallocated first. The new stencil buffer will be uninitialized.
1250 _mesa_alloc_stencil_buffer( GLcontext
*ctx
)
1252 GLuint buffersize
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1254 /* deallocate current stencil buffer if present */
1255 if (ctx
->DrawBuffer
->Stencil
) {
1256 FREE(ctx
->DrawBuffer
->Stencil
);
1257 ctx
->DrawBuffer
->Stencil
= NULL
;
1260 /* allocate new stencil buffer */
1261 ctx
->DrawBuffer
->Stencil
= (GLstencil
*) MALLOC(buffersize
* sizeof(GLstencil
));
1262 if (!ctx
->DrawBuffer
->Stencil
) {
1264 _mesa_set_enable( ctx
, GL_STENCIL_TEST
, GL_FALSE
);
1265 gl_error( ctx
, GL_OUT_OF_MEMORY
, "_mesa_alloc_stencil_buffer" );
1272 * Clear the software (malloc'd) stencil buffer.
1275 clear_software_stencil_buffer( GLcontext
*ctx
)
1277 if (ctx
->Visual
.StencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1278 /* no stencil buffer */
1282 if (ctx
->Scissor
.Enabled
) {
1283 /* clear scissor region only */
1284 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
;
1285 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1286 /* must apply mask to the clear */
1288 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1289 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1290 const GLstencil invMask
= ~mask
;
1291 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1292 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1294 for (i
= 0; i
< width
; i
++) {
1295 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1302 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1303 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1305 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1308 for (i
= 0; i
< width
; i
++)
1309 stencil
[x
] = ctx
->Stencil
.Clear
;
1315 /* clear whole stencil buffer */
1316 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1317 /* must apply mask to the clear */
1318 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1319 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1320 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1321 const GLstencil invMask
= ~mask
;
1322 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1324 for (i
= 0; i
< n
; i
++) {
1325 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1329 /* clear whole buffer without masking */
1330 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1331 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1334 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1337 for (i
= 0; i
< n
; i
++) {
1338 stencil
[i
] = ctx
->Stencil
.Clear
;
1348 * Clear the hardware (in graphics card) stencil buffer.
1349 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1351 * Actually, if there is a hardware stencil buffer it really should have
1352 * been cleared in Driver.Clear()! However, if the hardware does not
1353 * support scissored clears or masked clears (i.e. glStencilMask) then
1354 * we have to use the span-based functions.
1357 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1359 ASSERT(ctx
->Driver
.WriteStencilSpan
);
1360 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1362 if (ctx
->Scissor
.Enabled
) {
1363 /* clear scissor region only */
1364 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1365 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
;
1366 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1367 /* must apply mask to the clear */
1369 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1370 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1371 const GLstencil invMask
= ~mask
;
1372 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1373 GLstencil stencil
[MAX_WIDTH
];
1375 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1376 for (i
= 0; i
< width
; i
++) {
1377 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1379 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1384 GLstencil stencil
[MAX_WIDTH
];
1386 for (i
= 0; i
< width
; i
++) {
1387 stencil
[i
] = ctx
->Stencil
.Clear
;
1389 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1390 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1395 /* clear whole stencil buffer */
1396 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1397 /* must apply mask to the clear */
1398 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1399 const GLstencil invMask
= ~mask
;
1400 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1401 const GLint width
= ctx
->DrawBuffer
->Width
;
1402 const GLint height
= ctx
->DrawBuffer
->Height
;
1403 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1405 for (y
= 0; y
< height
; y
++) {
1406 GLstencil stencil
[MAX_WIDTH
];
1408 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1409 for (i
= 0; i
< width
; i
++) {
1410 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1412 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1416 /* clear whole buffer without masking */
1417 const GLint width
= ctx
->DrawBuffer
->Width
;
1418 const GLint height
= ctx
->DrawBuffer
->Width
;
1419 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1420 GLstencil stencil
[MAX_WIDTH
];
1422 for (i
= 0; i
< width
; i
++) {
1423 stencil
[i
] = ctx
->Stencil
.Clear
;
1425 for (y
= 0; y
< height
; y
++) {
1426 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1435 * Clear the stencil buffer.
1438 _mesa_clear_stencil_buffer( GLcontext
*ctx
)
1440 if (ctx
->Driver
.WriteStencilSpan
) {
1441 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1442 clear_hardware_stencil_buffer(ctx
);
1445 clear_software_stencil_buffer(ctx
);