1 /* $Id: stencil.c,v 1.12 1999/12/10 16:15:04 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999 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.
44 _mesa_ClearStencil( GLint s
)
46 GET_CURRENT_CONTEXT(ctx
);
47 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glClearStencil");
48 ctx
->Stencil
.Clear
= (GLstencil
) s
;
50 if (ctx
->Driver
.ClearStencil
) {
51 (*ctx
->Driver
.ClearStencil
)( ctx
, s
);
58 _mesa_StencilFunc( GLenum func
, GLint ref
, GLuint mask
)
60 GET_CURRENT_CONTEXT(ctx
);
63 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glStencilFunc");
74 ctx
->Stencil
.Function
= func
;
77 gl_error( ctx
, GL_INVALID_ENUM
, "glStencilFunc" );
81 maxref
= (1 << STENCIL_BITS
) - 1;
82 ctx
->Stencil
.Ref
= (GLstencil
) CLAMP( ref
, 0, maxref
);
83 ctx
->Stencil
.ValueMask
= (GLstencil
) mask
;
85 if (ctx
->Driver
.StencilFunc
) {
86 (*ctx
->Driver
.StencilFunc
)( ctx
, func
, ctx
->Stencil
.Ref
, mask
);
93 _mesa_StencilMask( GLuint mask
)
95 GET_CURRENT_CONTEXT(ctx
);
96 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glStencilMask");
97 ctx
->Stencil
.WriteMask
= (GLstencil
) mask
;
99 if (ctx
->Driver
.StencilMask
) {
100 (*ctx
->Driver
.StencilMask
)( ctx
, mask
);
107 _mesa_StencilOp( GLenum fail
, GLenum zfail
, GLenum zpass
)
109 GET_CURRENT_CONTEXT(ctx
);
110 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glStencilOp");
118 case GL_INCR_WRAP_EXT
:
119 case GL_DECR_WRAP_EXT
:
120 ctx
->Stencil
.FailFunc
= fail
;
123 gl_error( ctx
, GL_INVALID_ENUM
, "glStencilOp" );
133 case GL_INCR_WRAP_EXT
:
134 case GL_DECR_WRAP_EXT
:
135 ctx
->Stencil
.ZFailFunc
= zfail
;
138 gl_error( ctx
, GL_INVALID_ENUM
, "glStencilOp" );
148 case GL_INCR_WRAP_EXT
:
149 case GL_DECR_WRAP_EXT
:
150 ctx
->Stencil
.ZPassFunc
= zpass
;
153 gl_error( ctx
, GL_INVALID_ENUM
, "glStencilOp" );
157 if (ctx
->Driver
.StencilOp
) {
158 (*ctx
->Driver
.StencilOp
)( ctx
, fail
, zfail
, zpass
);
166 IF stencil test fails THEN
167 Apply fail-op to stencil value
168 Don't write the pixel (RGBA,Z)
170 IF doing depth test && depth test fails THEN
171 Apply zfail-op to stencil value
172 Write RGBA and Z to appropriate buffers
174 Apply zpass-op to stencil value
183 * Return the address of a stencil buffer value given the window coords:
185 #define STENCIL_ADDRESS(X,Y) \
186 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
191 * Apply the given stencil operator to the array of stencil values.
192 * Don't touch stencil[i] if mask[i] is zero.
193 * Input: n - size of stencil array
194 * oper - the stencil buffer operator
195 * stencil - array of stencil values
196 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
197 * Output: stencil - modified values
199 static void apply_stencil_op( const GLcontext
*ctx
, GLenum oper
,
200 GLuint n
, GLstencil stencil
[],
201 const GLubyte mask
[] )
203 const GLstencil ref
= ctx
->Stencil
.Ref
;
204 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
205 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
223 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
239 GLstencil s
= stencil
[i
];
240 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
249 GLstencil s
= stencil
[i
];
250 if (s
< STENCIL_MAX
) {
251 stencil
[i
] = (GLstencil
) (s
+1);
259 /* VERIFY logic of adding 1 to a write-masked value */
260 GLstencil s
= stencil
[i
];
261 if (s
< STENCIL_MAX
) {
262 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
272 GLstencil s
= stencil
[i
];
274 stencil
[i
] = (GLstencil
) (s
-1);
282 /* VERIFY logic of subtracting 1 to a write-masked value */
283 GLstencil s
= stencil
[i
];
285 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
291 case GL_INCR_WRAP_EXT
:
302 GLstencil s
= stencil
[i
];
303 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
308 case GL_DECR_WRAP_EXT
:
319 GLstencil s
= stencil
[i
];
320 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
329 GLstencil s
= stencil
[i
];
330 stencil
[i
] = (GLstencil
) ~s
;
337 GLstencil s
= stencil
[i
];
338 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
344 gl_problem(ctx
, "Bad stencil op in apply_stencil_op");
352 * Apply stencil test to an array of stencil values (before depth buffering).
353 * Input: n - number of pixels in the array
354 * stencil - array of [n] stencil values
355 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
356 * Output: mask - pixels which fail the stencil test will have their
357 * mask flag set to 0.
358 * stencil - updated stencil values (where the test passed)
359 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
362 do_stencil_test( GLcontext
*ctx
, GLuint n
, GLstencil stencil
[],
365 GLubyte fail
[PB_SIZE
];
366 GLboolean allfail
= GL_FALSE
;
370 ASSERT(n
<= PB_SIZE
);
373 * Perform stencil test. The results of this operation are stored
374 * in the fail[] array:
375 * IF fail[i] is non-zero THEN
376 * the stencil fail operator is to be applied
378 * the stencil fail operator is not to be applied
381 switch (ctx
->Stencil
.Function
) {
396 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
399 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
415 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
418 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
434 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
437 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
453 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
456 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
472 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
475 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
491 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
494 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
516 gl_problem(ctx
, "Bad stencil func in gl_stencil_span");
520 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
521 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
, n
, stencil
, fail
);
531 * Apply stencil and depth testing to an array of pixels.
532 * Hardware or software stencil buffer acceptable.
533 * Input: n - number of pixels in the span
534 * z - array [n] of z values
535 * stencil - array [n] of stencil values
536 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
537 * Output: stencil - modified stencil values
538 * mask - array [n] of flags (1=stencil and depth test passed)
539 * Return: GL_TRUE - all fragments failed the testing
540 * GL_FALSE - one or more fragments passed the testing
544 stencil_and_depth_test_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
545 const GLdepth z
[], GLstencil stencil
[],
548 ASSERT(ctx
->Stencil
.Enabled
);
549 ASSERT(n
<= PB_SIZE
);
552 * Apply the stencil test to the fragments.
553 * failMask[i] is 1 if the stencil test failed.
555 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
556 /* all fragments failed the stencil test, we're done. */
562 * Some fragments passed the stencil test, apply depth test to them
563 * and apply Zpass and Zfail stencil ops.
565 if (ctx
->Depth
.Test
==GL_FALSE
) {
567 * No depth buffer, just apply zpass stencil function to active pixels.
569 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
573 * Perform depth buffering, then apply zpass or zfail stencil function.
575 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
578 /* save the current mask bits */
579 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
581 /* apply the depth test */
582 if (ctx
->Driver
.DepthTestSpan
)
583 (*ctx
->Driver
.DepthTestSpan
)( ctx
, n
, x
, y
, z
, mask
);
585 /* Set the stencil pass/fail flags according to result of depth testing.
586 * if oldmask[i] == 0 then
587 * Don't touch the stencil value
588 * else if oldmask[i] and newmask[i] then
591 * assert(oldmask[i] && !newmask[i])
596 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
597 passmask
[i
] = oldmask
[i
] & mask
[i
];
598 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
601 /* apply the pass and fail operations */
602 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
603 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
605 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
606 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
610 return GL_TRUE
; /* one or more fragments passed both tests */
616 * Apply stencil and depth testing to the span of pixels.
617 * Both software and hardware stencil buffers are acceptable.
618 * Input: n - number of pixels in the span
619 * x, y - location of leftmost pixel in span
620 * z - array [n] of z values
621 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
622 * Output: mask - array [n] of flags (1=stencil and depth test passed)
623 * Return: GL_TRUE - all fragments failed the testing
624 * GL_FALSE - one or more fragments passed the testing
628 gl_stencil_and_depth_test_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
629 const GLdepth z
[], GLubyte mask
[] )
631 GLstencil stencilRow
[MAX_WIDTH
];
635 ASSERT(ctx
->Stencil
.Enabled
);
636 ASSERT(n
<= MAX_WIDTH
);
638 /* Get initial stencil values */
639 if (ctx
->Driver
.WriteStencilSpan
) {
640 ASSERT(ctx
->Driver
.ReadStencilSpan
);
641 /* Get stencil values from the hardware stencil buffer */
642 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, n
, x
, y
, stencilRow
);
643 stencil
= stencilRow
;
646 /* software stencil buffer */
647 stencil
= STENCIL_ADDRESS(x
, y
);
650 /* do all the stencil/depth testing/updating */
651 result
= stencil_and_depth_test_span( ctx
, n
, x
, y
, z
, stencil
, mask
);
653 if (ctx
->Driver
.WriteStencilSpan
) {
654 /* Write updated stencil values into hardware stencil buffer */
655 (ctx
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
665 * Apply the given stencil operator for each pixel in the array whose
666 * mask flag is set. This is for software stencil buffers only.
667 * Input: n - number of pixels in the span
668 * x, y - array of [n] pixels
669 * operator - the stencil buffer operator
670 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
673 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
674 GLuint n
, const GLint x
[], const GLint y
[],
675 GLenum oper
, const GLubyte mask
[] )
677 const GLstencil ref
= ctx
->Stencil
.Ref
;
678 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
679 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
682 ASSERT(!ctx
->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
692 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
700 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
701 *sptr
= (GLstencil
) (invmask
& *sptr
);
710 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
718 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
719 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
728 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
729 if (*sptr
< STENCIL_MAX
) {
730 *sptr
= (GLstencil
) (*sptr
+ 1);
738 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
739 if (*sptr
< STENCIL_MAX
) {
740 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
750 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
752 *sptr
= (GLstencil
) (*sptr
- 1);
760 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
762 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
768 case GL_INCR_WRAP_EXT
:
772 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
773 *sptr
= (GLstencil
) (*sptr
+ 1);
780 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
781 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
786 case GL_DECR_WRAP_EXT
:
790 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
791 *sptr
= (GLstencil
) (*sptr
- 1);
798 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
799 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
808 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
809 *sptr
= (GLstencil
) (~*sptr
);
816 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
817 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
823 gl_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
830 * Apply stencil test to an array of pixels before depth buffering.
831 * Used for software stencil buffer only.
832 * Input: n - number of pixels in the span
833 * x, y - array of [n] pixels to stencil
834 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
835 * Output: mask - pixels which fail the stencil test will have their
836 * mask flag set to 0.
837 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
840 stencil_test_pixels( GLcontext
*ctx
, GLuint n
,
841 const GLint x
[], const GLint y
[], GLubyte mask
[] )
843 GLubyte fail
[PB_SIZE
];
846 GLboolean allfail
= GL_FALSE
;
848 ASSERT(!ctx
->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
851 * Perform stencil test. The results of this operation are stored
852 * in the fail[] array:
853 * IF fail[i] is non-zero THEN
854 * the stencil fail operator is to be applied
856 * the stencil fail operator is not to be applied
860 switch (ctx
->Stencil
.Function
) {
875 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
878 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
879 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
895 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
898 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
899 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
915 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
918 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
919 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
935 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
938 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
939 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
955 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
958 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
959 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
975 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
978 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
979 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
1001 gl_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
1005 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
1006 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
, fail
);
1016 * Apply stencil and depth testing to an array of pixels.
1017 * This is used both for software and hardware stencil buffers.
1019 * The comments in this function are a bit sparse but the code is
1020 * almost identical to stencil_and_depth_test_span(), which is well
1023 * Input: n - number of pixels in the array
1024 * x, y - array of [n] pixel positions
1025 * z - array [n] of z values
1026 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
1027 * Output: mask - array [n] of flags (1=stencil and depth test passed)
1028 * Return: GL_TRUE - all fragments failed the testing
1029 * GL_FALSE - one or more fragments passed the testing
1032 gl_stencil_and_depth_test_pixels( GLcontext
*ctx
,
1033 GLuint n
, const GLint x
[], const GLint y
[],
1034 const GLdepth z
[], GLubyte mask
[] )
1036 ASSERT(ctx
->Stencil
.Enabled
);
1037 ASSERT(n
<= PB_SIZE
);
1039 if (ctx
->Driver
.WriteStencilPixels
) {
1040 /*** Hardware stencil buffer ***/
1041 GLstencil stencil
[PB_SIZE
];
1042 GLubyte mask
[PB_SIZE
];
1044 ASSERT(ctx
->Driver
.ReadStencilPixels
);
1045 (*ctx
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
1048 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
1049 /* all fragments failed the stencil test, we're done. */
1053 if (ctx
->Depth
.Test
== GL_FALSE
) {
1054 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
1057 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
1060 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
1062 if (ctx
->Driver
.DepthTestPixels
)
1063 (*ctx
->Driver
.DepthTestPixels
)( ctx
, n
, x
, y
, z
, mask
);
1066 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
1067 passmask
[i
] = oldmask
[i
] & mask
[i
];
1068 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
1071 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
1072 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
1074 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
1075 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
1079 /* Write updated stencil values into hardware stencil buffer */
1080 (ctx
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, mask
);
1086 /*** Software stencil buffer ***/
1088 if (stencil_test_pixels(ctx
, n
, x
, y
, mask
) == GL_FALSE
) {
1089 /* all fragments failed the stencil test, we're done. */
1094 if (ctx
->Depth
.Test
==GL_FALSE
) {
1095 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.ZPassFunc
, mask
);
1098 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
1101 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
1103 if (ctx
->Driver
.DepthTestPixels
)
1104 (*ctx
->Driver
.DepthTestPixels
)( ctx
, n
, x
, y
, z
, mask
);
1107 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
1108 passmask
[i
] = oldmask
[i
] & mask
[i
];
1109 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
1112 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
1113 apply_stencil_op_to_pixels( ctx
, n
, x
, y
,
1114 ctx
->Stencil
.ZFailFunc
, failmask
);
1116 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
1117 apply_stencil_op_to_pixels( ctx
, n
, x
, y
,
1118 ctx
->Stencil
.ZPassFunc
, passmask
);
1122 return GL_TRUE
; /* one or more fragments passed both tests */
1129 * Return a span of stencil values from the stencil buffer.
1130 * Used for glRead/CopyPixels
1131 * Input: n - how many pixels
1132 * x,y - location of first pixel
1133 * Output: stencil - the array of stencil values
1135 void gl_read_stencil_span( GLcontext
*ctx
,
1136 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1139 if (ctx
->DrawBuffer
->Stencil
) {
1140 if (ctx
->Driver
.ReadStencilSpan
) {
1141 (*ctx
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1144 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1145 #if STENCIL_BITS == 8
1146 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1159 * Write a span of stencil values to the stencil buffer.
1160 * Used for glDraw/CopyPixels
1161 * Input: n - how many pixels
1162 * x, y - location of first pixel
1163 * stencil - the array of stencil values
1165 void gl_write_stencil_span( GLcontext
*ctx
,
1166 GLint n
, GLint x
, GLint y
,
1167 const GLstencil stencil
[] )
1170 if (ctx
->DrawBuffer
->Stencil
) {
1172 if (y
< ctx
->DrawBuffer
->Ymin
|| y
> ctx
->DrawBuffer
->Ymax
)
1174 if (x
< ctx
->DrawBuffer
->Xmin
) {
1175 GLint diff
= ctx
->DrawBuffer
->Xmin
- x
;
1178 x
= ctx
->DrawBuffer
->Xmin
;
1180 if (x
+ n
> ctx
->DrawBuffer
->Xmax
) {
1181 GLint diff
= x
+ n
- ctx
->DrawBuffer
->Xmax
;
1187 if (ctx
->Driver
.WriteStencilSpan
) {
1188 (*ctx
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, stencil
, NULL
);
1191 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1192 #if STENCIL_BITS == 8
1193 MEMCPY( s
, stencil
, n
* sizeof(GLstencil
) );
1206 * Allocate a new stencil buffer. If there's an old one it will be
1207 * deallocated first. The new stencil buffer will be uninitialized.
1209 void gl_alloc_stencil_buffer( GLcontext
*ctx
)
1211 GLuint buffersize
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1213 /* deallocate current stencil buffer if present */
1214 if (ctx
->DrawBuffer
->Stencil
) {
1215 FREE(ctx
->DrawBuffer
->Stencil
);
1216 ctx
->DrawBuffer
->Stencil
= NULL
;
1219 /* allocate new stencil buffer */
1220 ctx
->DrawBuffer
->Stencil
= (GLstencil
*) MALLOC(buffersize
* sizeof(GLstencil
));
1221 if (!ctx
->DrawBuffer
->Stencil
) {
1223 _mesa_set_enable( ctx
, GL_STENCIL_TEST
, GL_FALSE
);
1224 gl_error( ctx
, GL_OUT_OF_MEMORY
, "gl_alloc_stencil_buffer" );
1231 * Clear the software (malloc'd) stencil buffer.
1234 clear_software_stencil_buffer( GLcontext
*ctx
)
1236 if (ctx
->Visual
->StencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1237 /* no stencil buffer */
1241 if (ctx
->Scissor
.Enabled
) {
1242 /* clear scissor region only */
1243 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
+ 1;
1244 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1245 /* must apply mask to the clear */
1247 for (y
= ctx
->DrawBuffer
->Ymin
; y
<= ctx
->DrawBuffer
->Ymax
; y
++) {
1248 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1249 const GLstencil invMask
= ~mask
;
1250 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1251 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1253 for (i
= 0; i
< width
; i
++) {
1254 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1261 for (y
= ctx
->DrawBuffer
->Ymin
; y
<= ctx
->DrawBuffer
->Ymax
; y
++) {
1262 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1264 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1267 for (i
= 0; i
< width
; i
++)
1268 stencil
[x
] = ctx
->Stencil
.Clear
;
1274 /* clear whole stencil buffer */
1275 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1276 /* must apply mask to the clear */
1277 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1278 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1279 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1280 const GLstencil invMask
= ~mask
;
1281 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1283 for (i
= 0; i
< n
; i
++) {
1284 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1288 /* clear whole buffer without masking */
1289 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1290 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1293 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1296 for (i
= 0; i
< n
; i
++) {
1297 stencil
[i
] = ctx
->Stencil
.Clear
;
1307 * Clear the hardware (in graphics card) stencil buffer.
1308 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1310 * Actually, if there is a hardware stencil buffer it really should have
1311 * been cleared in Driver.Clear()! However, if the hardware does not
1312 * support scissored clears or masked clears (i.e. glStencilMask) then
1313 * we have to use the span-based functions.
1316 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1318 ASSERT(ctx
->Driver
.WriteStencilSpan
);
1319 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1321 if (ctx
->Scissor
.Enabled
) {
1322 /* clear scissor region only */
1323 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1324 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
+ 1;
1325 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1326 /* must apply mask to the clear */
1328 for (y
= ctx
->DrawBuffer
->Ymin
; y
<= ctx
->DrawBuffer
->Ymax
; y
++) {
1329 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1330 const GLstencil invMask
= ~mask
;
1331 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1332 GLstencil stencil
[MAX_WIDTH
];
1334 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1335 for (i
= 0; i
< width
; i
++) {
1336 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1338 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1343 GLstencil stencil
[MAX_WIDTH
];
1345 for (i
= 0; i
< width
; i
++) {
1346 stencil
[i
] = ctx
->Stencil
.Clear
;
1348 for (y
= ctx
->DrawBuffer
->Ymin
; y
<= ctx
->DrawBuffer
->Ymax
; y
++) {
1349 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1354 /* clear whole stencil buffer */
1355 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1356 /* must apply mask to the clear */
1357 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1358 const GLstencil invMask
= ~mask
;
1359 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1360 const GLint width
= ctx
->DrawBuffer
->Width
;
1361 const GLint height
= ctx
->DrawBuffer
->Height
;
1362 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1364 for (y
= 0; y
< height
; y
++) {
1365 GLstencil stencil
[MAX_WIDTH
];
1367 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1368 for (i
= 0; i
< width
; i
++) {
1369 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1371 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1375 /* clear whole buffer without masking */
1376 const GLint width
= ctx
->DrawBuffer
->Width
;
1377 const GLint height
= ctx
->DrawBuffer
->Width
;
1378 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1379 GLstencil stencil
[MAX_WIDTH
];
1381 for (i
= 0; i
< width
; i
++) {
1382 stencil
[i
] = ctx
->Stencil
.Clear
;
1384 for (y
= 0; y
< height
; y
++) {
1385 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1394 * Clear the stencil buffer.
1396 void gl_clear_stencil_buffer( GLcontext
*ctx
)
1398 if (ctx
->Driver
.WriteStencilSpan
) {
1399 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1400 clear_hardware_stencil_buffer(ctx
);
1403 clear_software_stencil_buffer(ctx
);