1 /* $Id: s_stencil.c,v 1.11 2001/03/19 02:25:36 keithw Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 #include "s_context.h"
36 #include "s_stencil.h"
44 IF stencil test fails THEN
45 Apply fail-op to stencil value
46 Don't write the pixel (RGBA,Z)
48 IF doing depth test && depth test fails THEN
49 Apply zfail-op to stencil value
50 Write RGBA and Z to appropriate buffers
52 Apply zpass-op to stencil value
61 * Return the address of a stencil buffer value given the window coords:
63 #define STENCIL_ADDRESS(X,Y) \
64 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
69 * Apply the given stencil operator to the array of stencil values.
70 * Don't touch stencil[i] if mask[i] is zero.
71 * Input: n - size of stencil array
72 * oper - the stencil buffer operator
73 * stencil - array of stencil values
74 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
75 * Output: stencil - modified values
77 static void apply_stencil_op( const GLcontext
*ctx
, GLenum oper
,
78 GLuint n
, GLstencil stencil
[],
79 const GLubyte mask
[] )
81 const GLstencil ref
= ctx
->Stencil
.Ref
;
82 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
83 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
101 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
117 GLstencil s
= stencil
[i
];
118 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
127 GLstencil s
= stencil
[i
];
128 if (s
< STENCIL_MAX
) {
129 stencil
[i
] = (GLstencil
) (s
+1);
137 /* VERIFY logic of adding 1 to a write-masked value */
138 GLstencil s
= stencil
[i
];
139 if (s
< STENCIL_MAX
) {
140 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
150 GLstencil s
= stencil
[i
];
152 stencil
[i
] = (GLstencil
) (s
-1);
160 /* VERIFY logic of subtracting 1 to a write-masked value */
161 GLstencil s
= stencil
[i
];
163 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
169 case GL_INCR_WRAP_EXT
:
180 GLstencil s
= stencil
[i
];
181 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
186 case GL_DECR_WRAP_EXT
:
197 GLstencil s
= stencil
[i
];
198 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
207 GLstencil s
= stencil
[i
];
208 stencil
[i
] = (GLstencil
) ~s
;
215 GLstencil s
= stencil
[i
];
216 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
222 _mesa_problem(ctx
, "Bad stencil op in apply_stencil_op");
230 * Apply stencil test to an array of stencil values (before depth buffering).
231 * Input: n - number of pixels in the array
232 * stencil - array of [n] stencil values
233 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
234 * Output: mask - pixels which fail the stencil test will have their
235 * mask flag set to 0.
236 * stencil - updated stencil values (where the test passed)
237 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
240 do_stencil_test( GLcontext
*ctx
, GLuint n
, GLstencil stencil
[],
243 GLubyte fail
[PB_SIZE
];
244 GLboolean allfail
= GL_FALSE
;
248 ASSERT(n
<= PB_SIZE
);
251 * Perform stencil test. The results of this operation are stored
252 * in the fail[] array:
253 * IF fail[i] is non-zero THEN
254 * the stencil fail operator is to be applied
256 * the stencil fail operator is not to be applied
259 switch (ctx
->Stencil
.Function
) {
274 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
277 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
293 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
296 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
312 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
315 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
331 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
334 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
350 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
353 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
369 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
372 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
394 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_span");
398 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
399 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
, n
, stencil
, fail
);
409 * Apply stencil and depth testing to an array of pixels.
410 * Hardware or software stencil buffer acceptable.
411 * Input: n - number of pixels in the span
412 * z - array [n] of z values
413 * stencil - array [n] of stencil values
414 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
415 * Output: stencil - modified stencil values
416 * mask - array [n] of flags (1=stencil and depth test passed)
417 * Return: GL_TRUE - all fragments failed the testing
418 * GL_FALSE - one or more fragments passed the testing
422 stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
423 const GLdepth z
[], GLstencil stencil
[],
426 ASSERT(ctx
->Stencil
.Enabled
);
427 ASSERT(n
<= PB_SIZE
);
430 * Apply the stencil test to the fragments.
431 * failMask[i] is 1 if the stencil test failed.
433 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
434 /* all fragments failed the stencil test, we're done. */
440 * Some fragments passed the stencil test, apply depth test to them
441 * and apply Zpass and Zfail stencil ops.
443 if (ctx
->Depth
.Test
==GL_FALSE
) {
445 * No depth buffer, just apply zpass stencil function to active pixels.
447 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
451 * Perform depth buffering, then apply zpass or zfail stencil function.
453 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
456 /* save the current mask bits */
457 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
459 /* apply the depth test */
460 _mesa_depth_test_span(ctx
, n
, x
, y
, z
, mask
);
462 /* Set the stencil pass/fail flags according to result of depth testing.
463 * if oldmask[i] == 0 then
464 * Don't touch the stencil value
465 * else if oldmask[i] and newmask[i] then
468 * assert(oldmask[i] && !newmask[i])
473 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
474 passmask
[i
] = oldmask
[i
] & mask
[i
];
475 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
478 /* apply the pass and fail operations */
479 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
480 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
482 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
483 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
487 return GL_TRUE
; /* one or more fragments passed both tests */
493 * Apply stencil and depth testing to the span of pixels.
494 * Both software and hardware stencil buffers are acceptable.
495 * Input: n - number of pixels in the span
496 * x, y - location of leftmost pixel in span
497 * z - array [n] of z values
498 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
499 * Output: mask - array [n] of flags (1=stencil and depth test passed)
500 * Return: GL_TRUE - all fragments failed the testing
501 * GL_FALSE - one or more fragments passed the testing
505 _mesa_stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
506 const GLdepth z
[], GLubyte mask
[] )
508 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
509 GLstencil stencilRow
[MAX_WIDTH
];
513 ASSERT(ctx
->Stencil
.Enabled
);
514 ASSERT(n
<= MAX_WIDTH
);
516 /* Get initial stencil values */
517 if (swrast
->Driver
.WriteStencilSpan
) {
518 ASSERT(swrast
->Driver
.ReadStencilSpan
);
519 /* Get stencil values from the hardware stencil buffer */
520 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, n
, x
, y
, stencilRow
);
521 stencil
= stencilRow
;
524 /* software stencil buffer */
525 stencil
= STENCIL_ADDRESS(x
, y
);
528 /* do all the stencil/depth testing/updating */
529 result
= stencil_and_ztest_span( ctx
, n
, x
, y
, z
, stencil
, mask
);
531 if (swrast
->Driver
.WriteStencilSpan
) {
532 /* Write updated stencil values into hardware stencil buffer */
533 (swrast
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
543 * Apply the given stencil operator for each pixel in the array whose
544 * mask flag is set. This is for software stencil buffers only.
545 * Input: n - number of pixels in the span
546 * x, y - array of [n] pixels
547 * operator - the stencil buffer operator
548 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
551 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
552 GLuint n
, const GLint x
[], const GLint y
[],
553 GLenum oper
, const GLubyte mask
[] )
555 const GLstencil ref
= ctx
->Stencil
.Ref
;
556 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
557 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
560 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
570 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
578 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
579 *sptr
= (GLstencil
) (invmask
& *sptr
);
588 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
596 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
597 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
606 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
607 if (*sptr
< STENCIL_MAX
) {
608 *sptr
= (GLstencil
) (*sptr
+ 1);
616 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
617 if (*sptr
< STENCIL_MAX
) {
618 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
628 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
630 *sptr
= (GLstencil
) (*sptr
- 1);
638 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
640 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
646 case GL_INCR_WRAP_EXT
:
650 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
651 *sptr
= (GLstencil
) (*sptr
+ 1);
658 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
659 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
664 case GL_DECR_WRAP_EXT
:
668 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
669 *sptr
= (GLstencil
) (*sptr
- 1);
676 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
677 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
686 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
687 *sptr
= (GLstencil
) (~*sptr
);
694 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
695 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
701 _mesa_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
708 * Apply stencil test to an array of pixels before depth buffering.
709 * Used for software stencil buffer only.
710 * Input: n - number of pixels in the span
711 * x, y - array of [n] pixels to stencil
712 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
713 * Output: mask - pixels which fail the stencil test will have their
714 * mask flag set to 0.
715 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
718 stencil_test_pixels( GLcontext
*ctx
, GLuint n
,
719 const GLint x
[], const GLint y
[], GLubyte mask
[] )
721 GLubyte fail
[PB_SIZE
];
724 GLboolean allfail
= GL_FALSE
;
726 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
729 * Perform stencil test. The results of this operation are stored
730 * in the fail[] array:
731 * IF fail[i] is non-zero THEN
732 * the stencil fail operator is to be applied
734 * the stencil fail operator is not to be applied
738 switch (ctx
->Stencil
.Function
) {
753 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
756 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
757 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
773 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
776 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
777 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
793 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
796 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
797 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
813 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
816 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
817 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
833 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
836 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
837 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
853 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
856 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
857 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
879 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
883 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
884 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
, fail
);
894 * Apply stencil and depth testing to an array of pixels.
895 * This is used both for software and hardware stencil buffers.
897 * The comments in this function are a bit sparse but the code is
898 * almost identical to stencil_and_ztest_span(), which is well
901 * Input: n - number of pixels in the array
902 * x, y - array of [n] pixel positions
903 * z - array [n] of z values
904 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
905 * Output: mask - array [n] of flags (1=stencil and depth test passed)
906 * Return: GL_TRUE - all fragments failed the testing
907 * GL_FALSE - one or more fragments passed the testing
910 _mesa_stencil_and_ztest_pixels( GLcontext
*ctx
,
911 GLuint n
, const GLint x
[], const GLint y
[],
912 const GLdepth z
[], GLubyte mask
[] )
914 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
915 ASSERT(ctx
->Stencil
.Enabled
);
916 ASSERT(n
<= PB_SIZE
);
918 if (swrast
->Driver
.WriteStencilPixels
) {
919 /*** Hardware stencil buffer ***/
920 GLstencil stencil
[PB_SIZE
];
921 GLubyte origMask
[PB_SIZE
];
923 ASSERT(swrast
->Driver
.ReadStencilPixels
);
924 (*swrast
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
926 MEMCPY(origMask
, mask
, n
* sizeof(GLubyte
));
928 (void) do_stencil_test(ctx
, n
, stencil
, mask
);
930 if (ctx
->Depth
.Test
== GL_FALSE
) {
931 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
934 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
936 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
937 GLubyte failmask
[PB_SIZE
];
939 for (i
= 0; i
< n
; i
++) {
940 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
941 failmask
[i
] = origMask
[i
] & (mask
[i
] ^ 1);
943 apply_stencil_op(ctx
, ctx
->Stencil
.ZFailFunc
,
944 n
, stencil
, failmask
);
946 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
947 GLubyte passmask
[PB_SIZE
];
949 for (i
= 0; i
< n
; i
++) {
950 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
951 passmask
[i
] = origMask
[i
] & mask
[i
];
953 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
,
954 n
, stencil
, passmask
);
958 /* Write updated stencil values into hardware stencil buffer */
959 (swrast
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, origMask
);
964 /*** Software stencil buffer ***/
966 if (stencil_test_pixels(ctx
, n
, x
, y
, mask
) == GL_FALSE
) {
967 /* all fragments failed the stencil test, we're done. */
971 if (ctx
->Depth
.Test
==GL_FALSE
) {
972 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
973 ctx
->Stencil
.ZPassFunc
, mask
);
976 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
979 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
981 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
984 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
985 passmask
[i
] = oldmask
[i
] & mask
[i
];
986 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
989 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
990 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
991 ctx
->Stencil
.ZFailFunc
, failmask
);
993 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
994 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
995 ctx
->Stencil
.ZPassFunc
, passmask
);
999 return GL_TRUE
; /* one or more fragments passed both tests */
1006 * Return a span of stencil values from the stencil buffer.
1007 * Used for glRead/CopyPixels
1008 * Input: n - how many pixels
1009 * x,y - location of first pixel
1010 * Output: stencil - the array of stencil values
1013 _mesa_read_stencil_span( GLcontext
*ctx
,
1014 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1016 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1017 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1018 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1019 /* span is completely outside framebuffer */
1020 return; /* undefined values OK */
1029 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1030 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1039 if (swrast
->Driver
.ReadStencilSpan
) {
1040 (*swrast
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1042 else if (ctx
->DrawBuffer
->Stencil
) {
1043 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1044 #if STENCIL_BITS == 8
1045 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1057 * Write a span of stencil values to the stencil buffer.
1058 * Used for glDraw/CopyPixels
1059 * Input: n - how many pixels
1060 * x, y - location of first pixel
1061 * stencil - the array of stencil values
1064 _mesa_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1065 const GLstencil stencil
[] )
1067 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1068 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1069 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1070 /* span is completely outside framebuffer */
1071 return; /* undefined values OK */
1080 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1081 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1088 if (swrast
->Driver
.WriteStencilSpan
) {
1089 (*swrast
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, stencil
, NULL
);
1091 else if (ctx
->DrawBuffer
->Stencil
) {
1092 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1093 #if STENCIL_BITS == 8
1094 MEMCPY( s
, stencil
, n
* sizeof(GLstencil
) );
1106 * Allocate a new stencil buffer. If there's an old one it will be
1107 * deallocated first. The new stencil buffer will be uninitialized.
1110 _mesa_alloc_stencil_buffer( GLcontext
*ctx
)
1112 GLuint buffersize
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1114 /* deallocate current stencil buffer if present */
1115 if (ctx
->DrawBuffer
->Stencil
) {
1116 FREE(ctx
->DrawBuffer
->Stencil
);
1117 ctx
->DrawBuffer
->Stencil
= NULL
;
1120 /* allocate new stencil buffer */
1121 ctx
->DrawBuffer
->Stencil
= (GLstencil
*) MALLOC(buffersize
* sizeof(GLstencil
));
1122 if (!ctx
->DrawBuffer
->Stencil
) {
1124 /* _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE ); */
1125 _mesa_error( ctx
, GL_OUT_OF_MEMORY
, "_mesa_alloc_stencil_buffer" );
1132 * Clear the software (malloc'd) stencil buffer.
1135 clear_software_stencil_buffer( GLcontext
*ctx
)
1137 if (ctx
->Visual
.stencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1138 /* no stencil buffer */
1142 if (ctx
->Scissor
.Enabled
) {
1143 /* clear scissor region only */
1144 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1145 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1146 /* must apply mask to the clear */
1148 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1149 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1150 const GLstencil invMask
= ~mask
;
1151 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1152 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1154 for (i
= 0; i
< width
; i
++) {
1155 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1162 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1163 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1165 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1168 for (i
= 0; i
< width
; i
++)
1169 stencil
[x
] = ctx
->Stencil
.Clear
;
1175 /* clear whole stencil buffer */
1176 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1177 /* must apply mask to the clear */
1178 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1179 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1180 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1181 const GLstencil invMask
= ~mask
;
1182 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1184 for (i
= 0; i
< n
; i
++) {
1185 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1189 /* clear whole buffer without masking */
1190 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1191 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1194 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1197 for (i
= 0; i
< n
; i
++) {
1198 stencil
[i
] = ctx
->Stencil
.Clear
;
1208 * Clear the hardware (in graphics card) stencil buffer.
1209 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1211 * Actually, if there is a hardware stencil buffer it really should have
1212 * been cleared in Driver.Clear()! However, if the hardware does not
1213 * support scissored clears or masked clears (i.e. glStencilMask) then
1214 * we have to use the span-based functions.
1217 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1219 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1220 ASSERT(swrast
->Driver
.WriteStencilSpan
);
1221 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1223 if (ctx
->Scissor
.Enabled
) {
1224 /* clear scissor region only */
1225 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1226 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1227 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1228 /* must apply mask to the clear */
1230 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1231 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1232 const GLstencil invMask
= ~mask
;
1233 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1234 GLstencil stencil
[MAX_WIDTH
];
1236 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1237 for (i
= 0; i
< width
; i
++) {
1238 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1240 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1245 GLstencil stencil
[MAX_WIDTH
];
1247 for (i
= 0; i
< width
; i
++) {
1248 stencil
[i
] = ctx
->Stencil
.Clear
;
1250 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1251 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1256 /* clear whole stencil buffer */
1257 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1258 /* must apply mask to the clear */
1259 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1260 const GLstencil invMask
= ~mask
;
1261 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1262 const GLint width
= ctx
->DrawBuffer
->Width
;
1263 const GLint height
= ctx
->DrawBuffer
->Height
;
1264 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1266 for (y
= 0; y
< height
; y
++) {
1267 GLstencil stencil
[MAX_WIDTH
];
1269 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1270 for (i
= 0; i
< width
; i
++) {
1271 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1273 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1277 /* clear whole buffer without masking */
1278 const GLint width
= ctx
->DrawBuffer
->Width
;
1279 const GLint height
= ctx
->DrawBuffer
->Width
;
1280 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1281 GLstencil stencil
[MAX_WIDTH
];
1283 for (i
= 0; i
< width
; i
++) {
1284 stencil
[i
] = ctx
->Stencil
.Clear
;
1286 for (y
= 0; y
< height
; y
++) {
1287 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1296 * Clear the stencil buffer.
1299 _mesa_clear_stencil_buffer( GLcontext
*ctx
)
1301 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1302 if (swrast
->Driver
.WriteStencilSpan
) {
1303 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1304 clear_hardware_stencil_buffer(ctx
);
1307 clear_software_stencil_buffer(ctx
);