3 * \brief Quad stencil testing
7 #include "sp_context.h"
8 #include "sp_headers.h"
9 #include "sp_surface.h"
10 #include "sp_tile_cache.h"
12 #include "pipe/p_defines.h"
13 #include "pipe/p_util.h"
16 /** Only 8-bit stencil supported */
17 #define STENCIL_MAX 0xff
21 * Do the basic stencil test (compare stencil buffer values against the
24 * \param stencilVals the stencil values from the stencil buffer
25 * \param func the stencil func (PIPE_FUNC_x)
26 * \param ref the stencil reference value
27 * \param valMask the stencil value mask indicating which bits of the stencil
28 * values and ref value are to be used.
29 * \return mask indicating which pixels passed the stencil test
32 do_stencil_test(const ubyte stencilVals
[QUAD_SIZE
], unsigned func
,
33 unsigned ref
, unsigned valMask
)
35 unsigned passMask
= 0x0;
45 for (j
= 0; j
< QUAD_SIZE
; j
++) {
46 if (ref
< (stencilVals
[j
] & valMask
)) {
52 for (j
= 0; j
< QUAD_SIZE
; j
++) {
53 if (ref
== (stencilVals
[j
] & valMask
)) {
58 case PIPE_FUNC_LEQUAL
:
59 for (j
= 0; j
< QUAD_SIZE
; j
++) {
60 if (ref
<= (stencilVals
[j
] & valMask
)) {
65 case PIPE_FUNC_GREATER
:
66 for (j
= 0; j
< QUAD_SIZE
; j
++) {
67 if (ref
> (stencilVals
[j
] & valMask
)) {
72 case PIPE_FUNC_NOTEQUAL
:
73 for (j
= 0; j
< QUAD_SIZE
; j
++) {
74 if (ref
!= (stencilVals
[j
] & valMask
)) {
79 case PIPE_FUNC_GEQUAL
:
80 for (j
= 0; j
< QUAD_SIZE
; j
++) {
81 if (ref
>= (stencilVals
[j
] & valMask
)) {
86 case PIPE_FUNC_ALWAYS
:
98 * Apply the stencil operator to stencil values.
100 * \param stencilVals the stencil buffer values (read and written)
101 * \param mask indicates which pixels to update
102 * \param op the stencil operator (PIPE_STENCIL_OP_x)
103 * \param ref the stencil reference value
104 * \param wrtMask writemask controlling which bits are changed in the
108 apply_stencil_op(ubyte stencilVals
[QUAD_SIZE
],
109 unsigned mask
, unsigned op
, ubyte ref
, ubyte wrtMask
)
112 ubyte newstencil
[QUAD_SIZE
];
114 for (j
= 0; j
< QUAD_SIZE
; j
++) {
115 newstencil
[j
] = stencilVals
[j
];
119 case PIPE_STENCIL_OP_KEEP
:
122 case PIPE_STENCIL_OP_ZERO
:
123 for (j
= 0; j
< QUAD_SIZE
; j
++) {
124 if (mask
& (1 << j
)) {
129 case PIPE_STENCIL_OP_REPLACE
:
130 for (j
= 0; j
< QUAD_SIZE
; j
++) {
131 if (mask
& (1 << j
)) {
136 case PIPE_STENCIL_OP_INCR
:
137 for (j
= 0; j
< QUAD_SIZE
; j
++) {
138 if (mask
& (1 << j
)) {
139 if (stencilVals
[j
] < STENCIL_MAX
) {
140 newstencil
[j
] = stencilVals
[j
] + 1;
145 case PIPE_STENCIL_OP_DECR
:
146 for (j
= 0; j
< QUAD_SIZE
; j
++) {
147 if (mask
& (1 << j
)) {
148 if (stencilVals
[j
] > 0) {
149 newstencil
[j
] = stencilVals
[j
] - 1;
154 case PIPE_STENCIL_OP_INCR_WRAP
:
155 for (j
= 0; j
< QUAD_SIZE
; j
++) {
156 if (mask
& (1 << j
)) {
157 newstencil
[j
] = stencilVals
[j
] + 1;
161 case PIPE_STENCIL_OP_DECR_WRAP
:
162 for (j
= 0; j
< QUAD_SIZE
; j
++) {
163 if (mask
& (1 << j
)) {
164 newstencil
[j
] = stencilVals
[j
] - 1;
168 case PIPE_STENCIL_OP_INVERT
:
169 for (j
= 0; j
< QUAD_SIZE
; j
++) {
170 if (mask
& (1 << j
)) {
171 newstencil
[j
] = ~stencilVals
[j
];
180 * update the stencil values
182 if (wrtMask
!= STENCIL_MAX
) {
183 /* apply bit-wise stencil buffer writemask */
184 for (j
= 0; j
< QUAD_SIZE
; j
++) {
185 stencilVals
[j
] = (wrtMask
& newstencil
[j
]) | (~wrtMask
& stencilVals
[j
]);
189 for (j
= 0; j
< QUAD_SIZE
; j
++) {
190 stencilVals
[j
] = newstencil
[j
];
197 * Do stencil (and depth) testing. Stenciling depends on the outcome of
201 stencil_test_quad(struct quad_stage
*qs
, struct quad_header
*quad
)
203 struct softpipe_context
*softpipe
= qs
->softpipe
;
204 struct pipe_surface
*ps
= softpipe
->framebuffer
.sbuf
;
205 unsigned func
, zFailOp
, zPassOp
, failOp
;
206 ubyte ref
, wrtMask
, valMask
;
207 ubyte stencilVals
[QUAD_SIZE
];
208 struct softpipe_cached_tile
*tile
209 = sp_get_cached_tile(softpipe
, softpipe
->sbuf_cache
, quad
->x0
, quad
->y0
);
212 /* choose front or back face function, operator, etc */
213 /* XXX we could do these initializations once per primitive */
214 if (softpipe
->depth_stencil
->stencil
.back_enabled
&& quad
->facing
) {
215 func
= softpipe
->depth_stencil
->stencil
.back_func
;
216 failOp
= softpipe
->depth_stencil
->stencil
.back_fail_op
;
217 zFailOp
= softpipe
->depth_stencil
->stencil
.back_zfail_op
;
218 zPassOp
= softpipe
->depth_stencil
->stencil
.back_zpass_op
;
219 ref
= softpipe
->depth_stencil
->stencil
.ref_value
[1];
220 wrtMask
= softpipe
->depth_stencil
->stencil
.write_mask
[1];
221 valMask
= softpipe
->depth_stencil
->stencil
.value_mask
[1];
224 func
= softpipe
->depth_stencil
->stencil
.front_func
;
225 failOp
= softpipe
->depth_stencil
->stencil
.front_fail_op
;
226 zFailOp
= softpipe
->depth_stencil
->stencil
.front_zfail_op
;
227 zPassOp
= softpipe
->depth_stencil
->stencil
.front_zpass_op
;
228 ref
= softpipe
->depth_stencil
->stencil
.ref_value
[0];
229 wrtMask
= softpipe
->depth_stencil
->stencil
.write_mask
[0];
230 valMask
= softpipe
->depth_stencil
->stencil
.value_mask
[0];
233 assert(ps
); /* shouldn't get here if there's no stencil buffer */
235 /* get stencil values from cached tile */
236 switch (ps
->format
) {
237 case PIPE_FORMAT_S8_Z24
:
238 for (j
= 0; j
< QUAD_SIZE
; j
++) {
239 int x
= quad
->x0
% TILE_SIZE
+ (j
& 1);
240 int y
= quad
->y0
% TILE_SIZE
+ (j
>> 1);
241 stencilVals
[j
] = tile
->data
.depth32
[y
][x
] >> 24;
244 case PIPE_FORMAT_Z24_S8
:
245 for (j
= 0; j
< QUAD_SIZE
; j
++) {
246 int x
= quad
->x0
% TILE_SIZE
+ (j
& 1);
247 int y
= quad
->y0
% TILE_SIZE
+ (j
>> 1);
248 stencilVals
[j
] = tile
->data
.depth32
[y
][x
] & 0xff;
251 case PIPE_FORMAT_U_S8
:
252 for (j
= 0; j
< QUAD_SIZE
; j
++) {
253 int x
= quad
->x0
% TILE_SIZE
+ (j
& 1);
254 int y
= quad
->y0
% TILE_SIZE
+ (j
>> 1);
255 stencilVals
[j
] = tile
->data
.stencil8
[y
][x
];
262 /* do the stencil test first */
264 unsigned passMask
, failMask
;
265 passMask
= do_stencil_test(stencilVals
, func
, ref
, valMask
);
266 failMask
= quad
->mask
& ~passMask
;
267 quad
->mask
&= passMask
;
269 if (failOp
!= PIPE_STENCIL_OP_KEEP
) {
270 apply_stencil_op(stencilVals
, failMask
, failOp
, ref
, wrtMask
);
275 /* now the pixels that passed the stencil test are depth tested */
276 if (softpipe
->depth_stencil
->depth
.enabled
) {
277 const unsigned origMask
= quad
->mask
;
279 sp_depth_test_quad(qs
, quad
); /* quad->mask is updated */
281 /* update stencil buffer values according to z pass/fail result */
282 if (zFailOp
!= PIPE_STENCIL_OP_KEEP
) {
283 const unsigned failMask
= origMask
& ~quad
->mask
;
284 apply_stencil_op(stencilVals
, failMask
, zFailOp
, ref
, wrtMask
);
287 if (zPassOp
!= PIPE_STENCIL_OP_KEEP
) {
288 const unsigned passMask
= origMask
& quad
->mask
;
289 apply_stencil_op(stencilVals
, passMask
, zPassOp
, ref
, wrtMask
);
293 /* no depth test, apply Zpass operator to stencil buffer values */
294 apply_stencil_op(stencilVals
, quad
->mask
, zPassOp
, ref
, wrtMask
);
299 /* put new stencil values into cached tile */
300 switch (ps
->format
) {
301 case PIPE_FORMAT_S8_Z24
:
302 for (j
= 0; j
< QUAD_SIZE
; j
++) {
303 int x
= quad
->x0
% TILE_SIZE
+ (j
& 1);
304 int y
= quad
->y0
% TILE_SIZE
+ (j
>> 1);
305 uint s8z24
= tile
->data
.depth32
[y
][x
];
306 s8z24
= (stencilVals
[j
] << 24) | (s8z24
& 0xffffff);
307 tile
->data
.depth32
[y
][x
] = s8z24
;
310 case PIPE_FORMAT_Z24_S8
:
311 for (j
= 0; j
< QUAD_SIZE
; j
++) {
312 int x
= quad
->x0
% TILE_SIZE
+ (j
& 1);
313 int y
= quad
->y0
% TILE_SIZE
+ (j
>> 1);
314 uint z24s8
= tile
->data
.depth32
[y
][x
];
315 z24s8
= (z24s8
& 0xffffff00) | stencilVals
[j
];
316 tile
->data
.depth32
[y
][x
] = z24s8
;
319 case PIPE_FORMAT_U_S8
:
320 for (j
= 0; j
< QUAD_SIZE
; j
++) {
321 int x
= quad
->x0
% TILE_SIZE
+ (j
& 1);
322 int y
= quad
->y0
% TILE_SIZE
+ (j
>> 1);
323 tile
->data
.stencil8
[y
][x
] = stencilVals
[j
];
331 qs
->next
->run(qs
->next
, quad
);
335 static void stencil_begin(struct quad_stage
*qs
)
338 qs
->next
->begin(qs
->next
);
342 static void stencil_destroy(struct quad_stage
*qs
)
348 struct quad_stage
*sp_quad_stencil_test_stage( struct softpipe_context
*softpipe
)
350 struct quad_stage
*stage
= CALLOC_STRUCT(quad_stage
);
352 stage
->softpipe
= softpipe
;
353 stage
->begin
= stencil_begin
;
354 stage
->run
= stencil_test_quad
;
355 stage
->destroy
= stencil_destroy
;