1 /* $Id: stencil.c,v 1.13 1999/12/10 19:09:22 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.
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_depth_test_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 gl_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 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 gl_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 gl_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
1133 void gl_read_stencil_span( GLcontext
*ctx
,
1134 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1137 if (ctx
->DrawBuffer
->Stencil
) {
1138 if (ctx
->Driver
.ReadStencilSpan
) {
1139 (*ctx
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1142 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1143 #if STENCIL_BITS == 8
1144 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1157 * Write a span of stencil values to the stencil buffer.
1158 * Used for glDraw/CopyPixels
1159 * Input: n - how many pixels
1160 * x, y - location of first pixel
1161 * stencil - the array of stencil values
1163 void gl_write_stencil_span( GLcontext
*ctx
,
1164 GLint n
, GLint x
, GLint y
,
1165 const GLstencil stencil
[] )
1168 if (ctx
->DrawBuffer
->Stencil
) {
1170 if (y
< ctx
->DrawBuffer
->Ymin
|| y
> ctx
->DrawBuffer
->Ymax
)
1172 if (x
< ctx
->DrawBuffer
->Xmin
) {
1173 GLint diff
= ctx
->DrawBuffer
->Xmin
- x
;
1176 x
= ctx
->DrawBuffer
->Xmin
;
1178 if (x
+ n
> ctx
->DrawBuffer
->Xmax
) {
1179 GLint diff
= x
+ n
- ctx
->DrawBuffer
->Xmax
;
1185 if (ctx
->Driver
.WriteStencilSpan
) {
1186 (*ctx
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, stencil
, NULL
);
1189 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1190 #if STENCIL_BITS == 8
1191 MEMCPY( s
, stencil
, n
* sizeof(GLstencil
) );
1204 * Allocate a new stencil buffer. If there's an old one it will be
1205 * deallocated first. The new stencil buffer will be uninitialized.
1207 void gl_alloc_stencil_buffer( GLcontext
*ctx
)
1209 GLuint buffersize
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1211 /* deallocate current stencil buffer if present */
1212 if (ctx
->DrawBuffer
->Stencil
) {
1213 FREE(ctx
->DrawBuffer
->Stencil
);
1214 ctx
->DrawBuffer
->Stencil
= NULL
;
1217 /* allocate new stencil buffer */
1218 ctx
->DrawBuffer
->Stencil
= (GLstencil
*) MALLOC(buffersize
* sizeof(GLstencil
));
1219 if (!ctx
->DrawBuffer
->Stencil
) {
1221 _mesa_set_enable( ctx
, GL_STENCIL_TEST
, GL_FALSE
);
1222 gl_error( ctx
, GL_OUT_OF_MEMORY
, "gl_alloc_stencil_buffer" );
1229 * Clear the software (malloc'd) stencil buffer.
1232 clear_software_stencil_buffer( GLcontext
*ctx
)
1234 if (ctx
->Visual
->StencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1235 /* no stencil buffer */
1239 if (ctx
->Scissor
.Enabled
) {
1240 /* clear scissor region only */
1241 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
+ 1;
1242 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1243 /* must apply mask to the clear */
1245 for (y
= ctx
->DrawBuffer
->Ymin
; y
<= ctx
->DrawBuffer
->Ymax
; y
++) {
1246 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1247 const GLstencil invMask
= ~mask
;
1248 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1249 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1251 for (i
= 0; i
< width
; i
++) {
1252 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1259 for (y
= ctx
->DrawBuffer
->Ymin
; y
<= ctx
->DrawBuffer
->Ymax
; y
++) {
1260 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1262 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1265 for (i
= 0; i
< width
; i
++)
1266 stencil
[x
] = ctx
->Stencil
.Clear
;
1272 /* clear whole stencil buffer */
1273 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1274 /* must apply mask to the clear */
1275 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1276 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1277 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1278 const GLstencil invMask
= ~mask
;
1279 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1281 for (i
= 0; i
< n
; i
++) {
1282 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1286 /* clear whole buffer without masking */
1287 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1288 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1291 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1294 for (i
= 0; i
< n
; i
++) {
1295 stencil
[i
] = ctx
->Stencil
.Clear
;
1305 * Clear the hardware (in graphics card) stencil buffer.
1306 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1308 * Actually, if there is a hardware stencil buffer it really should have
1309 * been cleared in Driver.Clear()! However, if the hardware does not
1310 * support scissored clears or masked clears (i.e. glStencilMask) then
1311 * we have to use the span-based functions.
1314 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1316 ASSERT(ctx
->Driver
.WriteStencilSpan
);
1317 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1319 if (ctx
->Scissor
.Enabled
) {
1320 /* clear scissor region only */
1321 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1322 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
+ 1;
1323 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1324 /* must apply mask to the clear */
1326 for (y
= ctx
->DrawBuffer
->Ymin
; y
<= ctx
->DrawBuffer
->Ymax
; y
++) {
1327 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1328 const GLstencil invMask
= ~mask
;
1329 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1330 GLstencil stencil
[MAX_WIDTH
];
1332 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1333 for (i
= 0; i
< width
; i
++) {
1334 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1336 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1341 GLstencil stencil
[MAX_WIDTH
];
1343 for (i
= 0; i
< width
; i
++) {
1344 stencil
[i
] = ctx
->Stencil
.Clear
;
1346 for (y
= ctx
->DrawBuffer
->Ymin
; y
<= ctx
->DrawBuffer
->Ymax
; y
++) {
1347 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1352 /* clear whole stencil buffer */
1353 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1354 /* must apply mask to the clear */
1355 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1356 const GLstencil invMask
= ~mask
;
1357 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1358 const GLint width
= ctx
->DrawBuffer
->Width
;
1359 const GLint height
= ctx
->DrawBuffer
->Height
;
1360 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1362 for (y
= 0; y
< height
; y
++) {
1363 GLstencil stencil
[MAX_WIDTH
];
1365 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1366 for (i
= 0; i
< width
; i
++) {
1367 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1369 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1373 /* clear whole buffer without masking */
1374 const GLint width
= ctx
->DrawBuffer
->Width
;
1375 const GLint height
= ctx
->DrawBuffer
->Width
;
1376 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1377 GLstencil stencil
[MAX_WIDTH
];
1379 for (i
= 0; i
< width
; i
++) {
1380 stencil
[i
] = ctx
->Stencil
.Clear
;
1382 for (y
= 0; y
< height
; y
++) {
1383 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1392 * Clear the stencil buffer.
1394 void gl_clear_stencil_buffer( GLcontext
*ctx
)
1396 if (ctx
->Driver
.WriteStencilSpan
) {
1397 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1398 clear_hardware_stencil_buffer(ctx
);
1401 clear_software_stencil_buffer(ctx
);