Merge commit 'origin/master' into gallium-0.2
[mesa.git] / src / gallium / drivers / softpipe / sp_quad_stencil.c
1
2 /**
3 * \brief Quad stencil testing
4 */
5
6
7 #include "sp_context.h"
8 #include "sp_headers.h"
9 #include "sp_surface.h"
10 #include "sp_tile_cache.h"
11 #include "sp_quad.h"
12 #include "pipe/p_defines.h"
13 #include "util/u_memory.h"
14
15
16 /** Only 8-bit stencil supported */
17 #define STENCIL_MAX 0xff
18
19
20 /**
21 * Do the basic stencil test (compare stencil buffer values against the
22 * reference value.
23 *
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
30 */
31 static unsigned
32 do_stencil_test(const ubyte stencilVals[QUAD_SIZE], unsigned func,
33 unsigned ref, unsigned valMask)
34 {
35 unsigned passMask = 0x0;
36 unsigned j;
37
38 ref &= valMask;
39
40 switch (func) {
41 case PIPE_FUNC_NEVER:
42 /* passMask = 0x0 */
43 break;
44 case PIPE_FUNC_LESS:
45 for (j = 0; j < QUAD_SIZE; j++) {
46 if (ref < (stencilVals[j] & valMask)) {
47 passMask |= (1 << j);
48 }
49 }
50 break;
51 case PIPE_FUNC_EQUAL:
52 for (j = 0; j < QUAD_SIZE; j++) {
53 if (ref == (stencilVals[j] & valMask)) {
54 passMask |= (1 << j);
55 }
56 }
57 break;
58 case PIPE_FUNC_LEQUAL:
59 for (j = 0; j < QUAD_SIZE; j++) {
60 if (ref <= (stencilVals[j] & valMask)) {
61 passMask |= (1 << j);
62 }
63 }
64 break;
65 case PIPE_FUNC_GREATER:
66 for (j = 0; j < QUAD_SIZE; j++) {
67 if (ref > (stencilVals[j] & valMask)) {
68 passMask |= (1 << j);
69 }
70 }
71 break;
72 case PIPE_FUNC_NOTEQUAL:
73 for (j = 0; j < QUAD_SIZE; j++) {
74 if (ref != (stencilVals[j] & valMask)) {
75 passMask |= (1 << j);
76 }
77 }
78 break;
79 case PIPE_FUNC_GEQUAL:
80 for (j = 0; j < QUAD_SIZE; j++) {
81 if (ref >= (stencilVals[j] & valMask)) {
82 passMask |= (1 << j);
83 }
84 }
85 break;
86 case PIPE_FUNC_ALWAYS:
87 passMask = MASK_ALL;
88 break;
89 default:
90 assert(0);
91 }
92
93 return passMask;
94 }
95
96
97 /**
98 * Apply the stencil operator to stencil values.
99 *
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
105 * stencil values
106 */
107 static void
108 apply_stencil_op(ubyte stencilVals[QUAD_SIZE],
109 unsigned mask, unsigned op, ubyte ref, ubyte wrtMask)
110 {
111 unsigned j;
112 ubyte newstencil[QUAD_SIZE];
113
114 for (j = 0; j < QUAD_SIZE; j++) {
115 newstencil[j] = stencilVals[j];
116 }
117
118 switch (op) {
119 case PIPE_STENCIL_OP_KEEP:
120 /* no-op */
121 break;
122 case PIPE_STENCIL_OP_ZERO:
123 for (j = 0; j < QUAD_SIZE; j++) {
124 if (mask & (1 << j)) {
125 newstencil[j] = 0;
126 }
127 }
128 break;
129 case PIPE_STENCIL_OP_REPLACE:
130 for (j = 0; j < QUAD_SIZE; j++) {
131 if (mask & (1 << j)) {
132 newstencil[j] = ref;
133 }
134 }
135 break;
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;
141 }
142 }
143 }
144 break;
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;
150 }
151 }
152 }
153 break;
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;
158 }
159 }
160 break;
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;
165 }
166 }
167 break;
168 case PIPE_STENCIL_OP_INVERT:
169 for (j = 0; j < QUAD_SIZE; j++) {
170 if (mask & (1 << j)) {
171 newstencil[j] = ~stencilVals[j];
172 }
173 }
174 break;
175 default:
176 assert(0);
177 }
178
179 /*
180 * update the stencil values
181 */
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]);
186 }
187 }
188 else {
189 for (j = 0; j < QUAD_SIZE; j++) {
190 stencilVals[j] = newstencil[j];
191 }
192 }
193 }
194
195
196 /**
197 * Do stencil (and depth) testing. Stenciling depends on the outcome of
198 * depth testing.
199 */
200 static void
201 stencil_test_quad(struct quad_stage *qs, struct quad_header *quad)
202 {
203 struct softpipe_context *softpipe = qs->softpipe;
204 struct pipe_surface *ps = softpipe->framebuffer.zsbuf;
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->zsbuf_cache, quad->input.x0, quad->input.y0);
210 uint j;
211 uint face = quad->input.facing;
212
213 if (!softpipe->depth_stencil->stencil[1].enabled) {
214 /* single-sided stencil test, use front (face=0) state */
215 face = 0;
216 }
217
218 /* choose front or back face function, operator, etc */
219 /* XXX we could do these initializations once per primitive */
220 func = softpipe->depth_stencil->stencil[face].func;
221 failOp = softpipe->depth_stencil->stencil[face].fail_op;
222 zFailOp = softpipe->depth_stencil->stencil[face].zfail_op;
223 zPassOp = softpipe->depth_stencil->stencil[face].zpass_op;
224 ref = softpipe->depth_stencil->stencil[face].ref_value;
225 wrtMask = softpipe->depth_stencil->stencil[face].write_mask;
226 valMask = softpipe->depth_stencil->stencil[face].value_mask;
227
228 assert(ps); /* shouldn't get here if there's no stencil buffer */
229
230 /* get stencil values from cached tile */
231 switch (ps->format) {
232 case PIPE_FORMAT_S8Z24_UNORM:
233 for (j = 0; j < QUAD_SIZE; j++) {
234 int x = quad->input.x0 % TILE_SIZE + (j & 1);
235 int y = quad->input.y0 % TILE_SIZE + (j >> 1);
236 stencilVals[j] = tile->data.depth32[y][x] >> 24;
237 }
238 break;
239 case PIPE_FORMAT_Z24S8_UNORM:
240 for (j = 0; j < QUAD_SIZE; j++) {
241 int x = quad->input.x0 % TILE_SIZE + (j & 1);
242 int y = quad->input.y0 % TILE_SIZE + (j >> 1);
243 stencilVals[j] = tile->data.depth32[y][x] & 0xff;
244 }
245 break;
246 case PIPE_FORMAT_S8_UNORM:
247 for (j = 0; j < QUAD_SIZE; j++) {
248 int x = quad->input.x0 % TILE_SIZE + (j & 1);
249 int y = quad->input.y0 % TILE_SIZE + (j >> 1);
250 stencilVals[j] = tile->data.stencil8[y][x];
251 }
252 break;
253 default:
254 assert(0);
255 }
256
257 /* do the stencil test first */
258 {
259 unsigned passMask, failMask;
260 passMask = do_stencil_test(stencilVals, func, ref, valMask);
261 failMask = quad->inout.mask & ~passMask;
262 quad->inout.mask &= passMask;
263
264 if (failOp != PIPE_STENCIL_OP_KEEP) {
265 apply_stencil_op(stencilVals, failMask, failOp, ref, wrtMask);
266 }
267 }
268
269 if (quad->inout.mask) {
270 /* now the pixels that passed the stencil test are depth tested */
271 if (softpipe->depth_stencil->depth.enabled) {
272 const unsigned origMask = quad->inout.mask;
273
274 sp_depth_test_quad(qs, quad); /* quad->mask is updated */
275
276 /* update stencil buffer values according to z pass/fail result */
277 if (zFailOp != PIPE_STENCIL_OP_KEEP) {
278 const unsigned failMask = origMask & ~quad->inout.mask;
279 apply_stencil_op(stencilVals, failMask, zFailOp, ref, wrtMask);
280 }
281
282 if (zPassOp != PIPE_STENCIL_OP_KEEP) {
283 const unsigned passMask = origMask & quad->inout.mask;
284 apply_stencil_op(stencilVals, passMask, zPassOp, ref, wrtMask);
285 }
286 }
287 else {
288 /* no depth test, apply Zpass operator to stencil buffer values */
289 apply_stencil_op(stencilVals, quad->inout.mask, zPassOp, ref, wrtMask);
290 }
291
292 }
293
294 /* put new stencil values into cached tile */
295 switch (ps->format) {
296 case PIPE_FORMAT_S8Z24_UNORM:
297 for (j = 0; j < QUAD_SIZE; j++) {
298 int x = quad->input.x0 % TILE_SIZE + (j & 1);
299 int y = quad->input.y0 % TILE_SIZE + (j >> 1);
300 uint s8z24 = tile->data.depth32[y][x];
301 s8z24 = (stencilVals[j] << 24) | (s8z24 & 0xffffff);
302 tile->data.depth32[y][x] = s8z24;
303 }
304 break;
305 case PIPE_FORMAT_Z24S8_UNORM:
306 for (j = 0; j < QUAD_SIZE; j++) {
307 int x = quad->input.x0 % TILE_SIZE + (j & 1);
308 int y = quad->input.y0 % TILE_SIZE + (j >> 1);
309 uint z24s8 = tile->data.depth32[y][x];
310 z24s8 = (z24s8 & 0xffffff00) | stencilVals[j];
311 tile->data.depth32[y][x] = z24s8;
312 }
313 break;
314 case PIPE_FORMAT_S8_UNORM:
315 for (j = 0; j < QUAD_SIZE; j++) {
316 int x = quad->input.x0 % TILE_SIZE + (j & 1);
317 int y = quad->input.y0 % TILE_SIZE + (j >> 1);
318 tile->data.stencil8[y][x] = stencilVals[j];
319 }
320 break;
321 default:
322 assert(0);
323 }
324
325 if (quad->inout.mask)
326 qs->next->run(qs->next, quad);
327 }
328
329
330 static void stencil_begin(struct quad_stage *qs)
331 {
332 qs->next->begin(qs->next);
333 }
334
335
336 static void stencil_destroy(struct quad_stage *qs)
337 {
338 FREE( qs );
339 }
340
341
342 struct quad_stage *sp_quad_stencil_test_stage( struct softpipe_context *softpipe )
343 {
344 struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
345
346 stage->softpipe = softpipe;
347 stage->begin = stencil_begin;
348 stage->run = stencil_test_quad;
349 stage->destroy = stencil_destroy;
350
351 return stage;
352 }