488ccc0559ff2c76275fbd9e8f859bc4de887413
1 /* $Id: s_stencil.c,v 1.13 2001/12/17 04:54:35 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2001 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.
33 #include "s_context.h"
36 #include "s_stencil.h"
44 IF stencil test fails THEN
45 Apply fail-op to stencil value
46 Don't write the pixel (RGBA,Z)
48 IF doing depth test && depth test fails THEN
49 Apply zfail-op to stencil value
50 Write RGBA and Z to appropriate buffers
52 Apply zpass-op to stencil value
61 * Return the address of a stencil buffer value given the window coords:
63 #define STENCIL_ADDRESS(X,Y) \
64 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
69 * Apply the given stencil operator to the array of stencil values.
70 * Don't touch stencil[i] if mask[i] is zero.
71 * Input: n - size of stencil array
72 * oper - the stencil buffer operator
73 * stencil - array of stencil values
74 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
75 * Output: stencil - modified values
77 static void apply_stencil_op( const GLcontext
*ctx
, GLenum oper
,
78 GLuint n
, GLstencil stencil
[],
79 const GLubyte mask
[] )
81 const GLstencil ref
= ctx
->Stencil
.Ref
;
82 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
83 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
101 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
117 GLstencil s
= stencil
[i
];
118 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
127 GLstencil s
= stencil
[i
];
128 if (s
< STENCIL_MAX
) {
129 stencil
[i
] = (GLstencil
) (s
+1);
137 /* VERIFY logic of adding 1 to a write-masked value */
138 GLstencil s
= stencil
[i
];
139 if (s
< STENCIL_MAX
) {
140 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
150 GLstencil s
= stencil
[i
];
152 stencil
[i
] = (GLstencil
) (s
-1);
160 /* VERIFY logic of subtracting 1 to a write-masked value */
161 GLstencil s
= stencil
[i
];
163 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
169 case GL_INCR_WRAP_EXT
:
180 GLstencil s
= stencil
[i
];
181 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
186 case GL_DECR_WRAP_EXT
:
197 GLstencil s
= stencil
[i
];
198 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
207 GLstencil s
= stencil
[i
];
208 stencil
[i
] = (GLstencil
) ~s
;
215 GLstencil s
= stencil
[i
];
216 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
222 _mesa_problem(ctx
, "Bad stencil op in apply_stencil_op");
230 * Apply stencil test to an array of stencil values (before depth buffering).
231 * Input: n - number of pixels in the array
232 * stencil - array of [n] stencil values
233 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
234 * Output: mask - pixels which fail the stencil test will have their
235 * mask flag set to 0.
236 * stencil - updated stencil values (where the test passed)
237 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
240 do_stencil_test( GLcontext
*ctx
, GLuint n
, GLstencil stencil
[],
243 GLubyte fail
[PB_SIZE
];
244 GLboolean allfail
= GL_FALSE
;
248 ASSERT(n
<= PB_SIZE
);
251 * Perform stencil test. The results of this operation are stored
252 * in the fail[] array:
253 * IF fail[i] is non-zero THEN
254 * the stencil fail operator is to be applied
256 * the stencil fail operator is not to be applied
259 switch (ctx
->Stencil
.Function
) {
274 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
277 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
293 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
296 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
312 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
315 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
331 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
334 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
350 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
353 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
369 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
372 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
394 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_span");
398 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
399 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
, n
, stencil
, fail
);
409 * Apply stencil and depth testing to an array of pixels.
410 * Hardware or software stencil buffer acceptable.
411 * Input: n - number of pixels in the span
412 * z - array [n] of z values
413 * stencil - array [n] of stencil values
414 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
415 * Output: stencil - modified stencil values
416 * mask - array [n] of flags (1=stencil and depth test passed)
417 * Return: GL_TRUE - all fragments failed the testing
418 * GL_FALSE - one or more fragments passed the testing
422 stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
423 const GLdepth z
[], GLstencil stencil
[],
426 ASSERT(ctx
->Stencil
.Enabled
);
427 ASSERT(n
<= PB_SIZE
);
430 * Apply the stencil test to the fragments.
431 * failMask[i] is 1 if the stencil test failed.
433 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
434 /* all fragments failed the stencil test, we're done. */
440 * Some fragments passed the stencil test, apply depth test to them
441 * and apply Zpass and Zfail stencil ops.
443 if (ctx
->Depth
.Test
==GL_FALSE
) {
445 * No depth buffer, just apply zpass stencil function to active pixels.
447 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
451 * Perform depth buffering, then apply zpass or zfail stencil function.
453 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
456 /* save the current mask bits */
457 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
459 /* apply the depth test */
460 _old_depth_test_span(ctx
, n
, x
, y
, z
, mask
);
462 /* Set the stencil pass/fail flags according to result of depth testing.
463 * if oldmask[i] == 0 then
464 * Don't touch the stencil value
465 * else if oldmask[i] and newmask[i] then
468 * assert(oldmask[i] && !newmask[i])
473 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
474 passmask
[i
] = oldmask
[i
] & mask
[i
];
475 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
478 /* apply the pass and fail operations */
479 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
480 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
482 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
483 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
487 return GL_TRUE
; /* one or more fragments passed both tests */
493 * Apply stencil and depth testing to the span of pixels.
494 * Both software and hardware stencil buffers are acceptable.
495 * Input: n - number of pixels in the span
496 * x, y - location of leftmost pixel in span
497 * z - array [n] of z values
498 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
499 * Output: mask - array [n] of flags (1=stencil and depth test passed)
500 * Return: GL_TRUE - all fragments failed the testing
501 * GL_FALSE - one or more fragments passed the testing
505 _old_stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
506 const GLdepth z
[], GLubyte mask
[] )
508 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
509 GLstencil stencilRow
[MAX_WIDTH
];
513 ASSERT(ctx
->Stencil
.Enabled
);
514 ASSERT(n
<= MAX_WIDTH
);
516 /* Get initial stencil values */
517 if (swrast
->Driver
.WriteStencilSpan
) {
518 ASSERT(swrast
->Driver
.ReadStencilSpan
);
519 /* Get stencil values from the hardware stencil buffer */
520 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, n
, x
, y
, stencilRow
);
521 stencil
= stencilRow
;
524 /* software stencil buffer */
525 stencil
= STENCIL_ADDRESS(x
, y
);
528 /* do all the stencil/depth testing/updating */
529 result
= stencil_and_ztest_span( ctx
, n
, x
, y
, z
, stencil
, mask
);
531 if (swrast
->Driver
.WriteStencilSpan
) {
532 /* Write updated stencil values into hardware stencil buffer */
533 (swrast
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
540 * Apply stencil and depth testing to the span of pixels.
541 * Both software and hardware stencil buffers are acceptable.
542 * Input: n - number of pixels in the span
543 * x, y - location of leftmost pixel in span
544 * z - array [n] of z values
545 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
546 * Output: mask - array [n] of flags (1=stencil and depth test passed)
547 * Return: GL_TRUE - all fragments failed the testing
548 * GL_FALSE - one or more fragments passed the testing
552 _mesa_stencil_and_ztest_span(GLcontext
*ctx
, struct sw_span
*span
)
554 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
556 GLstencil stencilRow
[MAX_WIDTH
];
560 ASSERT(ctx
->Stencil
.Enabled
);
561 ASSERT(span
->end
<= MAX_WIDTH
);
562 ASSERT(span
->filledMask
== GL_TRUE
);
563 ASSERT(span
->filledDepth
== GL_TRUE
);
564 SW_SPAN_SET_FLAG(span
->testedDepth
);
567 /* Get initial stencil values */
568 if (swrast
->Driver
.WriteStencilSpan
) {
569 ASSERT(swrast
->Driver
.ReadStencilSpan
);
570 /* Get stencil values from the hardware stencil buffer */
571 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, span
->end
, span
->x
, span
->y
, stencilRow
);
572 stencil
= stencilRow
;
575 /* software stencil buffer */
576 stencil
= STENCIL_ADDRESS(span
->x
, span
->y
);
579 /* do all the stencil/depth testing/updating */
580 result
= stencil_and_ztest_span( ctx
, span
->end
, span
->x
, span
->y
,
581 span
->depth
, stencil
, span
->mask
);
583 if (swrast
->Driver
.WriteStencilSpan
) {
584 /* Write updated stencil values into hardware stencil buffer */
585 (swrast
->Driver
.WriteStencilSpan
)(ctx
, span
->end
, span
->x
,
586 span
->y
, stencil
, span
->mask
);
589 span
->write_all
= GL_FALSE
;
598 * Apply the given stencil operator for each pixel in the array whose
599 * mask flag is set. This is for software stencil buffers only.
600 * Input: n - number of pixels in the span
601 * x, y - array of [n] pixels
602 * operator - the stencil buffer operator
603 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
606 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
607 GLuint n
, const GLint x
[], const GLint y
[],
608 GLenum oper
, const GLubyte mask
[] )
610 const GLstencil ref
= ctx
->Stencil
.Ref
;
611 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
612 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
615 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
625 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
633 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
634 *sptr
= (GLstencil
) (invmask
& *sptr
);
643 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
651 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
652 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
661 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
662 if (*sptr
< STENCIL_MAX
) {
663 *sptr
= (GLstencil
) (*sptr
+ 1);
671 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
672 if (*sptr
< STENCIL_MAX
) {
673 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
683 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
685 *sptr
= (GLstencil
) (*sptr
- 1);
693 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
695 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
701 case GL_INCR_WRAP_EXT
:
705 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
706 *sptr
= (GLstencil
) (*sptr
+ 1);
713 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
714 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
719 case GL_DECR_WRAP_EXT
:
723 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
724 *sptr
= (GLstencil
) (*sptr
- 1);
731 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
732 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
741 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
742 *sptr
= (GLstencil
) (~*sptr
);
749 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
750 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
756 _mesa_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
763 * Apply stencil test to an array of pixels before depth buffering.
764 * Used for software stencil buffer only.
765 * Input: n - number of pixels in the span
766 * x, y - array of [n] pixels to stencil
767 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
768 * Output: mask - pixels which fail the stencil test will have their
769 * mask flag set to 0.
770 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
773 stencil_test_pixels( GLcontext
*ctx
, GLuint n
,
774 const GLint x
[], const GLint y
[], GLubyte mask
[] )
776 GLubyte fail
[PB_SIZE
];
779 GLboolean allfail
= GL_FALSE
;
781 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
784 * Perform stencil test. The results of this operation are stored
785 * in the fail[] array:
786 * IF fail[i] is non-zero THEN
787 * the stencil fail operator is to be applied
789 * the stencil fail operator is not to be applied
793 switch (ctx
->Stencil
.Function
) {
808 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
811 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
812 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
828 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
831 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
832 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
848 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
851 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
852 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
868 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
871 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
872 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
888 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
891 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
892 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
908 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
911 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
912 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
934 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
938 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
939 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
, fail
);
949 * Apply stencil and depth testing to an array of pixels.
950 * This is used both for software and hardware stencil buffers.
952 * The comments in this function are a bit sparse but the code is
953 * almost identical to stencil_and_ztest_span(), which is well
956 * Input: n - number of pixels in the array
957 * x, y - array of [n] pixel positions
958 * z - array [n] of z values
959 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
960 * Output: mask - array [n] of flags (1=stencil and depth test passed)
961 * Return: GL_TRUE - all fragments failed the testing
962 * GL_FALSE - one or more fragments passed the testing
965 _mesa_stencil_and_ztest_pixels( GLcontext
*ctx
,
966 GLuint n
, const GLint x
[], const GLint y
[],
967 const GLdepth z
[], GLubyte mask
[] )
969 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
970 ASSERT(ctx
->Stencil
.Enabled
);
971 ASSERT(n
<= PB_SIZE
);
973 if (swrast
->Driver
.WriteStencilPixels
) {
974 /*** Hardware stencil buffer ***/
975 GLstencil stencil
[PB_SIZE
];
976 GLubyte origMask
[PB_SIZE
];
978 ASSERT(swrast
->Driver
.ReadStencilPixels
);
979 (*swrast
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
981 MEMCPY(origMask
, mask
, n
* sizeof(GLubyte
));
983 (void) do_stencil_test(ctx
, n
, stencil
, mask
);
985 if (ctx
->Depth
.Test
== GL_FALSE
) {
986 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
989 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
991 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
992 GLubyte failmask
[PB_SIZE
];
994 for (i
= 0; i
< n
; i
++) {
995 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
996 failmask
[i
] = origMask
[i
] & (mask
[i
] ^ 1);
998 apply_stencil_op(ctx
, ctx
->Stencil
.ZFailFunc
,
999 n
, stencil
, failmask
);
1001 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
1002 GLubyte passmask
[PB_SIZE
];
1004 for (i
= 0; i
< n
; i
++) {
1005 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
1006 passmask
[i
] = origMask
[i
] & mask
[i
];
1008 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
,
1009 n
, stencil
, passmask
);
1013 /* Write updated stencil values into hardware stencil buffer */
1014 (swrast
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, origMask
);
1019 /*** Software stencil buffer ***/
1021 if (stencil_test_pixels(ctx
, n
, x
, y
, mask
) == GL_FALSE
) {
1022 /* all fragments failed the stencil test, we're done. */
1026 if (ctx
->Depth
.Test
==GL_FALSE
) {
1027 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
1028 ctx
->Stencil
.ZPassFunc
, mask
);
1031 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
1034 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
1036 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
1039 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
1040 passmask
[i
] = oldmask
[i
] & mask
[i
];
1041 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
1044 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
1045 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
1046 ctx
->Stencil
.ZFailFunc
, failmask
);
1048 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
1049 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
1050 ctx
->Stencil
.ZPassFunc
, passmask
);
1054 return GL_TRUE
; /* one or more fragments passed both tests */
1061 * Return a span of stencil values from the stencil buffer.
1062 * Used for glRead/CopyPixels
1063 * Input: n - how many pixels
1064 * x,y - location of first pixel
1065 * Output: stencil - the array of stencil values
1068 _mesa_read_stencil_span( GLcontext
*ctx
,
1069 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1071 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1072 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1073 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1074 /* span is completely outside framebuffer */
1075 return; /* undefined values OK */
1084 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1085 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1094 if (swrast
->Driver
.ReadStencilSpan
) {
1095 (*swrast
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1097 else if (ctx
->DrawBuffer
->Stencil
) {
1098 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1099 #if STENCIL_BITS == 8
1100 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1112 * Write a span of stencil values to the stencil buffer.
1113 * Used for glDraw/CopyPixels
1114 * Input: n - how many pixels
1115 * x, y - location of first pixel
1116 * stencil - the array of stencil values
1119 _mesa_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1120 const GLstencil stencil
[] )
1122 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1123 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1124 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1125 /* span is completely outside framebuffer */
1126 return; /* undefined values OK */
1135 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1136 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1143 if (swrast
->Driver
.WriteStencilSpan
) {
1144 (*swrast
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, stencil
, NULL
);
1146 else if (ctx
->DrawBuffer
->Stencil
) {
1147 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1148 #if STENCIL_BITS == 8
1149 MEMCPY( s
, stencil
, n
* sizeof(GLstencil
) );
1161 * Allocate a new stencil buffer. If there's an old one it will be
1162 * deallocated first. The new stencil buffer will be uninitialized.
1165 _mesa_alloc_stencil_buffer( GLcontext
*ctx
)
1167 GLuint buffersize
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1169 /* deallocate current stencil buffer if present */
1170 if (ctx
->DrawBuffer
->Stencil
) {
1171 FREE(ctx
->DrawBuffer
->Stencil
);
1172 ctx
->DrawBuffer
->Stencil
= NULL
;
1175 /* allocate new stencil buffer */
1176 ctx
->DrawBuffer
->Stencil
= (GLstencil
*) MALLOC(buffersize
* sizeof(GLstencil
));
1177 if (!ctx
->DrawBuffer
->Stencil
) {
1179 /* _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE ); */
1180 _mesa_error( ctx
, GL_OUT_OF_MEMORY
, "_mesa_alloc_stencil_buffer" );
1187 * Clear the software (malloc'd) stencil buffer.
1190 clear_software_stencil_buffer( GLcontext
*ctx
)
1192 if (ctx
->Visual
.stencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1193 /* no stencil buffer */
1197 if (ctx
->Scissor
.Enabled
) {
1198 /* clear scissor region only */
1199 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1200 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1201 /* must apply mask to the clear */
1203 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1204 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1205 const GLstencil invMask
= ~mask
;
1206 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1207 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1209 for (i
= 0; i
< width
; i
++) {
1210 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1217 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1218 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1220 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1223 for (i
= 0; i
< width
; i
++)
1224 stencil
[x
] = ctx
->Stencil
.Clear
;
1230 /* clear whole stencil buffer */
1231 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1232 /* must apply mask to the clear */
1233 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1234 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1235 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1236 const GLstencil invMask
= ~mask
;
1237 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1239 for (i
= 0; i
< n
; i
++) {
1240 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1244 /* clear whole buffer without masking */
1245 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1246 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1249 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1252 for (i
= 0; i
< n
; i
++) {
1253 stencil
[i
] = ctx
->Stencil
.Clear
;
1263 * Clear the hardware (in graphics card) stencil buffer.
1264 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1266 * Actually, if there is a hardware stencil buffer it really should have
1267 * been cleared in Driver.Clear()! However, if the hardware does not
1268 * support scissored clears or masked clears (i.e. glStencilMask) then
1269 * we have to use the span-based functions.
1272 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1274 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1275 ASSERT(swrast
->Driver
.WriteStencilSpan
);
1276 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1278 if (ctx
->Scissor
.Enabled
) {
1279 /* clear scissor region only */
1280 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1281 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1282 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1283 /* must apply mask to the clear */
1285 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1286 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1287 const GLstencil invMask
= ~mask
;
1288 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1289 GLstencil stencil
[MAX_WIDTH
];
1291 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1292 for (i
= 0; i
< width
; i
++) {
1293 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1295 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1300 GLstencil stencil
[MAX_WIDTH
];
1302 for (i
= 0; i
< width
; i
++) {
1303 stencil
[i
] = ctx
->Stencil
.Clear
;
1305 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1306 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1311 /* clear whole stencil buffer */
1312 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1313 /* must apply mask to the clear */
1314 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1315 const GLstencil invMask
= ~mask
;
1316 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1317 const GLint width
= ctx
->DrawBuffer
->Width
;
1318 const GLint height
= ctx
->DrawBuffer
->Height
;
1319 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1321 for (y
= 0; y
< height
; y
++) {
1322 GLstencil stencil
[MAX_WIDTH
];
1324 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1325 for (i
= 0; i
< width
; i
++) {
1326 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1328 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1332 /* clear whole buffer without masking */
1333 const GLint width
= ctx
->DrawBuffer
->Width
;
1334 const GLint height
= ctx
->DrawBuffer
->Height
;
1335 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1336 GLstencil stencil
[MAX_WIDTH
];
1338 for (i
= 0; i
< width
; i
++) {
1339 stencil
[i
] = ctx
->Stencil
.Clear
;
1341 for (y
= 0; y
< height
; y
++) {
1342 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1351 * Clear the stencil buffer.
1354 _mesa_clear_stencil_buffer( GLcontext
*ctx
)
1356 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1357 if (swrast
->Driver
.WriteStencilSpan
) {
1358 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1359 clear_hardware_stencil_buffer(ctx
);
1362 clear_software_stencil_buffer(ctx
);