include surface.offset in address calculations
[mesa.git] / src / mesa / pipe / softpipe / sp_quad_stencil.c
1
2 /**
3 * \brief Quad stencil testing
4 */
5
6
7 #include "main/glheader.h"
8 #include "main/imports.h"
9 #include "sp_context.h"
10 #include "sp_headers.h"
11 #include "sp_surface.h"
12 #include "sp_quad.h"
13 #include "pipe/p_defines.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 GLbitfield
32 do_stencil_test(const GLubyte stencilVals[QUAD_SIZE], GLuint func,
33 GLbitfield ref, GLbitfield valMask)
34 {
35 GLbitfield passMask = 0x0;
36 GLuint 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 ((stencilVals[j] & valMask) < ref) {
47 passMask |= (1 << j);
48 }
49 }
50 break;
51 case PIPE_FUNC_EQUAL:
52 for (j = 0; j < QUAD_SIZE; j++) {
53 if ((stencilVals[j] & valMask) == ref) {
54 passMask |= (1 << j);
55 }
56 }
57 break;
58 case PIPE_FUNC_LEQUAL:
59 for (j = 0; j < QUAD_SIZE; j++) {
60 if ((stencilVals[j] & valMask) <= ref) {
61 passMask |= (1 << j);
62 }
63 }
64 break;
65 case PIPE_FUNC_GREATER:
66 for (j = 0; j < QUAD_SIZE; j++) {
67 if ((stencilVals[j] & valMask) > ref) {
68 passMask |= (1 << j);
69 }
70 }
71 break;
72 case PIPE_FUNC_NOTEQUAL:
73 for (j = 0; j < QUAD_SIZE; j++) {
74 if ((stencilVals[j] & valMask) != ref) {
75 passMask |= (1 << j);
76 }
77 }
78 break;
79 case PIPE_FUNC_GEQUAL:
80 for (j = 0; j < QUAD_SIZE; j++) {
81 if ((stencilVals[j] & valMask) >= ref) {
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(GLubyte stencilVals[QUAD_SIZE],
109 GLbitfield mask, GLuint op, GLubyte ref, GLubyte wrtMask)
110 {
111 GLuint j;
112 GLubyte 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 softpipe_surface *s_surf = softpipe_surface(softpipe->framebuffer.sbuf);
205 GLuint func, zFailOp, zPassOp, failOp;
206 GLubyte ref, wrtMask, valMask;
207 GLubyte stencilVals[QUAD_SIZE];
208
209 /* choose front or back face function, operator, etc */
210 /* XXX we could do these initializations once per primitive */
211 if (softpipe->stencil.back_enabled && quad->facing) {
212 func = softpipe->stencil.back_func;
213 failOp = softpipe->stencil.back_fail_op;
214 zFailOp = softpipe->stencil.back_zfail_op;
215 zPassOp = softpipe->stencil.back_zpass_op;
216 ref = softpipe->stencil.ref_value[1];
217 wrtMask = softpipe->stencil.write_mask[1];
218 valMask = softpipe->stencil.value_mask[1];
219 }
220 else {
221 func = softpipe->stencil.front_func;
222 failOp = softpipe->stencil.front_fail_op;
223 zFailOp = softpipe->stencil.front_zfail_op;
224 zPassOp = softpipe->stencil.front_zpass_op;
225 ref = softpipe->stencil.ref_value[0];
226 wrtMask = softpipe->stencil.write_mask[0];
227 valMask = softpipe->stencil.value_mask[0];
228 }
229
230 assert(s_surf); /* shouldn't get here if there's no stencil buffer */
231 s_surf->read_quad_stencil(s_surf, quad->x0, quad->y0, stencilVals);
232
233 /* do the stencil test first */
234 {
235 GLbitfield passMask, failMask;
236 passMask = do_stencil_test(stencilVals, func, ref, valMask);
237 failMask = quad->mask & ~passMask;
238 quad->mask &= passMask;
239
240 if (failOp != PIPE_STENCIL_OP_KEEP) {
241 apply_stencil_op(stencilVals, failMask, failOp, ref, wrtMask);
242 }
243 }
244
245 if (quad->mask) {
246
247 /* now the pixels that passed the stencil test are depth tested */
248 if (softpipe->depth_test.enabled) {
249 const GLbitfield origMask = quad->mask;
250
251 sp_depth_test_quad(qs, quad); /* quad->mask is updated */
252
253 /* update stencil buffer values according to z pass/fail result */
254 if (zFailOp != PIPE_STENCIL_OP_KEEP) {
255 const GLbitfield failMask = origMask & ~quad->mask;
256 apply_stencil_op(stencilVals, failMask, zFailOp, ref, wrtMask);
257 }
258
259 if (zPassOp != PIPE_STENCIL_OP_KEEP) {
260 const GLbitfield passMask = origMask & quad->mask;
261 apply_stencil_op(stencilVals, passMask, zPassOp, ref, wrtMask);
262 }
263 }
264 else {
265 /* no depth test, apply Zpass operator to stencil buffer values */
266 apply_stencil_op(stencilVals, quad->mask, zPassOp, ref, wrtMask);
267 }
268
269 }
270
271 s_surf->write_quad_stencil(s_surf, quad->x0, quad->y0, stencilVals);
272
273 if (quad->mask)
274 qs->next->run(qs->next, quad);
275 }
276
277
278 static void stencil_begin(struct quad_stage *qs)
279 {
280 if (qs->next)
281 qs->next->begin(qs->next);
282 }
283
284
285 struct quad_stage *sp_quad_stencil_test_stage( struct softpipe_context *softpipe )
286 {
287 struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
288
289 stage->softpipe = softpipe;
290 stage->begin = stencil_begin;
291 stage->run = stencil_test_quad;
292
293 return stage;
294 }