3 * Mesa 3-D graphics library
6 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #include "s_context.h"
34 #include "s_stencil.h"
40 IF stencil test fails THEN
41 Apply fail-op to stencil value
42 Don't write the pixel (RGBA,Z)
44 IF doing depth test && depth test fails THEN
45 Apply zfail-op to stencil value
46 Write RGBA and Z to appropriate buffers
48 Apply zpass-op to stencil value
55 * Return the address of a stencil buffer value given the window coords:
57 #define STENCIL_ADDRESS(X,Y) \
58 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
63 * Apply the given stencil operator to the array of stencil values.
64 * Don't touch stencil[i] if mask[i] is zero.
65 * Input: n - size of stencil array
66 * oper - the stencil buffer operator
67 * face - 0 or 1 for front or back face operation
68 * stencil - array of stencil values
69 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
70 * Output: stencil - modified values
73 apply_stencil_op( const GLcontext
*ctx
, GLenum oper
, GLuint face
,
74 GLuint n
, GLstencil stencil
[], const GLubyte mask
[] )
76 const GLstencil ref
= ctx
->Stencil
.Ref
[face
];
77 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
[face
];
78 const GLstencil invmask
= (GLstencil
) (~wrtmask
);
96 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
112 GLstencil s
= stencil
[i
];
113 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
122 GLstencil s
= stencil
[i
];
123 if (s
< STENCIL_MAX
) {
124 stencil
[i
] = (GLstencil
) (s
+1);
132 /* VERIFY logic of adding 1 to a write-masked value */
133 GLstencil s
= stencil
[i
];
134 if (s
< STENCIL_MAX
) {
135 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
145 GLstencil s
= stencil
[i
];
147 stencil
[i
] = (GLstencil
) (s
-1);
155 /* VERIFY logic of subtracting 1 to a write-masked value */
156 GLstencil s
= stencil
[i
];
158 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
164 case GL_INCR_WRAP_EXT
:
175 GLstencil s
= stencil
[i
];
176 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
181 case GL_DECR_WRAP_EXT
:
192 GLstencil s
= stencil
[i
];
193 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
202 GLstencil s
= stencil
[i
];
203 stencil
[i
] = (GLstencil
) ~s
;
210 GLstencil s
= stencil
[i
];
211 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
217 _mesa_problem(ctx
, "Bad stencil op in apply_stencil_op");
225 * Apply stencil test to an array of stencil values (before depth buffering).
226 * Input: face - 0 or 1 for front or back-face polygons
227 * n - number of pixels in the array
228 * stencil - array of [n] stencil values
229 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
230 * Output: mask - pixels which fail the stencil test will have their
231 * mask flag set to 0.
232 * stencil - updated stencil values (where the test passed)
233 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
236 do_stencil_test( GLcontext
*ctx
, GLuint face
, GLuint n
, GLstencil stencil
[],
239 GLubyte fail
[MAX_WIDTH
];
240 GLboolean allfail
= GL_FALSE
;
243 const GLuint valueMask
= ctx
->Stencil
.ValueMask
[face
];
245 ASSERT(n
<= MAX_WIDTH
);
248 * Perform stencil test. The results of this operation are stored
249 * in the fail[] array:
250 * IF fail[i] is non-zero THEN
251 * the stencil fail operator is to be applied
253 * the stencil fail operator is not to be applied
256 switch (ctx
->Stencil
.Function
[face
]) {
258 /* never pass; always fail */
271 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
274 s
= (GLstencil
) (stencil
[i
] & valueMask
);
290 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
293 s
= (GLstencil
) (stencil
[i
] & valueMask
);
309 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
312 s
= (GLstencil
) (stencil
[i
] & valueMask
);
328 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
331 s
= (GLstencil
) (stencil
[i
] & valueMask
);
347 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
350 s
= (GLstencil
) (stencil
[i
] & valueMask
);
366 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
369 s
= (GLstencil
) (stencil
[i
] & valueMask
);
391 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_span");
395 if (ctx
->Stencil
.FailFunc
[face
] != GL_KEEP
) {
396 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
[face
], face
, n
, stencil
, fail
);
405 * Apply stencil and depth testing to the span of pixels.
406 * Both software and hardware stencil buffers are acceptable.
407 * Input: n - number of pixels in the span
408 * x, y - location of leftmost pixel in span
409 * z - array [n] of z values
410 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
411 * Output: mask - array [n] of flags (1=stencil and depth test passed)
412 * Return: GL_FALSE - all fragments failed the testing
413 * GL_TRUE - one or more fragments passed the testing
417 stencil_and_ztest_span(GLcontext
*ctx
, struct sw_span
*span
, GLuint face
)
419 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
420 GLstencil stencilRow
[MAX_WIDTH
];
422 const GLuint n
= span
->end
;
423 const GLint x
= span
->x
;
424 const GLint y
= span
->y
;
425 GLubyte
*mask
= span
->array
->mask
;
427 ASSERT((span
->arrayMask
& SPAN_XY
) == 0);
428 ASSERT(ctx
->Stencil
.Enabled
);
429 ASSERT(n
<= MAX_WIDTH
);
431 if (ctx
->Depth
.Test
) {
432 ASSERT(span
->arrayMask
& SPAN_Z
);
436 /* Get initial stencil values */
437 if (swrast
->Driver
.WriteStencilSpan
) {
438 /* Get stencil values from the hardware stencil buffer */
439 ASSERT(swrast
->Driver
.ReadStencilSpan
);
440 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, n
, x
, y
, stencilRow
);
441 stencil
= stencilRow
;
444 /* Get pointer into software stencil buffer */
445 stencil
= STENCIL_ADDRESS(x
, y
);
449 * Apply the stencil test to the fragments.
450 * failMask[i] is 1 if the stencil test failed.
452 if (do_stencil_test( ctx
, face
, n
, stencil
, mask
) == GL_FALSE
) {
453 /* all fragments failed the stencil test, we're done. */
454 span
->writeAll
= GL_FALSE
;
459 * Some fragments passed the stencil test, apply depth test to them
460 * and apply Zpass and Zfail stencil ops.
462 if (ctx
->Depth
.Test
== GL_FALSE
) {
464 * No depth buffer, just apply zpass stencil function to active pixels.
466 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
, n
, stencil
, mask
);
470 * Perform depth buffering, then apply zpass or zfail stencil function.
472 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
475 /* save the current mask bits */
476 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
478 /* apply the depth test */
479 _swrast_depth_test_span(ctx
, span
);
481 /* Set the stencil pass/fail flags according to result of depth testing.
482 * if oldmask[i] == 0 then
483 * Don't touch the stencil value
484 * else if oldmask[i] and newmask[i] then
487 * assert(oldmask[i] && !newmask[i])
492 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
493 passmask
[i
] = oldmask
[i
] & mask
[i
];
494 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
497 /* apply the pass and fail operations */
498 if (ctx
->Stencil
.ZFailFunc
[face
] != GL_KEEP
) {
499 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
[face
], face
,
500 n
, stencil
, failmask
);
502 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
503 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
504 n
, stencil
, passmask
);
509 * Write updated stencil values back into hardware stencil buffer.
511 if (swrast
->Driver
.WriteStencilSpan
) {
512 ASSERT(stencil
== stencilRow
);
513 (swrast
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
516 span
->writeAll
= GL_FALSE
;
518 return GL_TRUE
; /* one or more fragments passed both tests */
525 * Apply the given stencil operator for each pixel in the array whose
527 * \note This is for software stencil buffers only.
528 * Input: n - number of pixels in the span
529 * x, y - array of [n] pixels
530 * operator - the stencil buffer operator
531 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
534 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
535 GLuint n
, const GLint x
[], const GLint y
[],
536 GLenum oper
, GLuint face
, const GLubyte mask
[] )
538 const GLstencil ref
= ctx
->Stencil
.Ref
[face
];
539 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
[face
];
540 const GLstencil invmask
= (GLstencil
) (~wrtmask
);
543 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
553 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
561 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
562 *sptr
= (GLstencil
) (invmask
& *sptr
);
571 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
579 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
580 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
589 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
590 if (*sptr
< STENCIL_MAX
) {
591 *sptr
= (GLstencil
) (*sptr
+ 1);
599 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
600 if (*sptr
< STENCIL_MAX
) {
601 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
611 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
613 *sptr
= (GLstencil
) (*sptr
- 1);
621 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
623 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
629 case GL_INCR_WRAP_EXT
:
633 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
634 *sptr
= (GLstencil
) (*sptr
+ 1);
641 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
642 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
647 case GL_DECR_WRAP_EXT
:
651 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
652 *sptr
= (GLstencil
) (*sptr
- 1);
659 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
660 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
669 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
670 *sptr
= (GLstencil
) (~*sptr
);
677 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
678 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
684 _mesa_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
691 * Apply stencil test to an array of pixels before depth buffering.
693 * \note Used for software stencil buffer only.
694 * Input: n - number of pixels in the span
695 * x, y - array of [n] pixels to stencil
696 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
697 * Output: mask - pixels which fail the stencil test will have their
698 * mask flag set to 0.
699 * \return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
702 stencil_test_pixels( GLcontext
*ctx
, GLuint face
, GLuint n
,
703 const GLint x
[], const GLint y
[], GLubyte mask
[] )
705 GLubyte fail
[MAX_WIDTH
];
708 GLboolean allfail
= GL_FALSE
;
709 const GLuint valueMask
= ctx
->Stencil
.ValueMask
[face
];
711 /* software stencil buffer only! */
712 ASSERT(ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
713 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.ReadStencilSpan
);
714 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
);
717 * Perform stencil test. The results of this operation are stored
718 * in the fail[] array:
719 * IF fail[i] is non-zero THEN
720 * the stencil fail operator is to be applied
722 * the stencil fail operator is not to be applied
726 switch (ctx
->Stencil
.Function
[face
]) {
741 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
744 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
745 s
= (GLstencil
) (*sptr
& valueMask
);
761 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
764 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
765 s
= (GLstencil
) (*sptr
& valueMask
);
781 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
784 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
785 s
= (GLstencil
) (*sptr
& valueMask
);
801 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
804 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
805 s
= (GLstencil
) (*sptr
& valueMask
);
821 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
824 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
825 s
= (GLstencil
) (*sptr
& valueMask
);
841 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
844 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
845 s
= (GLstencil
) (*sptr
& valueMask
);
867 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
871 if (ctx
->Stencil
.FailFunc
[face
] != GL_KEEP
) {
872 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
[face
],
883 * Apply stencil and depth testing to an array of pixels.
884 * This is used both for software and hardware stencil buffers.
886 * The comments in this function are a bit sparse but the code is
887 * almost identical to stencil_and_ztest_span(), which is well
890 * Input: n - number of pixels in the array
891 * x, y - array of [n] pixel positions
892 * z - array [n] of z values
893 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
894 * Output: mask - array [n] of flags (1=stencil and depth test passed)
895 * Return: GL_FALSE - all fragments failed the testing
896 * GL_TRUE - one or more fragments passed the testing
899 stencil_and_ztest_pixels( GLcontext
*ctx
, struct sw_span
*span
, GLuint face
)
901 const GLuint n
= span
->end
;
902 const GLint
*x
= span
->array
->x
;
903 const GLint
*y
= span
->array
->y
;
904 GLubyte
*mask
= span
->array
->mask
;
905 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
907 ASSERT(span
->arrayMask
& SPAN_XY
);
908 ASSERT(ctx
->Stencil
.Enabled
);
909 ASSERT(n
<= MAX_WIDTH
);
911 if (swrast
->Driver
.WriteStencilPixels
) {
912 /*** Hardware stencil buffer ***/
913 GLstencil stencil
[MAX_WIDTH
];
914 GLubyte origMask
[MAX_WIDTH
];
916 ASSERT(!ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
917 ASSERT(swrast
->Driver
.ReadStencilPixels
);
918 (*swrast
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
920 MEMCPY(origMask
, mask
, n
* sizeof(GLubyte
));
922 (void) do_stencil_test(ctx
, face
, n
, stencil
, mask
);
924 if (ctx
->Depth
.Test
== GL_FALSE
) {
925 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
929 _swrast_depth_test_span(ctx
, span
);
931 if (ctx
->Stencil
.ZFailFunc
[face
] != GL_KEEP
) {
932 GLubyte failmask
[MAX_WIDTH
];
934 for (i
= 0; i
< n
; i
++) {
935 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
936 failmask
[i
] = origMask
[i
] & (mask
[i
] ^ 1);
938 apply_stencil_op(ctx
, ctx
->Stencil
.ZFailFunc
[face
], face
,
939 n
, stencil
, failmask
);
941 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
942 GLubyte passmask
[MAX_WIDTH
];
944 for (i
= 0; i
< n
; i
++) {
945 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
946 passmask
[i
] = origMask
[i
] & mask
[i
];
948 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
949 n
, stencil
, passmask
);
953 /* Write updated stencil values into hardware stencil buffer */
954 (swrast
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, origMask
);
959 /*** Software stencil buffer ***/
961 ASSERT(ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
963 if (stencil_test_pixels(ctx
, face
, n
, x
, y
, mask
) == GL_FALSE
) {
964 /* all fragments failed the stencil test, we're done. */
968 if (ctx
->Depth
.Test
==GL_FALSE
) {
969 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
970 ctx
->Stencil
.ZPassFunc
[face
], face
, mask
);
973 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
976 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
978 _swrast_depth_test_span(ctx
, span
);
981 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
982 passmask
[i
] = oldmask
[i
] & mask
[i
];
983 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
986 if (ctx
->Stencil
.ZFailFunc
[face
] != GL_KEEP
) {
987 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
988 ctx
->Stencil
.ZFailFunc
[face
],
991 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
992 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
993 ctx
->Stencil
.ZPassFunc
[face
],
998 return GL_TRUE
; /* one or more fragments passed both tests */
1004 * /return GL_TRUE = one or more fragments passed,
1005 * GL_FALSE = all fragments failed.
1008 _swrast_stencil_and_ztest_span(GLcontext
*ctx
, struct sw_span
*span
)
1010 /* span->facing can only be non-zero if using two-sided stencil */
1011 ASSERT(ctx
->Stencil
.TestTwoSide
|| span
->facing
== 0);
1012 if (span
->arrayMask
& SPAN_XY
)
1013 return stencil_and_ztest_pixels(ctx
, span
, span
->facing
);
1015 return stencil_and_ztest_span(ctx
, span
, span
->facing
);
1020 * Return a span of stencil values from the stencil buffer.
1021 * Used for glRead/CopyPixels
1022 * Input: n - how many pixels
1023 * x,y - location of first pixel
1024 * Output: stencil - the array of stencil values
1027 _swrast_read_stencil_span( GLcontext
*ctx
,
1028 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1030 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1031 const GLint bufWidth
= (GLint
) ctx
->DrawBuffer
->Width
;
1032 const GLint bufHeight
= (GLint
) ctx
->DrawBuffer
->Height
;
1034 if (y
< 0 || y
>= bufHeight
|| x
+ n
<= 0 || x
>= bufWidth
) {
1035 /* span is completely outside framebuffer */
1036 return; /* undefined values OK */
1045 if (x
+ n
> bufWidth
) {
1046 GLint dx
= x
+ n
- bufWidth
;
1055 if (swrast
->Driver
.ReadStencilSpan
) {
1056 (*swrast
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1058 else if (ctx
->DrawBuffer
->Stencil
) {
1059 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1060 #if STENCIL_BITS == 8
1061 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1073 * Write a span of stencil values to the stencil buffer.
1074 * Used for glDraw/CopyPixels
1075 * Input: n - how many pixels
1076 * x, y - location of first pixel
1077 * stencil - the array of stencil values
1080 _swrast_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1081 const GLstencil stencil
[] )
1083 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1084 const GLstencil
*ssrc
= stencil
;
1085 const GLint bufWidth
= (GLint
) ctx
->DrawBuffer
->Width
;
1086 const GLint bufHeight
= (GLint
) ctx
->DrawBuffer
->Height
;
1088 if (y
< 0 || y
>= bufHeight
|| x
+ n
<= 0 || x
>= bufWidth
) {
1089 /* span is completely outside framebuffer */
1090 return; /* undefined values OK */
1099 if (x
+ n
> bufWidth
) {
1100 GLint dx
= x
+ n
- bufWidth
;
1107 if (swrast
->Driver
.WriteStencilSpan
) {
1108 (*swrast
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, ssrc
, NULL
);
1110 else if (ctx
->DrawBuffer
->Stencil
) {
1111 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1112 #if STENCIL_BITS == 8
1113 MEMCPY( s
, ssrc
, n
* sizeof(GLstencil
) );
1125 * Allocate a new stencil buffer. If there's an old one it will be
1126 * deallocated first. The new stencil buffer will be uninitialized.
1129 _swrast_alloc_stencil_buffer( GLframebuffer
*buffer
)
1131 /* deallocate current stencil buffer if present */
1132 if (buffer
->Stencil
) {
1133 MESA_PBUFFER_FREE(buffer
->Stencil
);
1134 buffer
->Stencil
= NULL
;
1137 /* allocate new stencil buffer */
1138 buffer
->Stencil
= (GLstencil
*)
1139 MESA_PBUFFER_ALLOC(buffer
->Width
* buffer
->Height
* sizeof(GLstencil
));
1140 if (!buffer
->Stencil
) {
1142 _mesa_error( NULL
, GL_OUT_OF_MEMORY
, "_swrast_alloc_stencil_buffer" );
1149 * Clear the software (malloc'd) stencil buffer.
1152 clear_software_stencil_buffer( GLcontext
*ctx
)
1154 if (ctx
->Visual
.stencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1155 /* no stencil buffer */
1159 if (ctx
->Scissor
.Enabled
) {
1160 /* clear scissor region only */
1161 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1162 if (ctx
->Stencil
.WriteMask
[0] != STENCIL_MAX
) {
1163 /* must apply mask to the clear */
1165 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1166 const GLstencil mask
= ctx
->Stencil
.WriteMask
[0];
1167 const GLstencil invMask
= ~mask
;
1168 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1169 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1171 for (i
= 0; i
< width
; i
++) {
1172 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1179 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1180 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1182 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1185 for (i
= 0; i
< width
; i
++)
1186 stencil
[x
] = ctx
->Stencil
.Clear
;
1192 /* clear whole stencil buffer */
1193 if (ctx
->Stencil
.WriteMask
[0] != STENCIL_MAX
) {
1194 /* must apply mask to the clear */
1195 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1196 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1197 const GLstencil mask
= ctx
->Stencil
.WriteMask
[0];
1198 const GLstencil invMask
= ~mask
;
1199 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1201 for (i
= 0; i
< n
; i
++) {
1202 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1206 /* clear whole buffer without masking */
1207 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1208 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1211 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1214 for (i
= 0; i
< n
; i
++) {
1215 stencil
[i
] = ctx
->Stencil
.Clear
;
1225 * Clear the hardware (in graphics card) stencil buffer.
1226 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1228 * Actually, if there is a hardware stencil buffer it really should have
1229 * been cleared in Driver.Clear()! However, if the hardware does not
1230 * support scissored clears or masked clears (i.e. glStencilMask) then
1231 * we have to use the span-based functions.
1234 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1236 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1237 ASSERT(swrast
->Driver
.WriteStencilSpan
);
1238 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1240 if (ctx
->Scissor
.Enabled
) {
1241 /* clear scissor region only */
1242 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1243 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1244 if (ctx
->Stencil
.WriteMask
[0] != STENCIL_MAX
) {
1245 /* must apply mask to the clear */
1247 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1248 const GLstencil mask
= ctx
->Stencil
.WriteMask
[0];
1249 const GLstencil invMask
= ~mask
;
1250 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1251 GLstencil stencil
[MAX_WIDTH
];
1253 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1254 for (i
= 0; i
< width
; i
++) {
1255 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1257 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1262 GLstencil stencil
[MAX_WIDTH
];
1264 for (i
= 0; i
< width
; i
++) {
1265 stencil
[i
] = ctx
->Stencil
.Clear
;
1267 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1268 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1273 /* clear whole stencil buffer */
1274 if (ctx
->Stencil
.WriteMask
[0] != STENCIL_MAX
) {
1275 /* must apply mask to the clear */
1276 const GLstencil mask
= ctx
->Stencil
.WriteMask
[0];
1277 const GLstencil invMask
= ~mask
;
1278 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1279 const GLint width
= ctx
->DrawBuffer
->Width
;
1280 const GLint height
= ctx
->DrawBuffer
->Height
;
1281 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1283 for (y
= 0; y
< height
; y
++) {
1284 GLstencil stencil
[MAX_WIDTH
];
1286 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1287 for (i
= 0; i
< width
; i
++) {
1288 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1290 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1294 /* clear whole buffer without masking */
1295 const GLint width
= ctx
->DrawBuffer
->Width
;
1296 const GLint height
= ctx
->DrawBuffer
->Height
;
1297 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1298 GLstencil stencil
[MAX_WIDTH
];
1300 for (i
= 0; i
< width
; i
++) {
1301 stencil
[i
] = ctx
->Stencil
.Clear
;
1303 for (y
= 0; y
< height
; y
++) {
1304 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1313 * Clear the stencil buffer (hardware or software).
1316 _swrast_clear_stencil_buffer( GLcontext
*ctx
)
1318 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1319 if (swrast
->Driver
.WriteStencilSpan
) {
1320 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1321 clear_hardware_stencil_buffer(ctx
);
1324 clear_software_stencil_buffer(ctx
);