1 /* $Id: stencil.c,v 1.16 2000/04/11 21:26:57 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 case GL_INCR_WRAP_EXT
:
120 case GL_DECR_WRAP_EXT
:
121 ctx
->Stencil
.FailFunc
= fail
;
124 gl_error( ctx
, GL_INVALID_ENUM
, "glStencilOp" );
134 case GL_INCR_WRAP_EXT
:
135 case GL_DECR_WRAP_EXT
:
136 ctx
->Stencil
.ZFailFunc
= zfail
;
139 gl_error( ctx
, GL_INVALID_ENUM
, "glStencilOp" );
149 case GL_INCR_WRAP_EXT
:
150 case GL_DECR_WRAP_EXT
:
151 ctx
->Stencil
.ZPassFunc
= zpass
;
154 gl_error( ctx
, GL_INVALID_ENUM
, "glStencilOp" );
158 if (ctx
->Driver
.StencilOp
) {
159 (*ctx
->Driver
.StencilOp
)( ctx
, fail
, zfail
, zpass
);
167 IF stencil test fails THEN
168 Apply fail-op to stencil value
169 Don't write the pixel (RGBA,Z)
171 IF doing depth test && depth test fails THEN
172 Apply zfail-op to stencil value
173 Write RGBA and Z to appropriate buffers
175 Apply zpass-op to stencil value
184 * Return the address of a stencil buffer value given the window coords:
186 #define STENCIL_ADDRESS(X,Y) \
187 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
192 * Apply the given stencil operator to the array of stencil values.
193 * Don't touch stencil[i] if mask[i] is zero.
194 * Input: n - size of stencil array
195 * oper - the stencil buffer operator
196 * stencil - array of stencil values
197 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
198 * Output: stencil - modified values
200 static void apply_stencil_op( const GLcontext
*ctx
, GLenum oper
,
201 GLuint n
, GLstencil stencil
[],
202 const GLubyte mask
[] )
204 const GLstencil ref
= ctx
->Stencil
.Ref
;
205 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
206 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
224 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
240 GLstencil s
= stencil
[i
];
241 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
250 GLstencil s
= stencil
[i
];
251 if (s
< STENCIL_MAX
) {
252 stencil
[i
] = (GLstencil
) (s
+1);
260 /* VERIFY logic of adding 1 to a write-masked value */
261 GLstencil s
= stencil
[i
];
262 if (s
< STENCIL_MAX
) {
263 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
273 GLstencil s
= stencil
[i
];
275 stencil
[i
] = (GLstencil
) (s
-1);
283 /* VERIFY logic of subtracting 1 to a write-masked value */
284 GLstencil s
= stencil
[i
];
286 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
292 case GL_INCR_WRAP_EXT
:
303 GLstencil s
= stencil
[i
];
304 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
309 case GL_DECR_WRAP_EXT
:
320 GLstencil s
= stencil
[i
];
321 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
330 GLstencil s
= stencil
[i
];
331 stencil
[i
] = (GLstencil
) ~s
;
338 GLstencil s
= stencil
[i
];
339 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
345 gl_problem(ctx
, "Bad stencil op in apply_stencil_op");
353 * Apply stencil test to an array of stencil values (before depth buffering).
354 * Input: n - number of pixels in the array
355 * stencil - array of [n] stencil values
356 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
357 * Output: mask - pixels which fail the stencil test will have their
358 * mask flag set to 0.
359 * stencil - updated stencil values (where the test passed)
360 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
363 do_stencil_test( GLcontext
*ctx
, GLuint n
, GLstencil stencil
[],
366 GLubyte fail
[PB_SIZE
];
367 GLboolean allfail
= GL_FALSE
;
371 ASSERT(n
<= PB_SIZE
);
374 * Perform stencil test. The results of this operation are stored
375 * in the fail[] array:
376 * IF fail[i] is non-zero THEN
377 * the stencil fail operator is to be applied
379 * the stencil fail operator is not to be applied
382 switch (ctx
->Stencil
.Function
) {
397 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
400 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
416 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
419 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
435 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
438 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
454 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
457 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
473 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
476 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
492 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
495 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
517 gl_problem(ctx
, "Bad stencil func in gl_stencil_span");
521 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
522 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
, n
, stencil
, fail
);
532 * Apply stencil and depth testing to an array of pixels.
533 * Hardware or software stencil buffer acceptable.
534 * Input: n - number of pixels in the span
535 * z - array [n] of z values
536 * stencil - array [n] of stencil values
537 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
538 * Output: stencil - modified stencil values
539 * mask - array [n] of flags (1=stencil and depth test passed)
540 * Return: GL_TRUE - all fragments failed the testing
541 * GL_FALSE - one or more fragments passed the testing
545 stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
546 const GLdepth z
[], GLstencil stencil
[],
549 ASSERT(ctx
->Stencil
.Enabled
);
550 ASSERT(n
<= PB_SIZE
);
553 * Apply the stencil test to the fragments.
554 * failMask[i] is 1 if the stencil test failed.
556 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
557 /* all fragments failed the stencil test, we're done. */
563 * Some fragments passed the stencil test, apply depth test to them
564 * and apply Zpass and Zfail stencil ops.
566 if (ctx
->Depth
.Test
==GL_FALSE
) {
568 * No depth buffer, just apply zpass stencil function to active pixels.
570 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
574 * Perform depth buffering, then apply zpass or zfail stencil function.
576 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
579 /* save the current mask bits */
580 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
582 /* apply the depth test */
583 _mesa_depth_test_span(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 _mesa_stencil_and_ztest_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_ztest_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_ztest_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 _mesa_stencil_and_ztest_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 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
1065 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
1066 passmask
[i
] = oldmask
[i
] & mask
[i
];
1067 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
1070 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
1071 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
1073 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
1074 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
1078 /* Write updated stencil values into hardware stencil buffer */
1079 (ctx
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, mask
);
1085 /*** Software stencil buffer ***/
1087 if (stencil_test_pixels(ctx
, n
, x
, y
, mask
) == GL_FALSE
) {
1088 /* all fragments failed the stencil test, we're done. */
1093 if (ctx
->Depth
.Test
==GL_FALSE
) {
1094 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.ZPassFunc
, mask
);
1097 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
1100 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
1102 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
1105 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
1106 passmask
[i
] = oldmask
[i
] & mask
[i
];
1107 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
1110 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
1111 apply_stencil_op_to_pixels( ctx
, n
, x
, y
,
1112 ctx
->Stencil
.ZFailFunc
, failmask
);
1114 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
1115 apply_stencil_op_to_pixels( ctx
, n
, x
, y
,
1116 ctx
->Stencil
.ZPassFunc
, passmask
);
1120 return GL_TRUE
; /* one or more fragments passed both tests */
1127 * Return a span of stencil values from the stencil buffer.
1128 * Used for glRead/CopyPixels
1129 * Input: n - how many pixels
1130 * x,y - location of first pixel
1131 * Output: stencil - the array of stencil values
1134 _mesa_read_stencil_span( GLcontext
*ctx
,
1135 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1137 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1138 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1139 /* span is completely outside framebuffer */
1140 return; /* undefined values OK */
1149 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1150 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1159 if (ctx
->Driver
.ReadStencilSpan
) {
1160 (*ctx
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1162 else if (ctx
->DrawBuffer
->Stencil
) {
1163 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1164 #if STENCIL_BITS == 8
1165 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1177 * Write a span of stencil values to the stencil buffer.
1178 * Used for glDraw/CopyPixels
1179 * Input: n - how many pixels
1180 * x, y - location of first pixel
1181 * stencil - the array of stencil values
1184 _mesa_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1185 const GLstencil stencil
[] )
1187 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1188 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1189 /* span is completely outside framebuffer */
1190 return; /* undefined values OK */
1199 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1200 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1207 if (ctx
->Driver
.WriteStencilSpan
) {
1208 (*ctx
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, stencil
, NULL
);
1210 else if (ctx
->DrawBuffer
->Stencil
) {
1211 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1212 #if STENCIL_BITS == 8
1213 MEMCPY( s
, stencil
, n
* sizeof(GLstencil
) );
1225 * Allocate a new stencil buffer. If there's an old one it will be
1226 * deallocated first. The new stencil buffer will be uninitialized.
1229 _mesa_alloc_stencil_buffer( GLcontext
*ctx
)
1231 GLuint buffersize
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1233 /* deallocate current stencil buffer if present */
1234 if (ctx
->DrawBuffer
->Stencil
) {
1235 FREE(ctx
->DrawBuffer
->Stencil
);
1236 ctx
->DrawBuffer
->Stencil
= NULL
;
1239 /* allocate new stencil buffer */
1240 ctx
->DrawBuffer
->Stencil
= (GLstencil
*) MALLOC(buffersize
* sizeof(GLstencil
));
1241 if (!ctx
->DrawBuffer
->Stencil
) {
1243 _mesa_set_enable( ctx
, GL_STENCIL_TEST
, GL_FALSE
);
1244 gl_error( ctx
, GL_OUT_OF_MEMORY
, "_mesa_alloc_stencil_buffer" );
1251 * Clear the software (malloc'd) stencil buffer.
1254 clear_software_stencil_buffer( GLcontext
*ctx
)
1256 if (ctx
->Visual
->StencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1257 /* no stencil buffer */
1261 if (ctx
->Scissor
.Enabled
) {
1262 /* clear scissor region only */
1263 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
+ 1;
1264 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1265 /* must apply mask to the clear */
1267 for (y
= ctx
->DrawBuffer
->Ymin
; y
<= ctx
->DrawBuffer
->Ymax
; y
++) {
1268 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1269 const GLstencil invMask
= ~mask
;
1270 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1271 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1273 for (i
= 0; i
< width
; i
++) {
1274 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1281 for (y
= ctx
->DrawBuffer
->Ymin
; y
<= ctx
->DrawBuffer
->Ymax
; y
++) {
1282 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1284 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1287 for (i
= 0; i
< width
; i
++)
1288 stencil
[x
] = ctx
->Stencil
.Clear
;
1294 /* clear whole stencil buffer */
1295 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1296 /* must apply mask to the clear */
1297 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1298 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1299 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1300 const GLstencil invMask
= ~mask
;
1301 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1303 for (i
= 0; i
< n
; i
++) {
1304 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1308 /* clear whole buffer without masking */
1309 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1310 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1313 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1316 for (i
= 0; i
< n
; i
++) {
1317 stencil
[i
] = ctx
->Stencil
.Clear
;
1327 * Clear the hardware (in graphics card) stencil buffer.
1328 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1330 * Actually, if there is a hardware stencil buffer it really should have
1331 * been cleared in Driver.Clear()! However, if the hardware does not
1332 * support scissored clears or masked clears (i.e. glStencilMask) then
1333 * we have to use the span-based functions.
1336 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1338 ASSERT(ctx
->Driver
.WriteStencilSpan
);
1339 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1341 if (ctx
->Scissor
.Enabled
) {
1342 /* clear scissor region only */
1343 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1344 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
+ 1;
1345 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1346 /* must apply mask to the clear */
1348 for (y
= ctx
->DrawBuffer
->Ymin
; y
<= ctx
->DrawBuffer
->Ymax
; y
++) {
1349 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1350 const GLstencil invMask
= ~mask
;
1351 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1352 GLstencil stencil
[MAX_WIDTH
];
1354 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1355 for (i
= 0; i
< width
; i
++) {
1356 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1358 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1363 GLstencil stencil
[MAX_WIDTH
];
1365 for (i
= 0; i
< width
; i
++) {
1366 stencil
[i
] = ctx
->Stencil
.Clear
;
1368 for (y
= ctx
->DrawBuffer
->Ymin
; y
<= ctx
->DrawBuffer
->Ymax
; y
++) {
1369 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1374 /* clear whole stencil buffer */
1375 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1376 /* must apply mask to the clear */
1377 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1378 const GLstencil invMask
= ~mask
;
1379 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1380 const GLint width
= ctx
->DrawBuffer
->Width
;
1381 const GLint height
= ctx
->DrawBuffer
->Height
;
1382 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1384 for (y
= 0; y
< height
; y
++) {
1385 GLstencil stencil
[MAX_WIDTH
];
1387 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1388 for (i
= 0; i
< width
; i
++) {
1389 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1391 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1395 /* clear whole buffer without masking */
1396 const GLint width
= ctx
->DrawBuffer
->Width
;
1397 const GLint height
= ctx
->DrawBuffer
->Width
;
1398 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1399 GLstencil stencil
[MAX_WIDTH
];
1401 for (i
= 0; i
< width
; i
++) {
1402 stencil
[i
] = ctx
->Stencil
.Clear
;
1404 for (y
= 0; y
< height
; y
++) {
1405 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1414 * Clear the stencil buffer.
1417 _mesa_clear_stencil_buffer( GLcontext
*ctx
)
1419 if (ctx
->Driver
.WriteStencilSpan
) {
1420 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1421 clear_hardware_stencil_buffer(ctx
);
1424 clear_software_stencil_buffer(ctx
);