00001
00007 #include "sp_context.h"
00008 #include "sp_headers.h"
00009 #include "sp_surface.h"
00010 #include "sp_tile_cache.h"
00011 #include "sp_quad.h"
00012 #include "pipe/p_defines.h"
00013 #include "util/u_memory.h"
00014
00015
00017 #define STENCIL_MAX 0xff
00018
00019
00031 static unsigned
00032 do_stencil_test(const ubyte stencilVals[QUAD_SIZE], unsigned func,
00033 unsigned ref, unsigned valMask)
00034 {
00035 unsigned passMask = 0x0;
00036 unsigned j;
00037
00038 ref &= valMask;
00039
00040 switch (func) {
00041 case PIPE_FUNC_NEVER:
00042
00043 break;
00044 case PIPE_FUNC_LESS:
00045 for (j = 0; j < QUAD_SIZE; j++) {
00046 if (ref < (stencilVals[j] & valMask)) {
00047 passMask |= (1 << j);
00048 }
00049 }
00050 break;
00051 case PIPE_FUNC_EQUAL:
00052 for (j = 0; j < QUAD_SIZE; j++) {
00053 if (ref == (stencilVals[j] & valMask)) {
00054 passMask |= (1 << j);
00055 }
00056 }
00057 break;
00058 case PIPE_FUNC_LEQUAL:
00059 for (j = 0; j < QUAD_SIZE; j++) {
00060 if (ref <= (stencilVals[j] & valMask)) {
00061 passMask |= (1 << j);
00062 }
00063 }
00064 break;
00065 case PIPE_FUNC_GREATER:
00066 for (j = 0; j < QUAD_SIZE; j++) {
00067 if (ref > (stencilVals[j] & valMask)) {
00068 passMask |= (1 << j);
00069 }
00070 }
00071 break;
00072 case PIPE_FUNC_NOTEQUAL:
00073 for (j = 0; j < QUAD_SIZE; j++) {
00074 if (ref != (stencilVals[j] & valMask)) {
00075 passMask |= (1 << j);
00076 }
00077 }
00078 break;
00079 case PIPE_FUNC_GEQUAL:
00080 for (j = 0; j < QUAD_SIZE; j++) {
00081 if (ref >= (stencilVals[j] & valMask)) {
00082 passMask |= (1 << j);
00083 }
00084 }
00085 break;
00086 case PIPE_FUNC_ALWAYS:
00087 passMask = MASK_ALL;
00088 break;
00089 default:
00090 assert(0);
00091 }
00092
00093 return passMask;
00094 }
00095
00096
00107 static void
00108 apply_stencil_op(ubyte stencilVals[QUAD_SIZE],
00109 unsigned mask, unsigned op, ubyte ref, ubyte wrtMask)
00110 {
00111 unsigned j;
00112 ubyte newstencil[QUAD_SIZE];
00113
00114 for (j = 0; j < QUAD_SIZE; j++) {
00115 newstencil[j] = stencilVals[j];
00116 }
00117
00118 switch (op) {
00119 case PIPE_STENCIL_OP_KEEP:
00120
00121 break;
00122 case PIPE_STENCIL_OP_ZERO:
00123 for (j = 0; j < QUAD_SIZE; j++) {
00124 if (mask & (1 << j)) {
00125 newstencil[j] = 0;
00126 }
00127 }
00128 break;
00129 case PIPE_STENCIL_OP_REPLACE:
00130 for (j = 0; j < QUAD_SIZE; j++) {
00131 if (mask & (1 << j)) {
00132 newstencil[j] = ref;
00133 }
00134 }
00135 break;
00136 case PIPE_STENCIL_OP_INCR:
00137 for (j = 0; j < QUAD_SIZE; j++) {
00138 if (mask & (1 << j)) {
00139 if (stencilVals[j] < STENCIL_MAX) {
00140 newstencil[j] = stencilVals[j] + 1;
00141 }
00142 }
00143 }
00144 break;
00145 case PIPE_STENCIL_OP_DECR:
00146 for (j = 0; j < QUAD_SIZE; j++) {
00147 if (mask & (1 << j)) {
00148 if (stencilVals[j] > 0) {
00149 newstencil[j] = stencilVals[j] - 1;
00150 }
00151 }
00152 }
00153 break;
00154 case PIPE_STENCIL_OP_INCR_WRAP:
00155 for (j = 0; j < QUAD_SIZE; j++) {
00156 if (mask & (1 << j)) {
00157 newstencil[j] = stencilVals[j] + 1;
00158 }
00159 }
00160 break;
00161 case PIPE_STENCIL_OP_DECR_WRAP:
00162 for (j = 0; j < QUAD_SIZE; j++) {
00163 if (mask & (1 << j)) {
00164 newstencil[j] = stencilVals[j] - 1;
00165 }
00166 }
00167 break;
00168 case PIPE_STENCIL_OP_INVERT:
00169 for (j = 0; j < QUAD_SIZE; j++) {
00170 if (mask & (1 << j)) {
00171 newstencil[j] = ~stencilVals[j];
00172 }
00173 }
00174 break;
00175 default:
00176 assert(0);
00177 }
00178
00179
00180
00181
00182 if (wrtMask != STENCIL_MAX) {
00183
00184 for (j = 0; j < QUAD_SIZE; j++) {
00185 stencilVals[j] = (wrtMask & newstencil[j]) | (~wrtMask & stencilVals[j]);
00186 }
00187 }
00188 else {
00189 for (j = 0; j < QUAD_SIZE; j++) {
00190 stencilVals[j] = newstencil[j];
00191 }
00192 }
00193 }
00194
00195
00200 static void
00201 stencil_test_quad(struct quad_stage *qs, struct quad_header *quad)
00202 {
00203 struct softpipe_context *softpipe = qs->softpipe;
00204 struct pipe_surface *ps = softpipe->framebuffer.zsbuf;
00205 unsigned func, zFailOp, zPassOp, failOp;
00206 ubyte ref, wrtMask, valMask;
00207 ubyte stencilVals[QUAD_SIZE];
00208 struct softpipe_cached_tile *tile
00209 = sp_get_cached_tile(softpipe, softpipe->zsbuf_cache, quad->input.x0, quad->input.y0);
00210 uint j;
00211 uint face = quad->input.facing;
00212
00213 if (!softpipe->depth_stencil->stencil[1].enabled) {
00214
00215 face = 0;
00216 }
00217
00218
00219
00220 func = softpipe->depth_stencil->stencil[face].func;
00221 failOp = softpipe->depth_stencil->stencil[face].fail_op;
00222 zFailOp = softpipe->depth_stencil->stencil[face].zfail_op;
00223 zPassOp = softpipe->depth_stencil->stencil[face].zpass_op;
00224 ref = softpipe->depth_stencil->stencil[face].ref_value;
00225 wrtMask = softpipe->depth_stencil->stencil[face].write_mask;
00226 valMask = softpipe->depth_stencil->stencil[face].value_mask;
00227
00228 assert(ps);
00229
00230
00231 switch (ps->format) {
00232 case PIPE_FORMAT_S8Z24_UNORM:
00233 for (j = 0; j < QUAD_SIZE; j++) {
00234 int x = quad->input.x0 % TILE_SIZE + (j & 1);
00235 int y = quad->input.y0 % TILE_SIZE + (j >> 1);
00236 stencilVals[j] = tile->data.depth32[y][x] >> 24;
00237 }
00238 break;
00239 case PIPE_FORMAT_Z24S8_UNORM:
00240 for (j = 0; j < QUAD_SIZE; j++) {
00241 int x = quad->input.x0 % TILE_SIZE + (j & 1);
00242 int y = quad->input.y0 % TILE_SIZE + (j >> 1);
00243 stencilVals[j] = tile->data.depth32[y][x] & 0xff;
00244 }
00245 break;
00246 case PIPE_FORMAT_S8_UNORM:
00247 for (j = 0; j < QUAD_SIZE; j++) {
00248 int x = quad->input.x0 % TILE_SIZE + (j & 1);
00249 int y = quad->input.y0 % TILE_SIZE + (j >> 1);
00250 stencilVals[j] = tile->data.stencil8[y][x];
00251 }
00252 break;
00253 default:
00254 assert(0);
00255 }
00256
00257
00258 {
00259 unsigned passMask, failMask;
00260 passMask = do_stencil_test(stencilVals, func, ref, valMask);
00261 failMask = quad->inout.mask & ~passMask;
00262 quad->inout.mask &= passMask;
00263
00264 if (failOp != PIPE_STENCIL_OP_KEEP) {
00265 apply_stencil_op(stencilVals, failMask, failOp, ref, wrtMask);
00266 }
00267 }
00268
00269 if (quad->inout.mask) {
00270
00271 if (softpipe->depth_stencil->depth.enabled) {
00272 const unsigned origMask = quad->inout.mask;
00273
00274 sp_depth_test_quad(qs, quad);
00275
00276
00277 if (zFailOp != PIPE_STENCIL_OP_KEEP) {
00278 const unsigned failMask = origMask & ~quad->inout.mask;
00279 apply_stencil_op(stencilVals, failMask, zFailOp, ref, wrtMask);
00280 }
00281
00282 if (zPassOp != PIPE_STENCIL_OP_KEEP) {
00283 const unsigned passMask = origMask & quad->inout.mask;
00284 apply_stencil_op(stencilVals, passMask, zPassOp, ref, wrtMask);
00285 }
00286 }
00287 else {
00288
00289 apply_stencil_op(stencilVals, quad->inout.mask, zPassOp, ref, wrtMask);
00290 }
00291
00292 }
00293
00294
00295 switch (ps->format) {
00296 case PIPE_FORMAT_S8Z24_UNORM:
00297 for (j = 0; j < QUAD_SIZE; j++) {
00298 int x = quad->input.x0 % TILE_SIZE + (j & 1);
00299 int y = quad->input.y0 % TILE_SIZE + (j >> 1);
00300 uint s8z24 = tile->data.depth32[y][x];
00301 s8z24 = (stencilVals[j] << 24) | (s8z24 & 0xffffff);
00302 tile->data.depth32[y][x] = s8z24;
00303 }
00304 break;
00305 case PIPE_FORMAT_Z24S8_UNORM:
00306 for (j = 0; j < QUAD_SIZE; j++) {
00307 int x = quad->input.x0 % TILE_SIZE + (j & 1);
00308 int y = quad->input.y0 % TILE_SIZE + (j >> 1);
00309 uint z24s8 = tile->data.depth32[y][x];
00310 z24s8 = (z24s8 & 0xffffff00) | stencilVals[j];
00311 tile->data.depth32[y][x] = z24s8;
00312 }
00313 break;
00314 case PIPE_FORMAT_S8_UNORM:
00315 for (j = 0; j < QUAD_SIZE; j++) {
00316 int x = quad->input.x0 % TILE_SIZE + (j & 1);
00317 int y = quad->input.y0 % TILE_SIZE + (j >> 1);
00318 tile->data.stencil8[y][x] = stencilVals[j];
00319 }
00320 break;
00321 default:
00322 assert(0);
00323 }
00324
00325 if (quad->inout.mask)
00326 qs->next->run(qs->next, quad);
00327 }
00328
00329
00330 static void stencil_begin(struct quad_stage *qs)
00331 {
00332 qs->next->begin(qs->next);
00333 }
00334
00335
00336 static void stencil_destroy(struct quad_stage *qs)
00337 {
00338 FREE( qs );
00339 }
00340
00341
00342 struct quad_stage *sp_quad_stencil_test_stage( struct softpipe_context *softpipe )
00343 {
00344 struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
00345
00346 stage->softpipe = softpipe;
00347 stage->begin = stencil_begin;
00348 stage->run = stencil_test_quad;
00349 stage->destroy = stencil_destroy;
00350
00351 return stage;
00352 }