2 * Mesa 3-D graphics library
4 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
26 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/imports.h"
29 #include "main/format_pack.h"
30 #include "main/format_unpack.h"
31 #include "main/stencil.h"
33 #include "s_context.h"
35 #include "s_stencil.h"
42 IF stencil test fails THEN
43 Apply fail-op to stencil value
44 Don't write the pixel (RGBA,Z)
46 IF doing depth test && depth test fails THEN
47 Apply zfail-op to stencil value
48 Write RGBA and Z to appropriate buffers
50 Apply zpass-op to stencil value
58 * Compute/return the offset of the stencil value in a pixel.
59 * For example, if the format is Z24+S8, the position of the stencil bits
60 * within the 4-byte pixel will be either 0 or 3.
63 get_stencil_offset(mesa_format format
)
65 const GLubyte one
= 1;
66 GLubyte pixel
[MAX_PIXEL_BYTES
];
67 GLint bpp
= _mesa_get_format_bytes(format
);
70 assert(_mesa_get_format_bits(format
, GL_STENCIL_BITS
) == 8);
71 memset(pixel
, 0, sizeof(pixel
));
72 _mesa_pack_ubyte_stencil_row(format
, 1, &one
, pixel
);
74 for (i
= 0; i
< bpp
; i
++) {
79 _mesa_problem(NULL
, "get_stencil_offset() failed\n");
84 /** Clamp the stencil value to [0, 255] */
97 #define STENCIL_OP(NEW_VAL) \
99 for (i = j = 0; i < n; i++, j += stride) { \
101 GLubyte s = stencil[j]; \
103 stencil[j] = (GLubyte) (NEW_VAL); \
108 for (i = j = 0; i < n; i++, j += stride) { \
110 GLubyte s = stencil[j]; \
111 stencil[j] = (GLubyte) ((invmask & s) | (wrtmask & (NEW_VAL))); \
118 * Apply the given stencil operator to the array of stencil values.
119 * Don't touch stencil[i] if mask[i] is zero.
120 * @param n number of stencil values
121 * @param oper the stencil buffer operator
122 * @param face 0 or 1 for front or back face operation
123 * @param stencil array of stencil values (in/out)
124 * @param mask array [n] of flag: 1=apply operator, 0=don't apply operator
125 * @param stride stride between stencil values
128 apply_stencil_op(const struct gl_context
*ctx
, GLenum oper
, GLuint face
,
129 GLuint n
, GLubyte stencil
[], const GLubyte mask
[],
132 const GLubyte ref
= _mesa_get_stencil_ref(ctx
, face
);
133 const GLubyte wrtmask
= ctx
->Stencil
.WriteMask
[face
];
134 const GLubyte invmask
= (GLubyte
) (~wrtmask
);
142 /* replace stencil buf values with zero */
146 /* replace stencil buf values with ref value */
150 /* increment stencil buf values, with clamping */
151 STENCIL_OP(clamp(s
+ 1));
154 /* increment stencil buf values, with clamping */
155 STENCIL_OP(clamp(s
- 1));
157 case GL_INCR_WRAP_EXT
:
158 /* increment stencil buf values, without clamping */
161 case GL_DECR_WRAP_EXT
:
162 /* increment stencil buf values, without clamping */
166 /* replace stencil buf values with inverted value */
170 _mesa_problem(ctx
, "Bad stencil op in apply_stencil_op");
176 #define STENCIL_TEST(FUNC) \
177 for (i = j = 0; i < n; i++, j += stride) { \
179 s = (GLubyte) (stencil[j] & valueMask); \
198 * Apply stencil test to an array of stencil values (before depth buffering).
199 * For the values that fail, we'll apply the GL_STENCIL_FAIL operator to
200 * the stencil values.
202 * @param face 0 or 1 for front or back-face polygons
203 * @param n number of pixels in the array
204 * @param stencil array of [n] stencil values (in/out)
205 * @param mask array [n] of flag: 0=skip the pixel, 1=stencil the pixel,
206 * values are set to zero where the stencil test fails.
207 * @param stride stride between stencil values
208 * @return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
211 do_stencil_test(struct gl_context
*ctx
, GLuint face
, GLuint n
,
212 GLubyte stencil
[], GLubyte mask
[], GLint stride
)
214 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
215 GLubyte
*fail
= swrast
->stencil_temp
.buf2
;
216 GLboolean allfail
= GL_FALSE
;
218 const GLuint valueMask
= ctx
->Stencil
.ValueMask
[face
];
219 const GLubyte ref
= (GLubyte
) (_mesa_get_stencil_ref(ctx
, face
) & valueMask
);
223 * Perform stencil test. The results of this operation are stored
224 * in the fail[] array:
225 * IF fail[i] is non-zero THEN
226 * the stencil fail operator is to be applied
228 * the stencil fail operator is not to be applied
231 switch (ctx
->Stencil
.Function
[face
]) {
237 STENCIL_TEST(ref
< s
);
240 STENCIL_TEST(ref
<= s
);
243 STENCIL_TEST(ref
> s
);
246 STENCIL_TEST(ref
>= s
);
249 STENCIL_TEST(ref
== s
);
252 STENCIL_TEST(ref
!= s
);
258 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_span");
262 if (ctx
->Stencil
.FailFunc
[face
] != GL_KEEP
) {
263 apply_stencil_op(ctx
, ctx
->Stencil
.FailFunc
[face
], face
, n
, stencil
,
272 * Compute the zpass/zfail masks by comparing the pre- and post-depth test
276 compute_pass_fail_masks(GLuint n
, const GLubyte origMask
[],
277 const GLubyte newMask
[],
278 GLubyte passMask
[], GLubyte failMask
[])
281 for (i
= 0; i
< n
; i
++) {
282 assert(newMask
[i
] == 0 || newMask
[i
] == 1);
283 passMask
[i
] = origMask
[i
] & newMask
[i
];
284 failMask
[i
] = origMask
[i
] & (newMask
[i
] ^ 1);
290 * Get 8-bit stencil values from random locations in the stencil buffer.
293 get_s8_values(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
,
294 GLuint count
, const GLint x
[], const GLint y
[],
297 struct swrast_renderbuffer
*srb
= swrast_renderbuffer(rb
);
298 const GLint w
= rb
->Width
, h
= rb
->Height
;
299 const GLubyte
*map
= _swrast_pixel_address(rb
, 0, 0);
302 if (rb
->Format
== MESA_FORMAT_S_UINT8
) {
303 const GLint rowStride
= srb
->RowStride
;
304 for (i
= 0; i
< count
; i
++) {
305 if (x
[i
] >= 0 && y
[i
] >= 0 && x
[i
] < w
&& y
[i
] < h
) {
306 stencil
[i
] = *(map
+ y
[i
] * rowStride
+ x
[i
]);
311 const GLint bpp
= _mesa_get_format_bytes(rb
->Format
);
312 const GLint rowStride
= srb
->RowStride
;
313 for (i
= 0; i
< count
; i
++) {
314 if (x
[i
] >= 0 && y
[i
] >= 0 && x
[i
] < w
&& y
[i
] < h
) {
315 const GLubyte
*src
= map
+ y
[i
] * rowStride
+ x
[i
] * bpp
;
316 _mesa_unpack_ubyte_stencil_row(rb
->Format
, 1, src
, &stencil
[i
]);
324 * Put 8-bit stencil values at random locations into the stencil buffer.
327 put_s8_values(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
,
328 GLuint count
, const GLint x
[], const GLint y
[],
329 const GLubyte stencil
[])
331 const GLint w
= rb
->Width
, h
= rb
->Height
;
332 gl_pack_ubyte_stencil_func pack_stencil
=
333 _mesa_get_pack_ubyte_stencil_func(rb
->Format
);
336 for (i
= 0; i
< count
; i
++) {
337 if (x
[i
] >= 0 && y
[i
] >= 0 && x
[i
] < w
&& y
[i
] < h
) {
338 GLubyte
*dst
= _swrast_pixel_address(rb
, x
[i
], y
[i
]);
339 pack_stencil(&stencil
[i
], dst
);
346 * /return GL_TRUE = one or more fragments passed,
347 * GL_FALSE = all fragments failed.
350 _swrast_stencil_and_ztest_span(struct gl_context
*ctx
, SWspan
*span
)
352 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
353 struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
354 struct gl_renderbuffer
*rb
= fb
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
355 const GLint stencilOffset
= get_stencil_offset(rb
->Format
);
356 const GLint stencilStride
= _mesa_get_format_bytes(rb
->Format
);
357 const GLuint face
= (span
->facing
== 0) ? 0 : ctx
->Stencil
._BackFace
;
358 const GLuint count
= span
->end
;
359 GLubyte
*mask
= span
->array
->mask
;
360 GLubyte
*stencilTemp
= swrast
->stencil_temp
.buf1
;
363 if (span
->arrayMask
& SPAN_XY
) {
364 /* read stencil values from random locations */
365 get_s8_values(ctx
, rb
, count
, span
->array
->x
, span
->array
->y
,
367 stencilBuf
= stencilTemp
;
370 /* Processing a horizontal run of pixels. Since stencil is always
371 * 8 bits for all MESA_FORMATs, we just need to use the right offset
372 * and stride to access them.
374 stencilBuf
= _swrast_pixel_address(rb
, span
->x
, span
->y
) + stencilOffset
;
378 * Apply the stencil test to the fragments.
379 * failMask[i] is 1 if the stencil test failed.
381 if (!do_stencil_test(ctx
, face
, count
, stencilBuf
, mask
, stencilStride
)) {
382 /* all fragments failed the stencil test, we're done. */
383 span
->writeAll
= GL_FALSE
;
384 if (span
->arrayMask
& SPAN_XY
) {
385 /* need to write the updated stencil values back to the buffer */
386 put_s8_values(ctx
, rb
, count
, span
->array
->x
, span
->array
->y
,
393 * Some fragments passed the stencil test, apply depth test to them
394 * and apply Zpass and Zfail stencil ops.
396 if (ctx
->Depth
.Test
== GL_FALSE
||
397 ctx
->DrawBuffer
->Attachment
[BUFFER_DEPTH
].Renderbuffer
== NULL
) {
399 * No depth buffer, just apply zpass stencil function to active pixels.
401 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
, count
,
402 stencilBuf
, mask
, stencilStride
);
406 * Perform depth buffering, then apply zpass or zfail stencil function.
408 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
409 GLubyte
*passMask
= swrast
->stencil_temp
.buf2
;
410 GLubyte
*failMask
= swrast
->stencil_temp
.buf3
;
411 GLubyte
*origMask
= swrast
->stencil_temp
.buf4
;
413 /* save the current mask bits */
414 memcpy(origMask
, mask
, count
* sizeof(GLubyte
));
416 /* apply the depth test */
417 _swrast_depth_test_span(ctx
, span
);
419 compute_pass_fail_masks(count
, origMask
, mask
, passMask
, failMask
);
421 /* apply the pass and fail operations */
422 if (ctx
->Stencil
.ZFailFunc
[face
] != GL_KEEP
) {
423 apply_stencil_op(ctx
, ctx
->Stencil
.ZFailFunc
[face
], face
,
424 count
, stencilBuf
, failMask
, stencilStride
);
426 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
427 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
428 count
, stencilBuf
, passMask
, stencilStride
);
432 /* Write updated stencil values back into hardware stencil buffer */
433 if (span
->arrayMask
& SPAN_XY
) {
434 put_s8_values(ctx
, rb
, count
, span
->array
->x
, span
->array
->y
,
438 span
->writeAll
= GL_FALSE
;
440 return GL_TRUE
; /* one or more fragments passed both tests */
447 * Return a span of stencil values from the stencil buffer.
448 * Used for glRead/CopyPixels
449 * Input: n - how many pixels
450 * x,y - location of first pixel
451 * Output: stencil - the array of stencil values
454 _swrast_read_stencil_span(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
,
455 GLint n
, GLint x
, GLint y
, GLubyte stencil
[])
459 if (y
< 0 || y
>= (GLint
) rb
->Height
||
460 x
+ n
<= 0 || x
>= (GLint
) rb
->Width
) {
461 /* span is completely outside framebuffer */
462 return; /* undefined values OK */
471 if (x
+ n
> (GLint
) rb
->Width
) {
472 GLint dx
= x
+ n
- rb
->Width
;
479 src
= _swrast_pixel_address(rb
, x
, y
);
480 _mesa_unpack_ubyte_stencil_row(rb
->Format
, n
, src
, stencil
);
486 * Write a span of stencil values to the stencil buffer. This function
487 * applies the stencil write mask when needed.
488 * Used for glDraw/CopyPixels
489 * Input: n - how many pixels
490 * x, y - location of first pixel
491 * stencil - the array of stencil values
494 _swrast_write_stencil_span(struct gl_context
*ctx
, GLint n
, GLint x
, GLint y
,
495 const GLubyte stencil
[] )
497 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
498 struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
499 struct gl_renderbuffer
*rb
= fb
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
500 const GLuint stencilMax
= (1 << fb
->Visual
.stencilBits
) - 1;
501 const GLuint stencilMask
= ctx
->Stencil
.WriteMask
[0];
504 if (y
< 0 || y
>= (GLint
) rb
->Height
||
505 x
+ n
<= 0 || x
>= (GLint
) rb
->Width
) {
506 /* span is completely outside framebuffer */
507 return; /* undefined values OK */
515 if (x
+ n
> (GLint
) rb
->Width
) {
516 GLint dx
= x
+ n
- rb
->Width
;
523 stencilBuf
= _swrast_pixel_address(rb
, x
, y
);
525 if ((stencilMask
& stencilMax
) != stencilMax
) {
526 /* need to apply writemask */
527 GLubyte
*destVals
= swrast
->stencil_temp
.buf1
;
528 GLubyte
*newVals
= swrast
->stencil_temp
.buf2
;
531 _mesa_unpack_ubyte_stencil_row(rb
->Format
, n
, stencilBuf
, destVals
);
532 for (i
= 0; i
< n
; i
++) {
534 = (stencil
[i
] & stencilMask
) | (destVals
[i
] & ~stencilMask
);
536 _mesa_pack_ubyte_stencil_row(rb
->Format
, n
, newVals
, stencilBuf
);
539 _mesa_pack_ubyte_stencil_row(rb
->Format
, n
, stencil
, stencilBuf
);
546 * Clear the stencil buffer. If the buffer is a combined
547 * depth+stencil buffer, only the stencil bits will be touched.
550 _swrast_clear_stencil_buffer(struct gl_context
*ctx
)
552 struct gl_renderbuffer
*rb
=
553 ctx
->DrawBuffer
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
554 const GLubyte stencilBits
= ctx
->DrawBuffer
->Visual
.stencilBits
;
555 const GLuint writeMask
= ctx
->Stencil
.WriteMask
[0];
556 const GLuint stencilMax
= (1 << stencilBits
) - 1;
557 GLint x
, y
, width
, height
;
559 GLint rowStride
, i
, j
;
562 if (!rb
|| writeMask
== 0)
565 /* compute region to clear */
566 x
= ctx
->DrawBuffer
->_Xmin
;
567 y
= ctx
->DrawBuffer
->_Ymin
;
568 width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
569 height
= ctx
->DrawBuffer
->_Ymax
- ctx
->DrawBuffer
->_Ymin
;
571 mapMode
= GL_MAP_WRITE_BIT
;
572 if ((writeMask
& stencilMax
) != stencilMax
) {
573 /* need to mask stencil values */
574 mapMode
|= GL_MAP_READ_BIT
;
576 else if (_mesa_get_format_bits(rb
->Format
, GL_DEPTH_BITS
) > 0) {
577 /* combined depth+stencil, need to mask Z values */
578 mapMode
|= GL_MAP_READ_BIT
;
581 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
,
582 mapMode
, &map
, &rowStride
,
583 ctx
->DrawBuffer
->FlipY
);
585 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glClear(stencil)");
589 switch (rb
->Format
) {
590 case MESA_FORMAT_S_UINT8
:
592 GLubyte clear
= ctx
->Stencil
.Clear
& writeMask
& 0xff;
593 GLubyte mask
= (~writeMask
) & 0xff;
596 for (i
= 0; i
< height
; i
++) {
598 for (j
= 0; j
< width
; j
++) {
599 row
[j
] = (row
[j
] & mask
) | clear
;
604 else if (rowStride
== width
) {
605 /* clear whole buffer */
606 memset(map
, clear
, width
* height
);
609 /* clear scissored */
610 for (i
= 0; i
< height
; i
++) {
611 memset(map
, clear
, width
);
617 case MESA_FORMAT_Z24_UNORM_S8_UINT
:
619 GLuint clear
= (ctx
->Stencil
.Clear
& writeMask
& 0xff) << 24;
620 GLuint mask
= (((~writeMask
) & 0xff) << 24) | 0xffffff;
621 for (i
= 0; i
< height
; i
++) {
622 GLuint
*row
= (GLuint
*) map
;
623 for (j
= 0; j
< width
; j
++) {
624 row
[j
] = (row
[j
] & mask
) | clear
;
630 case MESA_FORMAT_S8_UINT_Z24_UNORM
:
632 GLuint clear
= ctx
->Stencil
.Clear
& writeMask
& 0xff;
633 GLuint mask
= 0xffffff00 | ((~writeMask
) & 0xff);
634 for (i
= 0; i
< height
; i
++) {
635 GLuint
*row
= (GLuint
*) map
;
636 for (j
= 0; j
< width
; j
++) {
637 row
[j
] = (row
[j
] & mask
) | clear
;
644 _mesa_problem(ctx
, "Unexpected stencil buffer format %s"
645 " in _swrast_clear_stencil_buffer()",
646 _mesa_get_format_name(rb
->Format
));
649 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);