1 /* $Id: s_stencil.c,v 1.28 2002/10/24 23:57:24 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 * face - 0 or 1 for front or back face operation
69 * stencil - array of stencil values
70 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
71 * Output: stencil - modified values
74 apply_stencil_op( const GLcontext
*ctx
, GLenum oper
, GLuint face
,
75 GLuint n
, GLstencil stencil
[], const GLubyte mask
[] )
77 const GLstencil ref
= ctx
->Stencil
.Ref
[face
];
78 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
[face
];
79 const GLstencil invmask
= (GLstencil
) (~wrtmask
);
97 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
113 GLstencil s
= stencil
[i
];
114 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
123 GLstencil s
= stencil
[i
];
124 if (s
< STENCIL_MAX
) {
125 stencil
[i
] = (GLstencil
) (s
+1);
133 /* VERIFY logic of adding 1 to a write-masked value */
134 GLstencil s
= stencil
[i
];
135 if (s
< STENCIL_MAX
) {
136 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
146 GLstencil s
= stencil
[i
];
148 stencil
[i
] = (GLstencil
) (s
-1);
156 /* VERIFY logic of subtracting 1 to a write-masked value */
157 GLstencil s
= stencil
[i
];
159 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
165 case GL_INCR_WRAP_EXT
:
176 GLstencil s
= stencil
[i
];
177 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
182 case GL_DECR_WRAP_EXT
:
193 GLstencil s
= stencil
[i
];
194 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
203 GLstencil s
= stencil
[i
];
204 stencil
[i
] = (GLstencil
) ~s
;
211 GLstencil s
= stencil
[i
];
212 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
218 _mesa_problem(ctx
, "Bad stencil op in apply_stencil_op");
226 * Apply stencil test to an array of stencil values (before depth buffering).
227 * Input: face - 0 or 1 for front or back-face polygons
228 * n - number of pixels in the array
229 * stencil - array of [n] stencil values
230 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
231 * Output: mask - pixels which fail the stencil test will have their
232 * mask flag set to 0.
233 * stencil - updated stencil values (where the test passed)
234 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
237 do_stencil_test( GLcontext
*ctx
, GLuint face
, GLuint n
, GLstencil stencil
[],
240 GLubyte fail
[MAX_WIDTH
];
241 GLboolean allfail
= GL_FALSE
;
244 const GLuint valueMask
= ctx
->Stencil
.ValueMask
[face
];
246 ASSERT(n
<= MAX_WIDTH
);
249 * Perform stencil test. The results of this operation are stored
250 * in the fail[] array:
251 * IF fail[i] is non-zero THEN
252 * the stencil fail operator is to be applied
254 * the stencil fail operator is not to be applied
257 switch (ctx
->Stencil
.Function
[face
]) {
259 /* never pass; always fail */
272 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
275 s
= (GLstencil
) (stencil
[i
] & valueMask
);
291 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
294 s
= (GLstencil
) (stencil
[i
] & valueMask
);
310 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
313 s
= (GLstencil
) (stencil
[i
] & valueMask
);
329 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
332 s
= (GLstencil
) (stencil
[i
] & valueMask
);
348 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
351 s
= (GLstencil
) (stencil
[i
] & valueMask
);
367 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
370 s
= (GLstencil
) (stencil
[i
] & valueMask
);
392 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_span");
396 if (ctx
->Stencil
.FailFunc
[face
] != GL_KEEP
) {
397 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
[face
], face
, n
, stencil
, fail
);
406 * Apply stencil and depth testing to the span of pixels.
407 * Both software and hardware stencil buffers are acceptable.
408 * Input: n - number of pixels in the span
409 * x, y - location of leftmost pixel in span
410 * z - array [n] of z values
411 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
412 * Output: mask - array [n] of flags (1=stencil and depth test passed)
413 * Return: GL_FALSE - all fragments failed the testing
414 * GL_TRUE - one or more fragments passed the testing
418 stencil_and_ztest_span(GLcontext
*ctx
, struct sw_span
*span
, GLuint face
)
420 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
421 GLstencil stencilRow
[MAX_WIDTH
];
423 const GLuint n
= span
->end
;
424 const GLint x
= span
->x
;
425 const GLint y
= span
->y
;
426 GLubyte
*mask
= span
->array
->mask
;
428 ASSERT((span
->arrayMask
& SPAN_XY
) == 0);
429 ASSERT(ctx
->Stencil
.Enabled
);
430 ASSERT(n
<= MAX_WIDTH
);
432 if (ctx
->Depth
.Test
) {
433 ASSERT(span
->arrayMask
& SPAN_Z
);
437 /* Get initial stencil values */
438 if (swrast
->Driver
.WriteStencilSpan
) {
439 /* Get stencil values from the hardware stencil buffer */
440 ASSERT(swrast
->Driver
.ReadStencilSpan
);
441 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, n
, x
, y
, stencilRow
);
442 stencil
= stencilRow
;
445 /* Get pointer into software stencil buffer */
446 stencil
= STENCIL_ADDRESS(x
, y
);
450 * Apply the stencil test to the fragments.
451 * failMask[i] is 1 if the stencil test failed.
453 if (do_stencil_test( ctx
, face
, n
, stencil
, mask
) == GL_FALSE
) {
454 /* all fragments failed the stencil test, we're done. */
455 span
->writeAll
= GL_FALSE
;
460 * Some fragments passed the stencil test, apply depth test to them
461 * and apply Zpass and Zfail stencil ops.
463 if (ctx
->Depth
.Test
== GL_FALSE
) {
465 * No depth buffer, just apply zpass stencil function to active pixels.
467 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
, n
, stencil
, mask
);
471 * Perform depth buffering, then apply zpass or zfail stencil function.
473 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
476 /* save the current mask bits */
477 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
479 /* apply the depth test */
480 _mesa_depth_test_span(ctx
, span
);
482 /* Set the stencil pass/fail flags according to result of depth testing.
483 * if oldmask[i] == 0 then
484 * Don't touch the stencil value
485 * else if oldmask[i] and newmask[i] then
488 * assert(oldmask[i] && !newmask[i])
493 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
494 passmask
[i
] = oldmask
[i
] & mask
[i
];
495 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
498 /* apply the pass and fail operations */
499 if (ctx
->Stencil
.ZFailFunc
[face
] != GL_KEEP
) {
500 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
[face
], face
,
501 n
, stencil
, failmask
);
503 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
504 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
505 n
, stencil
, passmask
);
510 * Write updated stencil values back into hardware stencil buffer.
512 if (swrast
->Driver
.WriteStencilSpan
) {
513 ASSERT(stencil
== stencilRow
);
514 (swrast
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
517 span
->writeAll
= GL_FALSE
;
519 return GL_TRUE
; /* one or more fragments passed both tests */
526 * Apply the given stencil operator for each pixel in the array whose
528 * \note This is for software stencil buffers only.
529 * Input: n - number of pixels in the span
530 * x, y - array of [n] pixels
531 * operator - the stencil buffer operator
532 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
535 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
536 GLuint n
, const GLint x
[], const GLint y
[],
537 GLenum oper
, GLuint face
, const GLubyte mask
[] )
539 const GLstencil ref
= ctx
->Stencil
.Ref
[face
];
540 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
[face
];
541 const GLstencil invmask
= (GLstencil
) (~wrtmask
);
544 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
554 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
562 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
563 *sptr
= (GLstencil
) (invmask
& *sptr
);
572 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
580 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
581 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
590 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
591 if (*sptr
< STENCIL_MAX
) {
592 *sptr
= (GLstencil
) (*sptr
+ 1);
600 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
601 if (*sptr
< STENCIL_MAX
) {
602 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
612 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
614 *sptr
= (GLstencil
) (*sptr
- 1);
622 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
624 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
630 case GL_INCR_WRAP_EXT
:
634 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
635 *sptr
= (GLstencil
) (*sptr
+ 1);
642 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
643 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
648 case GL_DECR_WRAP_EXT
:
652 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
653 *sptr
= (GLstencil
) (*sptr
- 1);
660 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
661 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
670 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
671 *sptr
= (GLstencil
) (~*sptr
);
678 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
679 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
685 _mesa_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
692 * Apply stencil test to an array of pixels before depth buffering.
694 * \note Used for software stencil buffer only.
695 * Input: n - number of pixels in the span
696 * x, y - array of [n] pixels to stencil
697 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
698 * Output: mask - pixels which fail the stencil test will have their
699 * mask flag set to 0.
700 * \return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
703 stencil_test_pixels( GLcontext
*ctx
, GLuint face
, GLuint n
,
704 const GLint x
[], const GLint y
[], GLubyte mask
[] )
706 GLubyte fail
[MAX_WIDTH
];
709 GLboolean allfail
= GL_FALSE
;
710 const GLuint valueMask
= ctx
->Stencil
.ValueMask
[face
];
712 /* software stencil buffer only! */
713 ASSERT(ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
714 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.ReadStencilSpan
);
715 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
);
718 * Perform stencil test. The results of this operation are stored
719 * in the fail[] array:
720 * IF fail[i] is non-zero THEN
721 * the stencil fail operator is to be applied
723 * the stencil fail operator is not to be applied
727 switch (ctx
->Stencil
.Function
[face
]) {
742 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
745 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
746 s
= (GLstencil
) (*sptr
& valueMask
);
762 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
765 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
766 s
= (GLstencil
) (*sptr
& valueMask
);
782 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
785 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
786 s
= (GLstencil
) (*sptr
& valueMask
);
802 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
805 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
806 s
= (GLstencil
) (*sptr
& valueMask
);
822 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
825 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
826 s
= (GLstencil
) (*sptr
& valueMask
);
842 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
845 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
846 s
= (GLstencil
) (*sptr
& valueMask
);
868 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
872 if (ctx
->Stencil
.FailFunc
[face
] != GL_KEEP
) {
873 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
[face
],
884 * Apply stencil and depth testing to an array of pixels.
885 * This is used both for software and hardware stencil buffers.
887 * The comments in this function are a bit sparse but the code is
888 * almost identical to stencil_and_ztest_span(), which is well
891 * Input: n - number of pixels in the array
892 * x, y - array of [n] pixel positions
893 * z - array [n] of z values
894 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
895 * Output: mask - array [n] of flags (1=stencil and depth test passed)
896 * Return: GL_FALSE - all fragments failed the testing
897 * GL_TRUE - one or more fragments passed the testing
900 stencil_and_ztest_pixels( GLcontext
*ctx
, struct sw_span
*span
, GLuint face
)
902 const GLuint n
= span
->end
;
903 const GLint
*x
= span
->array
->x
;
904 const GLint
*y
= span
->array
->y
;
905 GLubyte
*mask
= span
->array
->mask
;
906 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
908 ASSERT(span
->arrayMask
& SPAN_XY
);
909 ASSERT(ctx
->Stencil
.Enabled
);
910 ASSERT(n
<= MAX_WIDTH
);
912 if (swrast
->Driver
.WriteStencilPixels
) {
913 /*** Hardware stencil buffer ***/
914 GLstencil stencil
[MAX_WIDTH
];
915 GLubyte origMask
[MAX_WIDTH
];
917 ASSERT(!ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
918 ASSERT(swrast
->Driver
.ReadStencilPixels
);
919 (*swrast
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
921 MEMCPY(origMask
, mask
, n
* sizeof(GLubyte
));
923 (void) do_stencil_test(ctx
, face
, n
, stencil
, mask
);
925 if (ctx
->Depth
.Test
== GL_FALSE
) {
926 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
930 _mesa_depth_test_span(ctx
, span
);
932 if (ctx
->Stencil
.ZFailFunc
[face
] != GL_KEEP
) {
933 GLubyte failmask
[MAX_WIDTH
];
935 for (i
= 0; i
< n
; i
++) {
936 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
937 failmask
[i
] = origMask
[i
] & (mask
[i
] ^ 1);
939 apply_stencil_op(ctx
, ctx
->Stencil
.ZFailFunc
[face
], face
,
940 n
, stencil
, failmask
);
942 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
943 GLubyte passmask
[MAX_WIDTH
];
945 for (i
= 0; i
< n
; i
++) {
946 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
947 passmask
[i
] = origMask
[i
] & mask
[i
];
949 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
950 n
, stencil
, passmask
);
954 /* Write updated stencil values into hardware stencil buffer */
955 (swrast
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, origMask
);
960 /*** Software stencil buffer ***/
962 ASSERT(ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
964 if (stencil_test_pixels(ctx
, face
, 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
[face
], face
, mask
);
974 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
977 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
979 _mesa_depth_test_span(ctx
, span
);
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
[face
] != GL_KEEP
) {
988 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
989 ctx
->Stencil
.ZFailFunc
[face
],
992 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
993 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
994 ctx
->Stencil
.ZPassFunc
[face
],
999 return GL_TRUE
; /* one or more fragments passed both tests */
1005 * /return GL_TRUE = one or more fragments passed,
1006 * GL_FALSE = all fragments failed.
1009 _mesa_stencil_and_ztest_span(GLcontext
*ctx
, struct sw_span
*span
)
1011 /* span->facing can only be non-zero if using two-sided stencil */
1012 ASSERT(ctx
->Stencil
.TestTwoSide
|| span
->facing
== 0);
1013 if (span
->arrayMask
& SPAN_XY
)
1014 return stencil_and_ztest_pixels(ctx
, span
, span
->facing
);
1016 return stencil_and_ztest_span(ctx
, span
, span
->facing
);
1021 * Return a span of stencil values from the stencil buffer.
1022 * Used for glRead/CopyPixels
1023 * Input: n - how many pixels
1024 * x,y - location of first pixel
1025 * Output: stencil - the array of stencil values
1028 _mesa_read_stencil_span( GLcontext
*ctx
,
1029 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1031 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1032 const GLint bufWidth
= (GLint
) ctx
->DrawBuffer
->Width
;
1033 const GLint bufHeight
= (GLint
) ctx
->DrawBuffer
->Height
;
1035 if (y
< 0 || y
>= bufHeight
|| x
+ n
<= 0 || x
>= bufWidth
) {
1036 /* span is completely outside framebuffer */
1037 return; /* undefined values OK */
1046 if (x
+ n
> bufWidth
) {
1047 GLint dx
= x
+ n
- bufWidth
;
1056 if (swrast
->Driver
.ReadStencilSpan
) {
1057 (*swrast
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1059 else if (ctx
->DrawBuffer
->Stencil
) {
1060 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1061 #if STENCIL_BITS == 8
1062 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1074 * Write a span of stencil values to the stencil buffer.
1075 * Used for glDraw/CopyPixels
1076 * Input: n - how many pixels
1077 * x, y - location of first pixel
1078 * stencil - the array of stencil values
1081 _mesa_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1082 const GLstencil stencil
[] )
1084 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1085 const GLstencil
*ssrc
= stencil
;
1086 const GLint bufWidth
= (GLint
) ctx
->DrawBuffer
->Width
;
1087 const GLint bufHeight
= (GLint
) ctx
->DrawBuffer
->Height
;
1089 if (y
< 0 || y
>= bufHeight
|| x
+ n
<= 0 || x
>= bufWidth
) {
1090 /* span is completely outside framebuffer */
1091 return; /* undefined values OK */
1100 if (x
+ n
> bufWidth
) {
1101 GLint dx
= x
+ n
- bufWidth
;
1108 if (swrast
->Driver
.WriteStencilSpan
) {
1109 (*swrast
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, ssrc
, NULL
);
1111 else if (ctx
->DrawBuffer
->Stencil
) {
1112 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1113 #if STENCIL_BITS == 8
1114 MEMCPY( s
, ssrc
, n
* sizeof(GLstencil
) );
1126 * Allocate a new stencil buffer. If there's an old one it will be
1127 * deallocated first. The new stencil buffer will be uninitialized.
1130 _mesa_alloc_stencil_buffer( GLframebuffer
*buffer
)
1132 /* deallocate current stencil buffer if present */
1133 if (buffer
->Stencil
) {
1134 MESA_PBUFFER_FREE(buffer
->Stencil
);
1135 buffer
->Stencil
= NULL
;
1138 /* allocate new stencil buffer */
1139 buffer
->Stencil
= (GLstencil
*)
1140 MESA_PBUFFER_ALLOC(buffer
->Width
* buffer
->Height
* sizeof(GLstencil
));
1141 if (!buffer
->Stencil
) {
1143 _mesa_error( NULL
, GL_OUT_OF_MEMORY
, "_mesa_alloc_stencil_buffer" );
1150 * Clear the software (malloc'd) stencil buffer.
1153 clear_software_stencil_buffer( GLcontext
*ctx
)
1155 if (ctx
->Visual
.stencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1156 /* no stencil buffer */
1160 if (ctx
->Scissor
.Enabled
) {
1161 /* clear scissor region only */
1162 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1163 if (ctx
->Stencil
.WriteMask
[0] != STENCIL_MAX
) {
1164 /* must apply mask to the clear */
1166 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1167 const GLstencil mask
= ctx
->Stencil
.WriteMask
[0];
1168 const GLstencil invMask
= ~mask
;
1169 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1170 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1172 for (i
= 0; i
< width
; i
++) {
1173 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1180 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1181 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1183 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1186 for (i
= 0; i
< width
; i
++)
1187 stencil
[x
] = ctx
->Stencil
.Clear
;
1193 /* clear whole stencil buffer */
1194 if (ctx
->Stencil
.WriteMask
[0] != STENCIL_MAX
) {
1195 /* must apply mask to the clear */
1196 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1197 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1198 const GLstencil mask
= ctx
->Stencil
.WriteMask
[0];
1199 const GLstencil invMask
= ~mask
;
1200 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1202 for (i
= 0; i
< n
; i
++) {
1203 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1207 /* clear whole buffer without masking */
1208 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1209 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1212 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1215 for (i
= 0; i
< n
; i
++) {
1216 stencil
[i
] = ctx
->Stencil
.Clear
;
1226 * Clear the hardware (in graphics card) stencil buffer.
1227 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1229 * Actually, if there is a hardware stencil buffer it really should have
1230 * been cleared in Driver.Clear()! However, if the hardware does not
1231 * support scissored clears or masked clears (i.e. glStencilMask) then
1232 * we have to use the span-based functions.
1235 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1237 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1238 ASSERT(swrast
->Driver
.WriteStencilSpan
);
1239 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1241 if (ctx
->Scissor
.Enabled
) {
1242 /* clear scissor region only */
1243 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1244 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1245 if (ctx
->Stencil
.WriteMask
[0] != STENCIL_MAX
) {
1246 /* must apply mask to the clear */
1248 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1249 const GLstencil mask
= ctx
->Stencil
.WriteMask
[0];
1250 const GLstencil invMask
= ~mask
;
1251 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1252 GLstencil stencil
[MAX_WIDTH
];
1254 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1255 for (i
= 0; i
< width
; i
++) {
1256 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1258 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1263 GLstencil stencil
[MAX_WIDTH
];
1265 for (i
= 0; i
< width
; i
++) {
1266 stencil
[i
] = ctx
->Stencil
.Clear
;
1268 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1269 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1274 /* clear whole stencil buffer */
1275 if (ctx
->Stencil
.WriteMask
[0] != STENCIL_MAX
) {
1276 /* must apply mask to the clear */
1277 const GLstencil mask
= ctx
->Stencil
.WriteMask
[0];
1278 const GLstencil invMask
= ~mask
;
1279 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1280 const GLint width
= ctx
->DrawBuffer
->Width
;
1281 const GLint height
= ctx
->DrawBuffer
->Height
;
1282 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1284 for (y
= 0; y
< height
; y
++) {
1285 GLstencil stencil
[MAX_WIDTH
];
1287 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1288 for (i
= 0; i
< width
; i
++) {
1289 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1291 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1295 /* clear whole buffer without masking */
1296 const GLint width
= ctx
->DrawBuffer
->Width
;
1297 const GLint height
= ctx
->DrawBuffer
->Height
;
1298 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1299 GLstencil stencil
[MAX_WIDTH
];
1301 for (i
= 0; i
< width
; i
++) {
1302 stencil
[i
] = ctx
->Stencil
.Clear
;
1304 for (y
= 0; y
< height
; y
++) {
1305 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1314 * Clear the stencil buffer (hardware or software).
1317 _mesa_clear_stencil_buffer( GLcontext
*ctx
)
1319 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1320 if (swrast
->Driver
.WriteStencilSpan
) {
1321 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1322 clear_hardware_stencil_buffer(ctx
);
1325 clear_software_stencil_buffer(ctx
);