5f308ab28cb53561654b76b635c5373b9de1b310
1 /* $Id: s_stencil.c,v 1.6 2001/02/23 20:08:29 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 gl_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 gl_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 gl_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 gl_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 if (do_stencil_test(ctx
, n
, stencil
, mask
) == GL_FALSE
) {
925 /* all fragments failed the stencil test, we're done. */
929 MEMCPY(origMask
, mask
, n
* sizeof(GLubyte
));
931 if (ctx
->Depth
.Test
== GL_FALSE
) {
932 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
935 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
937 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
938 GLubyte failmask
[PB_SIZE
];
940 for (i
= 0; i
< n
; i
++) {
941 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
942 failmask
[i
] = origMask
[i
] & (mask
[i
] ^ 1);
944 apply_stencil_op(ctx
, ctx
->Stencil
.ZFailFunc
,
945 n
, stencil
, failmask
);
947 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
948 GLubyte passmask
[PB_SIZE
];
950 for (i
= 0; i
< n
; i
++) {
951 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
952 passmask
[i
] = origMask
[i
] & mask
[i
];
954 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
,
955 n
, stencil
, passmask
);
959 /* Write updated stencil values into hardware stencil buffer */
960 (ctx
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, origMask
);
965 /*** Software stencil buffer ***/
967 if (stencil_test_pixels(ctx
, n
, x
, y
, mask
) == GL_FALSE
) {
968 /* all fragments failed the stencil test, we're done. */
972 if (ctx
->Depth
.Test
==GL_FALSE
) {
973 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
974 ctx
->Stencil
.ZPassFunc
, mask
);
977 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
980 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
982 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
985 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
986 passmask
[i
] = oldmask
[i
] & mask
[i
];
987 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
990 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
991 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
992 ctx
->Stencil
.ZFailFunc
, failmask
);
994 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
995 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
996 ctx
->Stencil
.ZPassFunc
, passmask
);
1000 return GL_TRUE
; /* one or more fragments passed both tests */
1007 * Return a span of stencil values from the stencil buffer.
1008 * Used for glRead/CopyPixels
1009 * Input: n - how many pixels
1010 * x,y - location of first pixel
1011 * Output: stencil - the array of stencil values
1014 _mesa_read_stencil_span( GLcontext
*ctx
,
1015 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
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 (ctx
->Driver
.ReadStencilSpan
) {
1040 (*ctx
->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 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1068 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1069 /* span is completely outside framebuffer */
1070 return; /* undefined values OK */
1079 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1080 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1087 if (ctx
->Driver
.WriteStencilSpan
) {
1088 (*ctx
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, stencil
, NULL
);
1090 else if (ctx
->DrawBuffer
->Stencil
) {
1091 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1092 #if STENCIL_BITS == 8
1093 MEMCPY( s
, stencil
, n
* sizeof(GLstencil
) );
1105 * Allocate a new stencil buffer. If there's an old one it will be
1106 * deallocated first. The new stencil buffer will be uninitialized.
1109 _mesa_alloc_stencil_buffer( GLcontext
*ctx
)
1111 GLuint buffersize
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1113 /* deallocate current stencil buffer if present */
1114 if (ctx
->DrawBuffer
->Stencil
) {
1115 FREE(ctx
->DrawBuffer
->Stencil
);
1116 ctx
->DrawBuffer
->Stencil
= NULL
;
1119 /* allocate new stencil buffer */
1120 ctx
->DrawBuffer
->Stencil
= (GLstencil
*) MALLOC(buffersize
* sizeof(GLstencil
));
1121 if (!ctx
->DrawBuffer
->Stencil
) {
1123 /* _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE ); */
1124 gl_error( ctx
, GL_OUT_OF_MEMORY
, "_mesa_alloc_stencil_buffer" );
1131 * Clear the software (malloc'd) stencil buffer.
1134 clear_software_stencil_buffer( GLcontext
*ctx
)
1136 if (ctx
->Visual
.stencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1137 /* no stencil buffer */
1141 if (ctx
->Scissor
.Enabled
) {
1142 /* clear scissor region only */
1143 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1144 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1145 /* must apply mask to the clear */
1147 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1148 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1149 const GLstencil invMask
= ~mask
;
1150 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1151 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1153 for (i
= 0; i
< width
; i
++) {
1154 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1161 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1162 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1164 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1167 for (i
= 0; i
< width
; i
++)
1168 stencil
[x
] = ctx
->Stencil
.Clear
;
1174 /* clear whole stencil buffer */
1175 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1176 /* must apply mask to the clear */
1177 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1178 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1179 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1180 const GLstencil invMask
= ~mask
;
1181 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1183 for (i
= 0; i
< n
; i
++) {
1184 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1188 /* clear whole buffer without masking */
1189 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1190 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1193 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1196 for (i
= 0; i
< n
; i
++) {
1197 stencil
[i
] = ctx
->Stencil
.Clear
;
1207 * Clear the hardware (in graphics card) stencil buffer.
1208 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1210 * Actually, if there is a hardware stencil buffer it really should have
1211 * been cleared in Driver.Clear()! However, if the hardware does not
1212 * support scissored clears or masked clears (i.e. glStencilMask) then
1213 * we have to use the span-based functions.
1216 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1218 ASSERT(ctx
->Driver
.WriteStencilSpan
);
1219 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1221 if (ctx
->Scissor
.Enabled
) {
1222 /* clear scissor region only */
1223 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1224 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1225 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1226 /* must apply mask to the clear */
1228 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1229 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1230 const GLstencil invMask
= ~mask
;
1231 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1232 GLstencil stencil
[MAX_WIDTH
];
1234 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1235 for (i
= 0; i
< width
; i
++) {
1236 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1238 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1243 GLstencil stencil
[MAX_WIDTH
];
1245 for (i
= 0; i
< width
; i
++) {
1246 stencil
[i
] = ctx
->Stencil
.Clear
;
1248 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1249 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1254 /* clear whole stencil buffer */
1255 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1256 /* must apply mask to the clear */
1257 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1258 const GLstencil invMask
= ~mask
;
1259 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1260 const GLint width
= ctx
->DrawBuffer
->Width
;
1261 const GLint height
= ctx
->DrawBuffer
->Height
;
1262 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1264 for (y
= 0; y
< height
; y
++) {
1265 GLstencil stencil
[MAX_WIDTH
];
1267 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1268 for (i
= 0; i
< width
; i
++) {
1269 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1271 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1275 /* clear whole buffer without masking */
1276 const GLint width
= ctx
->DrawBuffer
->Width
;
1277 const GLint height
= ctx
->DrawBuffer
->Width
;
1278 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1279 GLstencil stencil
[MAX_WIDTH
];
1281 for (i
= 0; i
< width
; i
++) {
1282 stencil
[i
] = ctx
->Stencil
.Clear
;
1284 for (y
= 0; y
< height
; y
++) {
1285 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1294 * Clear the stencil buffer.
1297 _mesa_clear_stencil_buffer( GLcontext
*ctx
)
1299 if (ctx
->Driver
.WriteStencilSpan
) {
1300 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1301 clear_hardware_stencil_buffer(ctx
);
1304 clear_software_stencil_buffer(ctx
);