2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/imports.h"
29 #include "main/format_unpack.h"
31 #include "s_context.h"
33 #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 * Apply the given stencil operator to the array of stencil values.
56 * Don't touch stencil[i] if mask[i] is zero.
57 * Input: n - size of stencil array
58 * oper - the stencil buffer operator
59 * face - 0 or 1 for front or back face operation
60 * stencil - array of stencil values
61 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
62 * Output: stencil - modified values
65 apply_stencil_op( const struct gl_context
*ctx
, GLenum oper
, GLuint face
,
66 GLuint n
, GLubyte stencil
[], const GLubyte mask
[] )
68 const GLubyte ref
= ctx
->Stencil
.Ref
[face
];
69 const GLubyte wrtmask
= ctx
->Stencil
.WriteMask
[face
];
70 const GLubyte invmask
= (GLubyte
) (~wrtmask
);
71 const GLubyte stencilMax
= (1 << ctx
->DrawBuffer
->Visual
.stencilBits
) - 1;
89 stencil
[i
] = (GLubyte
) (stencil
[i
] & invmask
);
105 GLubyte s
= stencil
[i
];
106 stencil
[i
] = (GLubyte
) ((invmask
& s
) | (wrtmask
& ref
));
115 GLubyte s
= stencil
[i
];
116 if (s
< stencilMax
) {
117 stencil
[i
] = (GLubyte
) (s
+1);
125 /* VERIFY logic of adding 1 to a write-masked value */
126 GLubyte s
= stencil
[i
];
127 if (s
< stencilMax
) {
128 stencil
[i
] = (GLubyte
) ((invmask
& s
) | (wrtmask
& (s
+1)));
138 GLubyte s
= stencil
[i
];
140 stencil
[i
] = (GLubyte
) (s
-1);
148 /* VERIFY logic of subtracting 1 to a write-masked value */
149 GLubyte s
= stencil
[i
];
151 stencil
[i
] = (GLubyte
) ((invmask
& s
) | (wrtmask
& (s
-1)));
157 case GL_INCR_WRAP_EXT
:
168 GLubyte s
= stencil
[i
];
169 stencil
[i
] = (GLubyte
) ((invmask
& s
) | (wrtmask
& (s
+1)));
174 case GL_DECR_WRAP_EXT
:
185 GLubyte s
= stencil
[i
];
186 stencil
[i
] = (GLubyte
) ((invmask
& s
) | (wrtmask
& (s
-1)));
195 GLubyte s
= stencil
[i
];
196 stencil
[i
] = (GLubyte
) ~s
;
203 GLubyte s
= stencil
[i
];
204 stencil
[i
] = (GLubyte
) ((invmask
& s
) | (wrtmask
& ~s
));
210 _mesa_problem(ctx
, "Bad stencil op in apply_stencil_op");
218 * Apply stencil test to an array of stencil values (before depth buffering).
219 * Input: face - 0 or 1 for front or back-face polygons
220 * n - number of pixels in the array
221 * stencil - array of [n] stencil values
222 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
223 * Output: mask - pixels which fail the stencil test will have their
224 * mask flag set to 0.
225 * stencil - updated stencil values (where the test passed)
226 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
229 do_stencil_test( struct gl_context
*ctx
, GLuint face
, GLuint n
, GLubyte stencil
[],
232 GLubyte fail
[MAX_WIDTH
];
233 GLboolean allfail
= GL_FALSE
;
235 const GLuint valueMask
= ctx
->Stencil
.ValueMask
[face
];
236 const GLubyte r
= (GLubyte
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
239 ASSERT(n
<= MAX_WIDTH
);
242 * Perform stencil test. The results of this operation are stored
243 * in the fail[] array:
244 * IF fail[i] is non-zero THEN
245 * the stencil fail operator is to be applied
247 * the stencil fail operator is not to be applied
250 switch (ctx
->Stencil
.Function
[face
]) {
252 /* never pass; always fail */
267 s
= (GLubyte
) (stencil
[i
] & valueMask
);
285 s
= (GLubyte
) (stencil
[i
] & valueMask
);
303 s
= (GLubyte
) (stencil
[i
] & valueMask
);
321 s
= (GLubyte
) (stencil
[i
] & valueMask
);
339 s
= (GLubyte
) (stencil
[i
] & valueMask
);
357 s
= (GLubyte
) (stencil
[i
] & valueMask
);
379 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_span");
383 if (ctx
->Stencil
.FailFunc
[face
] != GL_KEEP
) {
384 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
[face
], face
, n
, stencil
, fail
);
392 * Compute the zpass/zfail masks by comparing the pre- and post-depth test
396 compute_pass_fail_masks(GLuint n
, const GLubyte origMask
[],
397 const GLubyte newMask
[],
398 GLubyte passMask
[], GLubyte failMask
[])
401 for (i
= 0; i
< n
; i
++) {
402 ASSERT(newMask
[i
] == 0 || newMask
[i
] == 1);
403 passMask
[i
] = origMask
[i
] & newMask
[i
];
404 failMask
[i
] = origMask
[i
] & (newMask
[i
] ^ 1);
410 * Apply stencil and depth testing to the span of pixels.
411 * Both software and hardware stencil buffers are acceptable.
412 * Input: n - number of pixels in the span
413 * x, y - location of leftmost pixel in span
414 * z - array [n] of z values
415 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
416 * Output: mask - array [n] of flags (1=stencil and depth test passed)
417 * Return: GL_FALSE - all fragments failed the testing
418 * GL_TRUE - one or more fragments passed the testing
422 stencil_and_ztest_span(struct gl_context
*ctx
, SWspan
*span
, GLuint face
)
424 struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
425 struct gl_renderbuffer
*rb
= fb
->_StencilBuffer
;
426 GLubyte stencilRow
[MAX_WIDTH
];
428 const GLuint n
= span
->end
;
429 const GLint x
= span
->x
;
430 const GLint y
= span
->y
;
431 GLubyte
*mask
= span
->array
->mask
;
433 ASSERT((span
->arrayMask
& SPAN_XY
) == 0);
434 ASSERT(ctx
->Stencil
.Enabled
);
435 ASSERT(n
<= MAX_WIDTH
);
437 if (ctx
->Depth
.Test
) {
438 ASSERT(span
->arrayMask
& SPAN_Z
);
442 stencil
= (GLubyte
*) rb
->GetPointer(ctx
, rb
, x
, y
);
444 rb
->GetRow(ctx
, rb
, n
, x
, y
, stencilRow
);
445 stencil
= stencilRow
;
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
;
455 if (!rb
->GetPointer(ctx
, rb
, 0, 0)) {
456 /* put updated stencil values into buffer */
457 rb
->PutRow(ctx
, rb
, n
, x
, y
, stencil
, NULL
);
463 * Some fragments passed the stencil test, apply depth test to them
464 * and apply Zpass and Zfail stencil ops.
466 if (ctx
->Depth
.Test
== GL_FALSE
||
467 ctx
->DrawBuffer
->_DepthBuffer
== NULL
) {
469 * No depth buffer, just apply zpass stencil function to active pixels.
471 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
, n
, stencil
, mask
);
475 * Perform depth buffering, then apply zpass or zfail stencil function.
477 GLubyte passMask
[MAX_WIDTH
], failMask
[MAX_WIDTH
], origMask
[MAX_WIDTH
];
479 /* save the current mask bits */
480 memcpy(origMask
, mask
, n
* sizeof(GLubyte
));
482 /* apply the depth test */
483 _swrast_depth_test_span(ctx
, span
);
485 compute_pass_fail_masks(n
, origMask
, mask
, passMask
, failMask
);
487 /* apply the pass and fail operations */
488 if (ctx
->Stencil
.ZFailFunc
[face
] != GL_KEEP
) {
489 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
[face
], face
,
490 n
, stencil
, failMask
);
492 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
493 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
494 n
, stencil
, passMask
);
499 * Write updated stencil values back into hardware stencil buffer.
501 if (!rb
->GetPointer(ctx
, rb
, 0, 0)) {
502 rb
->PutRow(ctx
, rb
, n
, x
, y
, stencil
, NULL
);
505 span
->writeAll
= GL_FALSE
;
507 return GL_TRUE
; /* one or more fragments passed both tests */
513 * Return the address of a stencil buffer value given the window coords:
515 #define STENCIL_ADDRESS(X, Y) (stencilStart + (Y) * stride + (X))
520 * Apply the given stencil operator for each pixel in the array whose
522 * \note This is for software stencil buffers only.
523 * Input: n - number of pixels in the span
524 * x, y - array of [n] pixels
525 * operator - the stencil buffer operator
526 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
529 apply_stencil_op_to_pixels( struct gl_context
*ctx
,
530 GLuint n
, const GLint x
[], const GLint y
[],
531 GLenum oper
, GLuint face
, const GLubyte mask
[] )
533 struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
534 struct gl_renderbuffer
*rb
= fb
->_StencilBuffer
;
535 const GLubyte stencilMax
= (1 << fb
->Visual
.stencilBits
) - 1;
536 const GLubyte ref
= ctx
->Stencil
.Ref
[face
];
537 const GLubyte wrtmask
= ctx
->Stencil
.WriteMask
[face
];
538 const GLubyte invmask
= (GLubyte
) (~wrtmask
);
540 GLubyte
*stencilStart
= (GLubyte
*) rb
->Data
;
541 const GLuint stride
= rb
->Width
;
543 ASSERT(rb
->GetPointer(ctx
, rb
, 0, 0));
553 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
561 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
562 *sptr
= (GLubyte
) (invmask
& *sptr
);
571 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
579 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
580 *sptr
= (GLubyte
) ((invmask
& *sptr
) | (wrtmask
& ref
));
589 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
590 if (*sptr
< stencilMax
) {
591 *sptr
= (GLubyte
) (*sptr
+ 1);
599 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
600 if (*sptr
< stencilMax
) {
601 *sptr
= (GLubyte
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
611 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
613 *sptr
= (GLubyte
) (*sptr
- 1);
621 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
623 *sptr
= (GLubyte
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
629 case GL_INCR_WRAP_EXT
:
633 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
634 *sptr
= (GLubyte
) (*sptr
+ 1);
641 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
642 *sptr
= (GLubyte
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
647 case GL_DECR_WRAP_EXT
:
651 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
652 *sptr
= (GLubyte
) (*sptr
- 1);
659 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
660 *sptr
= (GLubyte
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
669 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
670 *sptr
= (GLubyte
) (~*sptr
);
677 GLubyte
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
678 *sptr
= (GLubyte
) ((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( struct gl_context
*ctx
, GLuint face
, GLuint n
,
703 const GLint x
[], const GLint y
[], GLubyte mask
[] )
705 const struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
706 struct gl_renderbuffer
*rb
= fb
->_StencilBuffer
;
707 GLubyte fail
[MAX_WIDTH
];
710 GLboolean allfail
= GL_FALSE
;
711 const GLuint valueMask
= ctx
->Stencil
.ValueMask
[face
];
712 const GLubyte
*stencilStart
= (GLubyte
*) rb
->Data
;
713 const GLuint stride
= rb
->Width
;
715 ASSERT(rb
->GetPointer(ctx
, rb
, 0, 0));
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
= (GLubyte
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
745 const GLubyte
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
746 s
= (GLubyte
) (*sptr
& valueMask
);
762 r
= (GLubyte
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
765 const GLubyte
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
766 s
= (GLubyte
) (*sptr
& valueMask
);
782 r
= (GLubyte
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
785 const GLubyte
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
786 s
= (GLubyte
) (*sptr
& valueMask
);
802 r
= (GLubyte
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
805 const GLubyte
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
806 s
= (GLubyte
) (*sptr
& valueMask
);
822 r
= (GLubyte
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
825 const GLubyte
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
826 s
= (GLubyte
) (*sptr
& valueMask
);
842 r
= (GLubyte
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
845 const GLubyte
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
846 s
= (GLubyte
) (*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
],
883 get_s8_values(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
,
884 GLuint count
, const GLint x
[], const GLint y
[],
887 const GLint w
= rb
->Width
, h
= rb
->Height
;
888 const GLubyte
*map
= (const GLubyte
*) rb
->Data
;
891 if (rb
->Format
== MESA_FORMAT_S8
) {
892 const GLuint rowStride
= rb
->RowStride
;
893 for (i
= 0; i
< count
; i
++) {
894 if (x
[i
] >= 0 && y
[i
] >= 0 && x
[i
] < w
&& y
[i
] < h
) {
895 stencil
[i
] = *(map
+ y
[i
] * rowStride
+ x
[i
]);
900 const GLuint bpp
= _mesa_get_format_bytes(rb
->Format
);
901 const GLuint rowStride
= rb
->RowStride
* bpp
;
902 for (i
= 0; i
< count
; i
++) {
903 if (x
[i
] >= 0 && y
[i
] >= 0 && x
[i
] < w
&& y
[i
] < h
) {
904 const GLubyte
*src
= map
+ y
[i
] * rowStride
+ x
[i
] * bpp
;
905 _mesa_unpack_ubyte_stencil_row(rb
->Format
, 1, src
, &stencil
[i
]);
913 * Apply stencil and depth testing to an array of pixels.
914 * This is used both for software and hardware stencil buffers.
916 * The comments in this function are a bit sparse but the code is
917 * almost identical to stencil_and_ztest_span(), which is well
920 * Input: n - number of pixels in the array
921 * x, y - array of [n] pixel positions
922 * z - array [n] of z values
923 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
924 * Output: mask - array [n] of flags (1=stencil and depth test passed)
925 * Return: GL_FALSE - all fragments failed the testing
926 * GL_TRUE - one or more fragments passed the testing
929 stencil_and_ztest_pixels( struct gl_context
*ctx
, SWspan
*span
, GLuint face
)
931 GLubyte passMask
[MAX_WIDTH
], failMask
[MAX_WIDTH
], origMask
[MAX_WIDTH
];
932 struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
933 struct gl_renderbuffer
*rb
= fb
->_StencilBuffer
;
934 const GLuint n
= span
->end
;
935 const GLint
*x
= span
->array
->x
;
936 const GLint
*y
= span
->array
->y
;
937 GLubyte
*mask
= span
->array
->mask
;
939 ASSERT(span
->arrayMask
& SPAN_XY
);
940 ASSERT(ctx
->Stencil
.Enabled
);
941 ASSERT(n
<= MAX_WIDTH
);
943 if (!rb
->GetPointer(ctx
, rb
, 0, 0)) {
944 /* No direct access */
945 GLubyte stencil
[MAX_WIDTH
];
947 ASSERT(rb
->DataType
== GL_UNSIGNED_BYTE
);
948 get_s8_values(ctx
, rb
, n
, x
, y
, stencil
);
950 memcpy(origMask
, mask
, n
* sizeof(GLubyte
));
952 (void) do_stencil_test(ctx
, face
, n
, stencil
, mask
);
954 if (ctx
->Depth
.Test
== GL_FALSE
) {
955 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
959 GLubyte tmpMask
[MAX_WIDTH
];
960 memcpy(tmpMask
, mask
, n
* sizeof(GLubyte
));
962 _swrast_depth_test_span(ctx
, span
);
964 compute_pass_fail_masks(n
, tmpMask
, mask
, passMask
, failMask
);
966 if (ctx
->Stencil
.ZFailFunc
[face
] != GL_KEEP
) {
967 apply_stencil_op(ctx
, ctx
->Stencil
.ZFailFunc
[face
], face
,
968 n
, stencil
, failMask
);
970 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
971 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
972 n
, stencil
, passMask
);
976 /* Write updated stencil values into hardware stencil buffer */
977 rb
->PutValues(ctx
, rb
, n
, x
, y
, stencil
, origMask
);
982 /* Direct access to stencil buffer */
984 if (stencil_test_pixels(ctx
, face
, n
, x
, y
, mask
) == GL_FALSE
) {
985 /* all fragments failed the stencil test, we're done. */
989 if (ctx
->Depth
.Test
==GL_FALSE
) {
990 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
991 ctx
->Stencil
.ZPassFunc
[face
], face
, mask
);
994 memcpy(origMask
, mask
, n
* sizeof(GLubyte
));
996 _swrast_depth_test_span(ctx
, span
);
998 compute_pass_fail_masks(n
, origMask
, mask
, passMask
, failMask
);
1000 if (ctx
->Stencil
.ZFailFunc
[face
] != GL_KEEP
) {
1001 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
1002 ctx
->Stencil
.ZFailFunc
[face
],
1005 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
1006 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
1007 ctx
->Stencil
.ZPassFunc
[face
],
1012 return GL_TRUE
; /* one or more fragments passed both tests */
1018 * /return GL_TRUE = one or more fragments passed,
1019 * GL_FALSE = all fragments failed.
1022 _swrast_stencil_and_ztest_span(struct gl_context
*ctx
, SWspan
*span
)
1024 const GLuint face
= (span
->facing
== 0) ? 0 : ctx
->Stencil
._BackFace
;
1026 if (span
->arrayMask
& SPAN_XY
)
1027 return stencil_and_ztest_pixels(ctx
, span
, face
);
1029 return stencil_and_ztest_span(ctx
, span
, face
);
1035 clip_span(GLuint bufferWidth
, GLuint bufferHeight
,
1036 GLint x
, GLint y
, GLuint
*count
)
1039 GLuint skipPixels
= 0;
1041 if (y
< 0 || y
>= bufferHeight
|| x
+ n
<= 0 || x
>= bufferWidth
) {
1042 /* totally out of bounds */
1053 if (x
+ n
> bufferWidth
) {
1054 GLint dx
= x
+ n
- bufferWidth
;
1067 * Return a span of stencil values from the stencil buffer.
1068 * Used for glRead/CopyPixels
1069 * Input: n - how many pixels
1070 * x,y - location of first pixel
1071 * Output: stencil - the array of stencil values
1074 _swrast_read_stencil_span(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
,
1075 GLint n
, GLint x
, GLint y
, GLubyte stencil
[])
1079 if (y
< 0 || y
>= (GLint
) rb
->Height
||
1080 x
+ n
<= 0 || x
>= (GLint
) rb
->Width
) {
1081 /* span is completely outside framebuffer */
1082 return; /* undefined values OK */
1091 if (x
+ n
> (GLint
) rb
->Width
) {
1092 GLint dx
= x
+ n
- rb
->Width
;
1099 src
= (GLubyte
*) rb
->Data
+ y
* rb
->RowStride
+x
;
1100 _mesa_unpack_ubyte_stencil_row(rb
->Format
, n
, src
, stencil
);
1106 * Write a span of stencil values to the stencil buffer. This function
1107 * applies the stencil write mask when needed.
1108 * Used for glDraw/CopyPixels
1109 * Input: n - how many pixels
1110 * x, y - location of first pixel
1111 * stencil - the array of stencil values
1114 _swrast_write_stencil_span(struct gl_context
*ctx
, GLint n
, GLint x
, GLint y
,
1115 const GLubyte stencil
[] )
1117 struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
1118 struct gl_renderbuffer
*rb
= fb
->_StencilBuffer
;
1119 const GLuint stencilMax
= (1 << fb
->Visual
.stencilBits
) - 1;
1120 const GLuint stencilMask
= ctx
->Stencil
.WriteMask
[0];
1122 if (y
< 0 || y
>= (GLint
) rb
->Height
||
1123 x
+ n
<= 0 || x
>= (GLint
) rb
->Width
) {
1124 /* span is completely outside framebuffer */
1125 return; /* undefined values OK */
1133 if (x
+ n
> (GLint
) rb
->Width
) {
1134 GLint dx
= x
+ n
- rb
->Width
;
1141 if ((stencilMask
& stencilMax
) != stencilMax
) {
1142 /* need to apply writemask */
1143 GLubyte destVals
[MAX_WIDTH
], newVals
[MAX_WIDTH
];
1145 rb
->GetRow(ctx
, rb
, n
, x
, y
, destVals
);
1146 for (i
= 0; i
< n
; i
++) {
1148 = (stencil
[i
] & stencilMask
) | (destVals
[i
] & ~stencilMask
);
1150 rb
->PutRow(ctx
, rb
, n
, x
, y
, newVals
, NULL
);
1153 rb
->PutRow(ctx
, rb
, n
, x
, y
, stencil
, NULL
);
1160 * Clear the stencil buffer. If the buffer is a combined
1161 * depth+stencil buffer, only the stencil bits will be touched.
1164 _swrast_clear_stencil_buffer(struct gl_context
*ctx
)
1166 struct gl_renderbuffer
*rb
=
1167 ctx
->DrawBuffer
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
1168 const GLubyte stencilBits
= ctx
->DrawBuffer
->Visual
.stencilBits
;
1169 const GLuint writeMask
= ctx
->Stencil
.WriteMask
[0];
1170 const GLuint stencilMax
= (1 << stencilBits
) - 1;
1171 GLint x
, y
, width
, height
;
1173 GLint rowStride
, i
, j
;
1176 if (!rb
|| writeMask
== 0)
1179 /* compute region to clear */
1180 x
= ctx
->DrawBuffer
->_Xmin
;
1181 y
= ctx
->DrawBuffer
->_Ymin
;
1182 width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1183 height
= ctx
->DrawBuffer
->_Ymax
- ctx
->DrawBuffer
->_Ymin
;
1185 mapMode
= GL_MAP_WRITE_BIT
;
1186 if ((writeMask
& stencilMax
) != stencilMax
) {
1187 /* need to mask stencil values */
1188 mapMode
|= GL_MAP_READ_BIT
;
1190 else if (_mesa_get_format_bits(rb
->Format
, GL_DEPTH_BITS
) > 0) {
1191 /* combined depth+stencil, need to mask Z values */
1192 mapMode
|= GL_MAP_READ_BIT
;
1195 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
,
1196 mapMode
, &map
, &rowStride
);
1198 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glClear(stencil)");
1202 switch (rb
->Format
) {
1203 case MESA_FORMAT_S8
:
1205 GLubyte clear
= ctx
->Stencil
.Clear
& writeMask
& 0xff;
1206 GLubyte mask
= (~writeMask
) & 0xff;
1209 for (i
= 0; i
< height
; i
++) {
1211 for (j
= 0; j
< width
; j
++) {
1212 row
[j
] = (row
[j
] & mask
) | clear
;
1217 else if (rowStride
== width
) {
1218 /* clear whole buffer */
1219 memset(map
, clear
, width
* height
);
1222 /* clear scissored */
1223 for (i
= 0; i
< height
; i
++) {
1224 memset(map
, clear
, width
);
1230 case MESA_FORMAT_S8_Z24
:
1232 GLuint clear
= (ctx
->Stencil
.Clear
& writeMask
& 0xff) << 24;
1233 GLuint mask
= (((~writeMask
) & 0xff) << 24) | 0xffffff;
1234 for (i
= 0; i
< height
; i
++) {
1235 GLuint
*row
= (GLuint
*) map
;
1236 for (j
= 0; j
< width
; j
++) {
1237 row
[j
] = (row
[j
] & mask
) | clear
;
1243 case MESA_FORMAT_Z24_S8
:
1245 GLuint clear
= ctx
->Stencil
.Clear
& writeMask
& 0xff;
1246 GLuint mask
= 0xffffff00 | ((~writeMask
) & 0xff);
1247 for (i
= 0; i
< height
; i
++) {
1248 GLuint
*row
= (GLuint
*) map
;
1249 for (j
= 0; j
< width
; j
++) {
1250 row
[j
] = (row
[j
] & mask
) | clear
;
1257 _mesa_problem(ctx
, "Unexpected stencil buffer format %s"
1258 " in _swrast_clear_stencil_buffer()",
1259 _mesa_get_format_name(rb
->Format
));
1262 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);