1 /* $Id: s_stencil.c,v 1.22 2002/03/19 16:47:05 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2002 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"
35 #include "s_stencil.h"
41 IF stencil test fails THEN
42 Apply fail-op to stencil value
43 Don't write the pixel (RGBA,Z)
45 IF doing depth test && depth test fails THEN
46 Apply zfail-op to stencil value
47 Write RGBA and Z to appropriate buffers
49 Apply zpass-op to stencil value
56 * Return the address of a stencil buffer value given the window coords:
58 #define STENCIL_ADDRESS(X,Y) \
59 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
64 * Apply the given stencil operator to the array of stencil values.
65 * Don't touch stencil[i] if mask[i] is zero.
66 * Input: n - size of stencil array
67 * oper - the stencil buffer operator
68 * stencil - array of stencil values
69 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
70 * Output: stencil - modified values
73 apply_stencil_op( const GLcontext
*ctx
, GLenum oper
,
74 GLuint n
, GLstencil stencil
[], const GLubyte mask
[] )
76 const GLstencil ref
= ctx
->Stencil
.Ref
;
77 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
78 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
96 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
112 GLstencil s
= stencil
[i
];
113 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
122 GLstencil s
= stencil
[i
];
123 if (s
< STENCIL_MAX
) {
124 stencil
[i
] = (GLstencil
) (s
+1);
132 /* VERIFY logic of adding 1 to a write-masked value */
133 GLstencil s
= stencil
[i
];
134 if (s
< STENCIL_MAX
) {
135 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
145 GLstencil s
= stencil
[i
];
147 stencil
[i
] = (GLstencil
) (s
-1);
155 /* VERIFY logic of subtracting 1 to a write-masked value */
156 GLstencil s
= stencil
[i
];
158 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
164 case GL_INCR_WRAP_EXT
:
175 GLstencil s
= stencil
[i
];
176 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
181 case GL_DECR_WRAP_EXT
:
192 GLstencil s
= stencil
[i
];
193 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
202 GLstencil s
= stencil
[i
];
203 stencil
[i
] = (GLstencil
) ~s
;
210 GLstencil s
= stencil
[i
];
211 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
217 _mesa_problem(ctx
, "Bad stencil op in apply_stencil_op");
225 * Apply stencil test to an array of stencil values (before depth buffering).
226 * Input: n - number of pixels in the array
227 * stencil - array of [n] stencil values
228 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
229 * Output: mask - pixels which fail the stencil test will have their
230 * mask flag set to 0.
231 * stencil - updated stencil values (where the test passed)
232 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
235 do_stencil_test( GLcontext
*ctx
, GLuint n
, GLstencil stencil
[],
238 GLubyte fail
[MAX_WIDTH
];
239 GLboolean allfail
= GL_FALSE
;
243 ASSERT(n
<= MAX_WIDTH
);
246 * Perform stencil test. The results of this operation are stored
247 * in the fail[] array:
248 * IF fail[i] is non-zero THEN
249 * the stencil fail operator is to be applied
251 * the stencil fail operator is not to be applied
254 switch (ctx
->Stencil
.Function
) {
256 /* never pass; always fail */
269 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
272 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
288 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
291 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
307 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
310 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
326 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
329 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
345 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
348 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
364 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
367 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
389 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_span");
393 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
394 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
, n
, stencil
, fail
);
403 * Apply stencil and depth testing to the span of pixels.
404 * Both software and hardware stencil buffers are acceptable.
405 * Input: n - number of pixels in the span
406 * x, y - location of leftmost pixel in span
407 * z - array [n] of z values
408 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
409 * Output: mask - array [n] of flags (1=stencil and depth test passed)
410 * Return: GL_FALSE - all fragments failed the testing
411 * GL_TRUE - one or more fragments passed the testing
415 stencil_and_ztest_span(GLcontext
*ctx
, struct sw_span
*span
)
417 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
418 GLstencil stencilRow
[MAX_WIDTH
];
420 const GLuint n
= span
->end
;
421 const GLint x
= span
->x
;
422 const GLint y
= span
->y
;
423 GLubyte
*mask
= span
->mask
;
425 ASSERT((span
->arrayMask
& SPAN_XY
) == 0);
426 ASSERT(ctx
->Stencil
.Enabled
);
427 ASSERT(n
<= MAX_WIDTH
);
429 if (ctx
->Depth
.Test
) {
430 ASSERT(span
->arrayMask
& SPAN_Z
);
434 /* Get initial stencil values */
435 if (swrast
->Driver
.WriteStencilSpan
) {
436 /* Get stencil values from the hardware stencil buffer */
437 ASSERT(swrast
->Driver
.ReadStencilSpan
);
438 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, n
, x
, y
, stencilRow
);
439 stencil
= stencilRow
;
442 /* Get pointer into software stencil buffer */
443 stencil
= STENCIL_ADDRESS(x
, y
);
447 * Apply the stencil test to the fragments.
448 * failMask[i] is 1 if the stencil test failed.
450 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
451 /* all fragments failed the stencil test, we're done. */
452 span
->writeAll
= GL_FALSE
;
457 * Some fragments passed the stencil test, apply depth test to them
458 * and apply Zpass and Zfail stencil ops.
460 if (ctx
->Depth
.Test
== GL_FALSE
) {
462 * No depth buffer, just apply zpass stencil function to active pixels.
464 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
468 * Perform depth buffering, then apply zpass or zfail stencil function.
470 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
473 /* save the current mask bits */
474 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
476 /* apply the depth test */
477 _mesa_depth_test_span(ctx
, span
);
479 /* Set the stencil pass/fail flags according to result of depth testing.
480 * if oldmask[i] == 0 then
481 * Don't touch the stencil value
482 * else if oldmask[i] and newmask[i] then
485 * assert(oldmask[i] && !newmask[i])
490 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
491 passmask
[i
] = oldmask
[i
] & mask
[i
];
492 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
495 /* apply the pass and fail operations */
496 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
497 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
499 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
500 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
505 * Write updated stencil values back into hardware stencil buffer.
507 if (swrast
->Driver
.WriteStencilSpan
) {
508 ASSERT(stencil
== stencilRow
);
509 (swrast
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
512 span
->writeAll
= GL_FALSE
;
514 return GL_TRUE
; /* one or more fragments passed both tests */
521 * Apply the given stencil operator for each pixel in the array whose
523 * \note This is for software stencil buffers only.
524 * Input: n - number of pixels in the span
525 * x, y - array of [n] pixels
526 * operator - the stencil buffer operator
527 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
530 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
531 GLuint n
, const GLint x
[], const GLint y
[],
532 GLenum oper
, const GLubyte mask
[] )
534 const GLstencil ref
= ctx
->Stencil
.Ref
;
535 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
536 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
539 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
549 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
557 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
558 *sptr
= (GLstencil
) (invmask
& *sptr
);
567 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
575 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
576 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
585 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
586 if (*sptr
< STENCIL_MAX
) {
587 *sptr
= (GLstencil
) (*sptr
+ 1);
595 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
596 if (*sptr
< STENCIL_MAX
) {
597 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
607 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
609 *sptr
= (GLstencil
) (*sptr
- 1);
617 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
619 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
625 case GL_INCR_WRAP_EXT
:
629 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
630 *sptr
= (GLstencil
) (*sptr
+ 1);
637 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
638 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
643 case GL_DECR_WRAP_EXT
:
647 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
648 *sptr
= (GLstencil
) (*sptr
- 1);
655 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
656 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
665 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
666 *sptr
= (GLstencil
) (~*sptr
);
673 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
674 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
680 _mesa_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
687 * Apply stencil test to an array of pixels before depth buffering.
689 * \note Used for software stencil buffer only.
690 * Input: n - number of pixels in the span
691 * x, y - array of [n] pixels to stencil
692 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
693 * Output: mask - pixels which fail the stencil test will have their
694 * mask flag set to 0.
695 * \return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
698 stencil_test_pixels( GLcontext
*ctx
, GLuint n
,
699 const GLint x
[], const GLint y
[], GLubyte mask
[] )
701 GLubyte fail
[MAX_WIDTH
];
704 GLboolean allfail
= GL_FALSE
;
706 /* software stencil buffer only! */
707 ASSERT(ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
708 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.ReadStencilSpan
);
709 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
);
712 * Perform stencil test. The results of this operation are stored
713 * in the fail[] array:
714 * IF fail[i] is non-zero THEN
715 * the stencil fail operator is to be applied
717 * the stencil fail operator is not to be applied
721 switch (ctx
->Stencil
.Function
) {
736 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
739 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
740 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
756 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
759 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
760 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
776 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
779 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
780 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
796 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
799 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
800 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
816 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
819 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
820 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
836 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
839 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
840 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
862 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
866 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
867 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
, fail
);
877 * Apply stencil and depth testing to an array of pixels.
878 * This is used both for software and hardware stencil buffers.
880 * The comments in this function are a bit sparse but the code is
881 * almost identical to stencil_and_ztest_span(), which is well
884 * Input: n - number of pixels in the array
885 * x, y - array of [n] pixel positions
886 * z - array [n] of z values
887 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
888 * Output: mask - array [n] of flags (1=stencil and depth test passed)
889 * Return: GL_FALSE - all fragments failed the testing
890 * GL_TRUE - one or more fragments passed the testing
893 stencil_and_ztest_pixels( GLcontext
*ctx
, struct sw_span
*span
)
895 const GLuint n
= span
->end
;
896 const GLint
*x
= span
->xArray
;
897 const GLint
*y
= span
->yArray
;
898 GLubyte
*mask
= span
->mask
;
899 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
901 ASSERT(span
->arrayMask
& SPAN_XY
);
902 ASSERT(ctx
->Stencil
.Enabled
);
903 ASSERT(n
<= MAX_WIDTH
);
905 if (swrast
->Driver
.WriteStencilPixels
) {
906 /*** Hardware stencil buffer ***/
907 GLstencil stencil
[MAX_WIDTH
];
908 GLubyte origMask
[MAX_WIDTH
];
910 ASSERT(!ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
911 ASSERT(swrast
->Driver
.ReadStencilPixels
);
912 (*swrast
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
914 MEMCPY(origMask
, mask
, n
* sizeof(GLubyte
));
916 (void) do_stencil_test(ctx
, n
, stencil
, mask
);
918 if (ctx
->Depth
.Test
== GL_FALSE
) {
919 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
922 _mesa_depth_test_span(ctx
, span
);
924 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
925 GLubyte failmask
[MAX_WIDTH
];
927 for (i
= 0; i
< n
; i
++) {
928 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
929 failmask
[i
] = origMask
[i
] & (mask
[i
] ^ 1);
931 apply_stencil_op(ctx
, ctx
->Stencil
.ZFailFunc
,
932 n
, stencil
, failmask
);
934 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
935 GLubyte passmask
[MAX_WIDTH
];
937 for (i
= 0; i
< n
; i
++) {
938 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
939 passmask
[i
] = origMask
[i
] & mask
[i
];
941 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
,
942 n
, stencil
, passmask
);
946 /* Write updated stencil values into hardware stencil buffer */
947 (swrast
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, origMask
);
952 /*** Software stencil buffer ***/
954 ASSERT(ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
956 if (stencil_test_pixels(ctx
, n
, x
, y
, mask
) == GL_FALSE
) {
957 /* all fragments failed the stencil test, we're done. */
961 if (ctx
->Depth
.Test
==GL_FALSE
) {
962 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
963 ctx
->Stencil
.ZPassFunc
, mask
);
966 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
969 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
971 _mesa_depth_test_span(ctx
, span
);
974 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
975 passmask
[i
] = oldmask
[i
] & mask
[i
];
976 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
979 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
980 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
981 ctx
->Stencil
.ZFailFunc
, failmask
);
983 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
984 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
985 ctx
->Stencil
.ZPassFunc
, passmask
);
989 return GL_TRUE
; /* one or more fragments passed both tests */
995 * /return GL_TRUE = one or more fragments passed,
996 * GL_FALSE = all fragments failed.
999 _mesa_stencil_and_ztest_span(GLcontext
*ctx
, struct sw_span
*span
)
1001 if (span
->arrayMask
& SPAN_XY
)
1002 return stencil_and_ztest_pixels(ctx
, span
);
1004 return stencil_and_ztest_span(ctx
, span
);
1009 * Return a span of stencil values from the stencil buffer.
1010 * Used for glRead/CopyPixels
1011 * Input: n - how many pixels
1012 * x,y - location of first pixel
1013 * Output: stencil - the array of stencil values
1016 _mesa_read_stencil_span( GLcontext
*ctx
,
1017 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1019 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1020 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1021 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1022 /* span is completely outside framebuffer */
1023 return; /* undefined values OK */
1032 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1033 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1042 if (swrast
->Driver
.ReadStencilSpan
) {
1043 (*swrast
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1045 else if (ctx
->DrawBuffer
->Stencil
) {
1046 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1047 #if STENCIL_BITS == 8
1048 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1060 * Write a span of stencil values to the stencil buffer.
1061 * Used for glDraw/CopyPixels
1062 * Input: n - how many pixels
1063 * x, y - location of first pixel
1064 * stencil - the array of stencil values
1067 _mesa_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1068 const GLstencil stencil
[] )
1070 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1071 const GLstencil
*ssrc
= stencil
;
1073 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1074 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1075 /* span is completely outside framebuffer */
1076 return; /* undefined values OK */
1085 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1086 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1093 if (swrast
->Driver
.WriteStencilSpan
) {
1094 (*swrast
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, ssrc
, NULL
);
1096 else if (ctx
->DrawBuffer
->Stencil
) {
1097 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1098 #if STENCIL_BITS == 8
1099 MEMCPY( s
, ssrc
, n
* sizeof(GLstencil
) );
1111 * Allocate a new stencil buffer. If there's an old one it will be
1112 * deallocated first. The new stencil buffer will be uninitialized.
1115 _mesa_alloc_stencil_buffer( GLframebuffer
*buffer
)
1117 /* deallocate current stencil buffer if present */
1118 if (buffer
->Stencil
) {
1119 MESA_PBUFFER_FREE(buffer
->Stencil
);
1120 buffer
->Stencil
= NULL
;
1123 /* allocate new stencil buffer */
1124 buffer
->Stencil
= (GLstencil
*)
1125 MESA_PBUFFER_ALLOC(buffer
->Width
* buffer
->Height
* sizeof(GLstencil
));
1126 if (!buffer
->Stencil
) {
1128 _mesa_error( NULL
, GL_OUT_OF_MEMORY
, "_mesa_alloc_stencil_buffer" );
1135 * Clear the software (malloc'd) stencil buffer.
1138 clear_software_stencil_buffer( GLcontext
*ctx
)
1140 if (ctx
->Visual
.stencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1141 /* no stencil buffer */
1145 if (ctx
->Scissor
.Enabled
) {
1146 /* clear scissor region only */
1147 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1148 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1149 /* must apply mask to the clear */
1151 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1152 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1153 const GLstencil invMask
= ~mask
;
1154 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1155 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1157 for (i
= 0; i
< width
; i
++) {
1158 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1165 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1166 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1168 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1171 for (i
= 0; i
< width
; i
++)
1172 stencil
[x
] = ctx
->Stencil
.Clear
;
1178 /* clear whole stencil buffer */
1179 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1180 /* must apply mask to the clear */
1181 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1182 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1183 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1184 const GLstencil invMask
= ~mask
;
1185 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1187 for (i
= 0; i
< n
; i
++) {
1188 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1192 /* clear whole buffer without masking */
1193 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1194 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1197 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1200 for (i
= 0; i
< n
; i
++) {
1201 stencil
[i
] = ctx
->Stencil
.Clear
;
1211 * Clear the hardware (in graphics card) stencil buffer.
1212 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1214 * Actually, if there is a hardware stencil buffer it really should have
1215 * been cleared in Driver.Clear()! However, if the hardware does not
1216 * support scissored clears or masked clears (i.e. glStencilMask) then
1217 * we have to use the span-based functions.
1220 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1222 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1223 ASSERT(swrast
->Driver
.WriteStencilSpan
);
1224 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1226 if (ctx
->Scissor
.Enabled
) {
1227 /* clear scissor region only */
1228 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1229 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1230 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1231 /* must apply mask to the clear */
1233 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1234 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1235 const GLstencil invMask
= ~mask
;
1236 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1237 GLstencil stencil
[MAX_WIDTH
];
1239 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1240 for (i
= 0; i
< width
; i
++) {
1241 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1243 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1248 GLstencil stencil
[MAX_WIDTH
];
1250 for (i
= 0; i
< width
; i
++) {
1251 stencil
[i
] = ctx
->Stencil
.Clear
;
1253 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1254 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1259 /* clear whole stencil buffer */
1260 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1261 /* must apply mask to the clear */
1262 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1263 const GLstencil invMask
= ~mask
;
1264 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1265 const GLint width
= ctx
->DrawBuffer
->Width
;
1266 const GLint height
= ctx
->DrawBuffer
->Height
;
1267 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1269 for (y
= 0; y
< height
; y
++) {
1270 GLstencil stencil
[MAX_WIDTH
];
1272 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1273 for (i
= 0; i
< width
; i
++) {
1274 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1276 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1280 /* clear whole buffer without masking */
1281 const GLint width
= ctx
->DrawBuffer
->Width
;
1282 const GLint height
= ctx
->DrawBuffer
->Height
;
1283 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1284 GLstencil stencil
[MAX_WIDTH
];
1286 for (i
= 0; i
< width
; i
++) {
1287 stencil
[i
] = ctx
->Stencil
.Clear
;
1289 for (y
= 0; y
< height
; y
++) {
1290 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1299 * Clear the stencil buffer (hardware or software).
1302 _mesa_clear_stencil_buffer( GLcontext
*ctx
)
1304 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1305 if (swrast
->Driver
.WriteStencilSpan
) {
1306 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1307 clear_hardware_stencil_buffer(ctx
);
1310 clear_software_stencil_buffer(ctx
);