1 /* $Id: s_stencil.c,v 1.8 2001/03/03 20:33:30 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.
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 GLstencil stencilRow
[MAX_WIDTH
];
512 ASSERT(ctx
->Stencil
.Enabled
);
513 ASSERT(n
<= MAX_WIDTH
);
515 /* Get initial stencil values */
516 if (ctx
->Driver
.WriteStencilSpan
) {
517 ASSERT(ctx
->Driver
.ReadStencilSpan
);
518 /* Get stencil values from the hardware stencil buffer */
519 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, n
, x
, y
, stencilRow
);
520 stencil
= stencilRow
;
523 /* software stencil buffer */
524 stencil
= STENCIL_ADDRESS(x
, y
);
527 /* do all the stencil/depth testing/updating */
528 result
= stencil_and_ztest_span( ctx
, n
, x
, y
, z
, stencil
, mask
);
530 if (ctx
->Driver
.WriteStencilSpan
) {
531 /* Write updated stencil values into hardware stencil buffer */
532 (ctx
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
542 * Apply the given stencil operator for each pixel in the array whose
543 * mask flag is set. This is for software stencil buffers only.
544 * Input: n - number of pixels in the span
545 * x, y - array of [n] pixels
546 * operator - the stencil buffer operator
547 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
550 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
551 GLuint n
, const GLint x
[], const GLint y
[],
552 GLenum oper
, const GLubyte mask
[] )
554 const GLstencil ref
= ctx
->Stencil
.Ref
;
555 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
556 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
559 ASSERT(!ctx
->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
569 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
577 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
578 *sptr
= (GLstencil
) (invmask
& *sptr
);
587 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
595 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
596 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
605 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
606 if (*sptr
< STENCIL_MAX
) {
607 *sptr
= (GLstencil
) (*sptr
+ 1);
615 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
616 if (*sptr
< STENCIL_MAX
) {
617 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
627 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
629 *sptr
= (GLstencil
) (*sptr
- 1);
637 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
639 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
645 case GL_INCR_WRAP_EXT
:
649 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
650 *sptr
= (GLstencil
) (*sptr
+ 1);
657 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
658 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
663 case GL_DECR_WRAP_EXT
:
667 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
668 *sptr
= (GLstencil
) (*sptr
- 1);
675 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
676 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
685 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
686 *sptr
= (GLstencil
) (~*sptr
);
693 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
694 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
700 _mesa_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
707 * Apply stencil test to an array of pixels before depth buffering.
708 * Used for software stencil buffer only.
709 * Input: n - number of pixels in the span
710 * x, y - array of [n] pixels to stencil
711 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
712 * Output: mask - pixels which fail the stencil test will have their
713 * mask flag set to 0.
714 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
717 stencil_test_pixels( GLcontext
*ctx
, GLuint n
,
718 const GLint x
[], const GLint y
[], GLubyte mask
[] )
720 GLubyte fail
[PB_SIZE
];
723 GLboolean allfail
= GL_FALSE
;
725 ASSERT(!ctx
->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
728 * Perform stencil test. The results of this operation are stored
729 * in the fail[] array:
730 * IF fail[i] is non-zero THEN
731 * the stencil fail operator is to be applied
733 * the stencil fail operator is not to be applied
737 switch (ctx
->Stencil
.Function
) {
752 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
755 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
756 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
772 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
775 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
776 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
792 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
795 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
796 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
812 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
815 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
816 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
832 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
835 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
836 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
852 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
855 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
856 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
878 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
882 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
883 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
, fail
);
893 * Apply stencil and depth testing to an array of pixels.
894 * This is used both for software and hardware stencil buffers.
896 * The comments in this function are a bit sparse but the code is
897 * almost identical to stencil_and_ztest_span(), which is well
900 * Input: n - number of pixels in the array
901 * x, y - array of [n] pixel positions
902 * z - array [n] of z values
903 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
904 * Output: mask - array [n] of flags (1=stencil and depth test passed)
905 * Return: GL_TRUE - all fragments failed the testing
906 * GL_FALSE - one or more fragments passed the testing
909 _mesa_stencil_and_ztest_pixels( GLcontext
*ctx
,
910 GLuint n
, const GLint x
[], const GLint y
[],
911 const GLdepth z
[], GLubyte mask
[] )
913 ASSERT(ctx
->Stencil
.Enabled
);
914 ASSERT(n
<= PB_SIZE
);
916 if (ctx
->Driver
.WriteStencilPixels
) {
917 /*** Hardware stencil buffer ***/
918 GLstencil stencil
[PB_SIZE
];
919 GLubyte origMask
[PB_SIZE
];
921 ASSERT(ctx
->Driver
.ReadStencilPixels
);
922 (*ctx
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
924 MEMCPY(origMask
, mask
, n
* sizeof(GLubyte
));
926 (void) do_stencil_test(ctx
, n
, stencil
, mask
);
928 if (ctx
->Depth
.Test
== GL_FALSE
) {
929 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
932 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
934 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
935 GLubyte failmask
[PB_SIZE
];
937 for (i
= 0; i
< n
; i
++) {
938 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
939 failmask
[i
] = origMask
[i
] & (mask
[i
] ^ 1);
941 apply_stencil_op(ctx
, ctx
->Stencil
.ZFailFunc
,
942 n
, stencil
, failmask
);
944 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
945 GLubyte passmask
[PB_SIZE
];
947 for (i
= 0; i
< n
; i
++) {
948 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
949 passmask
[i
] = origMask
[i
] & mask
[i
];
951 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
,
952 n
, stencil
, passmask
);
956 /* Write updated stencil values into hardware stencil buffer */
957 (ctx
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, origMask
);
962 /*** Software stencil buffer ***/
964 if (stencil_test_pixels(ctx
, n
, x
, y
, mask
) == GL_FALSE
) {
965 /* all fragments failed the stencil test, we're done. */
969 if (ctx
->Depth
.Test
==GL_FALSE
) {
970 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
971 ctx
->Stencil
.ZPassFunc
, mask
);
974 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
977 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
979 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
982 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
983 passmask
[i
] = oldmask
[i
] & mask
[i
];
984 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
987 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
988 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
989 ctx
->Stencil
.ZFailFunc
, failmask
);
991 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
992 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
993 ctx
->Stencil
.ZPassFunc
, passmask
);
997 return GL_TRUE
; /* one or more fragments passed both tests */
1004 * Return a span of stencil values from the stencil buffer.
1005 * Used for glRead/CopyPixels
1006 * Input: n - how many pixels
1007 * x,y - location of first pixel
1008 * Output: stencil - the array of stencil values
1011 _mesa_read_stencil_span( GLcontext
*ctx
,
1012 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1014 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1015 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1016 /* span is completely outside framebuffer */
1017 return; /* undefined values OK */
1026 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1027 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1036 if (ctx
->Driver
.ReadStencilSpan
) {
1037 (*ctx
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1039 else if (ctx
->DrawBuffer
->Stencil
) {
1040 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1041 #if STENCIL_BITS == 8
1042 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1054 * Write a span of stencil values to the stencil buffer.
1055 * Used for glDraw/CopyPixels
1056 * Input: n - how many pixels
1057 * x, y - location of first pixel
1058 * stencil - the array of stencil values
1061 _mesa_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1062 const GLstencil stencil
[] )
1064 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1065 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1066 /* span is completely outside framebuffer */
1067 return; /* undefined values OK */
1076 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1077 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1084 if (ctx
->Driver
.WriteStencilSpan
) {
1085 (*ctx
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, stencil
, NULL
);
1087 else if (ctx
->DrawBuffer
->Stencil
) {
1088 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1089 #if STENCIL_BITS == 8
1090 MEMCPY( s
, stencil
, n
* sizeof(GLstencil
) );
1102 * Allocate a new stencil buffer. If there's an old one it will be
1103 * deallocated first. The new stencil buffer will be uninitialized.
1106 _mesa_alloc_stencil_buffer( GLcontext
*ctx
)
1108 GLuint buffersize
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1110 /* deallocate current stencil buffer if present */
1111 if (ctx
->DrawBuffer
->Stencil
) {
1112 FREE(ctx
->DrawBuffer
->Stencil
);
1113 ctx
->DrawBuffer
->Stencil
= NULL
;
1116 /* allocate new stencil buffer */
1117 ctx
->DrawBuffer
->Stencil
= (GLstencil
*) MALLOC(buffersize
* sizeof(GLstencil
));
1118 if (!ctx
->DrawBuffer
->Stencil
) {
1120 /* _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE ); */
1121 _mesa_error( ctx
, GL_OUT_OF_MEMORY
, "_mesa_alloc_stencil_buffer" );
1128 * Clear the software (malloc'd) stencil buffer.
1131 clear_software_stencil_buffer( GLcontext
*ctx
)
1133 if (ctx
->Visual
.stencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1134 /* no stencil buffer */
1138 if (ctx
->Scissor
.Enabled
) {
1139 /* clear scissor region only */
1140 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1141 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1142 /* must apply mask to the clear */
1144 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1145 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1146 const GLstencil invMask
= ~mask
;
1147 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1148 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1150 for (i
= 0; i
< width
; i
++) {
1151 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1158 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1159 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1161 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1164 for (i
= 0; i
< width
; i
++)
1165 stencil
[x
] = ctx
->Stencil
.Clear
;
1171 /* clear whole stencil buffer */
1172 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1173 /* must apply mask to the clear */
1174 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1175 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1176 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1177 const GLstencil invMask
= ~mask
;
1178 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1180 for (i
= 0; i
< n
; i
++) {
1181 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1185 /* clear whole buffer without masking */
1186 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1187 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1190 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1193 for (i
= 0; i
< n
; i
++) {
1194 stencil
[i
] = ctx
->Stencil
.Clear
;
1204 * Clear the hardware (in graphics card) stencil buffer.
1205 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1207 * Actually, if there is a hardware stencil buffer it really should have
1208 * been cleared in Driver.Clear()! However, if the hardware does not
1209 * support scissored clears or masked clears (i.e. glStencilMask) then
1210 * we have to use the span-based functions.
1213 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1215 ASSERT(ctx
->Driver
.WriteStencilSpan
);
1216 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1218 if (ctx
->Scissor
.Enabled
) {
1219 /* clear scissor region only */
1220 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1221 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1222 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1223 /* must apply mask to the clear */
1225 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1226 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1227 const GLstencil invMask
= ~mask
;
1228 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1229 GLstencil stencil
[MAX_WIDTH
];
1231 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1232 for (i
= 0; i
< width
; i
++) {
1233 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1235 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1240 GLstencil stencil
[MAX_WIDTH
];
1242 for (i
= 0; i
< width
; i
++) {
1243 stencil
[i
] = ctx
->Stencil
.Clear
;
1245 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1246 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1251 /* clear whole stencil buffer */
1252 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1253 /* must apply mask to the clear */
1254 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1255 const GLstencil invMask
= ~mask
;
1256 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1257 const GLint width
= ctx
->DrawBuffer
->Width
;
1258 const GLint height
= ctx
->DrawBuffer
->Height
;
1259 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1261 for (y
= 0; y
< height
; y
++) {
1262 GLstencil stencil
[MAX_WIDTH
];
1264 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1265 for (i
= 0; i
< width
; i
++) {
1266 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1268 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1272 /* clear whole buffer without masking */
1273 const GLint width
= ctx
->DrawBuffer
->Width
;
1274 const GLint height
= ctx
->DrawBuffer
->Width
;
1275 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1276 GLstencil stencil
[MAX_WIDTH
];
1278 for (i
= 0; i
< width
; i
++) {
1279 stencil
[i
] = ctx
->Stencil
.Clear
;
1281 for (y
= 0; y
< height
; y
++) {
1282 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1291 * Clear the stencil buffer.
1294 _mesa_clear_stencil_buffer( GLcontext
*ctx
)
1296 if (ctx
->Driver
.WriteStencilSpan
) {
1297 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1298 clear_hardware_stencil_buffer(ctx
);
1301 clear_software_stencil_buffer(ctx
);