diff options
Diffstat (limited to 'src/mesa/pipe/softpipe')
-rw-r--r-- | src/mesa/pipe/softpipe/sp_context.c | 1 | ||||
-rw-r--r-- | src/mesa/pipe/softpipe/sp_quad.h | 1 | ||||
-rw-r--r-- | src/mesa/pipe/softpipe/sp_quad_depth_test.c | 15 | ||||
-rw-r--r-- | src/mesa/pipe/softpipe/sp_quad_stencil.c | 277 | ||||
-rw-r--r-- | src/mesa/pipe/softpipe/sp_surface.h | 5 |
5 files changed, 235 insertions, 64 deletions
diff --git a/src/mesa/pipe/softpipe/sp_context.c b/src/mesa/pipe/softpipe/sp_context.c index 6afc0c1320f..50434600c3f 100644 --- a/src/mesa/pipe/softpipe/sp_context.c +++ b/src/mesa/pipe/softpipe/sp_context.c @@ -87,6 +87,7 @@ struct pipe_context *softpipe_create( void ) softpipe->quad.alpha_test = sp_quad_alpha_test_stage(softpipe); softpipe->quad.blend = sp_quad_blend_stage(softpipe); softpipe->quad.depth_test = sp_quad_depth_test_stage(softpipe); + softpipe->quad.stencil_test = sp_quad_stencil_test_stage(softpipe); softpipe->quad.output = sp_quad_output_stage(softpipe); /* diff --git a/src/mesa/pipe/softpipe/sp_quad.h b/src/mesa/pipe/softpipe/sp_quad.h index c09905c2498..df416dfa7f2 100644 --- a/src/mesa/pipe/softpipe/sp_quad.h +++ b/src/mesa/pipe/softpipe/sp_quad.h @@ -55,5 +55,6 @@ struct quad_stage *sp_quad_output_stage( struct softpipe_context *softpipe ); void sp_build_quad_pipeline(struct softpipe_context *sp); +void sp_depth_test_quad(struct quad_stage *qs, struct quad_header *quad); #endif /* SP_TILE_H */ diff --git a/src/mesa/pipe/softpipe/sp_quad_depth_test.c b/src/mesa/pipe/softpipe/sp_quad_depth_test.c index f7dc5c877b1..d47c4c42b8f 100644 --- a/src/mesa/pipe/softpipe/sp_quad_depth_test.c +++ b/src/mesa/pipe/softpipe/sp_quad_depth_test.c @@ -35,8 +35,12 @@ #include "sp_quad.h" -static void -depth_test_quad(struct quad_stage *qs, struct quad_header *quad) +/** + * Do depth testing for a quad. + * Not static since it's used by the stencil code. + */ +void +sp_depth_test_quad(struct quad_stage *qs, struct quad_header *quad) { struct softpipe_context *softpipe = qs->softpipe; struct softpipe_surface *sps = softpipe_surface(softpipe->framebuffer.zbuf); @@ -137,6 +141,13 @@ depth_test_quad(struct quad_stage *qs, struct quad_header *quad) /* write updated zquad to zbuffer */ sps->write_quad_z(sps, quad->x0, quad->y0, bzzzz); } +} + + +static void +depth_test_quad(struct quad_stage *qs, struct quad_header *quad) +{ + sp_depth_test_quad(qs, quad); if (quad->mask) qs->next->run(qs->next, quad); diff --git a/src/mesa/pipe/softpipe/sp_quad_stencil.c b/src/mesa/pipe/softpipe/sp_quad_stencil.c index 9f59d09906c..5b59addce24 100644 --- a/src/mesa/pipe/softpipe/sp_quad_stencil.c +++ b/src/mesa/pipe/softpipe/sp_quad_stencil.c @@ -13,108 +13,261 @@ #include "pipe/p_defines.h" -static void -stencil_test_quad(struct quad_stage *qs, struct quad_header *quad) -{ - struct softpipe_context *softpipe = qs->softpipe; - struct softpipe_surface *sps = softpipe_surface(softpipe->framebuffer.zbuf); - GLuint bzzzz[QUAD_SIZE]; /**< Z values fetched from depth buffer */ - GLuint qzzzz[QUAD_SIZE]; /**< Z values from the quad */ - GLuint zmask = 0; - GLuint j; - GLfloat scale; +/** Only 8-bit stencil supported */ +#define STENCIL_MAX 0xff - assert(sps); /* shouldn't get here if there's no zbuffer */ - /* - * To increase efficiency, we should probably have multiple versions - * of this function that are specifically for Z16, Z32 and FP Z buffers. - * Try to effectively do that with codegen... - */ - if (sps->surface.format == PIPE_FORMAT_U_Z16) - scale = 65535.0; - else - assert(0); /* XXX fix this someday */ - - /* - * Convert quad's float depth values to int depth values. - * If the Z buffer stores integer values, we _have_ to do the depth - * compares with integers (not floats). Otherwise, the float->int->float - * conversion of Z values (which isn't an identity function) will cause - * Z-fighting errors. - */ - for (j = 0; j < QUAD_SIZE; j++) { - qzzzz[j] = (GLuint) (quad->outputs.depth[j] * scale); - } +/** + * Do the basic stencil test (compare stencil buffer values against the + * reference value. + * + * \param stencilVals the stencil values from the stencil buffer + * \param func the stencil func (PIPE_FUNC_x) + * \param ref the stencil reference value + * \param valMask the stencil value mask indicating which bits of the stencil + * values and ref value are to be used. + * \return mask indicating which pixels passed the stencil test + */ +static GLbitfield +do_stencil_test(const GLubyte stencilVals[QUAD_SIZE], GLuint func, + GLbitfield ref, GLbitfield valMask) +{ + GLbitfield passMask = 0x0; + GLuint j; - /* get zquad from zbuffer */ - sps->read_quad_z(sps, quad->x0, quad->y0, bzzzz); + ref &= valMask; - switch (softpipe->depth_test.func) { + switch (func) { case PIPE_FUNC_NEVER: - /* zmask = 0 */ + /* passMask = 0x0 */ break; case PIPE_FUNC_LESS: - /* Note this is pretty much a single sse or cell instruction. - * Like this: quad->mask &= (quad->outputs.depth < zzzz); - */ for (j = 0; j < QUAD_SIZE; j++) { - if (qzzzz[j] < bzzzz[j]) - zmask |= 1 << j; + if ((stencilVals[j] & valMask) < ref) { + passMask |= (1 << j); + } } break; case PIPE_FUNC_EQUAL: for (j = 0; j < QUAD_SIZE; j++) { - if (qzzzz[j] == bzzzz[j]) - zmask |= 1 << j; + if ((stencilVals[j] & valMask) == ref) { + passMask |= (1 << j); + } } break; case PIPE_FUNC_LEQUAL: for (j = 0; j < QUAD_SIZE; j++) { - if (qzzzz[j] <= bzzzz[j]) - zmask |= (1 << j); + if ((stencilVals[j] & valMask) <= ref) { + passMask |= (1 << j); + } } break; case PIPE_FUNC_GREATER: for (j = 0; j < QUAD_SIZE; j++) { - if (qzzzz[j] > bzzzz[j]) - zmask |= (1 << j); + if ((stencilVals[j] & valMask) > ref) { + passMask |= (1 << j); + } } break; case PIPE_FUNC_NOTEQUAL: for (j = 0; j < QUAD_SIZE; j++) { - if (qzzzz[j] != bzzzz[j]) - zmask |= (1 << j); + if ((stencilVals[j] & valMask) != ref) { + passMask |= (1 << j); + } } break; case PIPE_FUNC_GEQUAL: for (j = 0; j < QUAD_SIZE; j++) { - if (qzzzz[j] >= bzzzz[j]) - zmask |= (1 << j); + if ((stencilVals[j] & valMask) >= ref) { + passMask |= (1 << j); + } } break; case PIPE_FUNC_ALWAYS: - zmask = MASK_ALL; + passMask = MASK_ALL; break; default: - abort(); + assert(0); } - quad->mask &= zmask; + return passMask; +} + + +/** + * Apply the stencil operator to stencil values. + * + * \param stencilVals the stencil buffer values (read and written) + * \param mask indicates which pixels to update + * \param op the stencil operator (PIPE_STENCIL_OP_x) + * \param ref the stencil reference value + * \param wrtMask writemask controlling which bits are changed in the + * stencil values + */ +static void +apply_stencil_op(GLubyte stencilVals[QUAD_SIZE], + GLbitfield mask, GLuint op, GLubyte ref, GLubyte wrtMask) +{ + GLuint j; + GLubyte newstencil[QUAD_SIZE]; + + for (j = 0; j < QUAD_SIZE; j++) { + newstencil[j] = stencilVals[j]; + } - if (softpipe->depth_test.writemask) { - - /* This is also efficient with sse / spe instructions: - */ + switch (op) { + case PIPE_STENCIL_OP_KEEP: + /* no-op */ + break; + case PIPE_STENCIL_OP_ZERO: for (j = 0; j < QUAD_SIZE; j++) { - if (quad->mask & (1 << j)) { - bzzzz[j] = qzzzz[j]; - } + if (mask & (1 << j)) { + newstencil[j] = 0; + } } + break; + case PIPE_STENCIL_OP_REPLACE: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + newstencil[j] = ref; + } + } + break; + case PIPE_STENCIL_OP_INCR: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + if (stencilVals[j] < STENCIL_MAX) { + newstencil[j] = stencilVals[j] + 1; + } + } + } + break; + case PIPE_STENCIL_OP_DECR: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + if (stencilVals[j] > 0) { + newstencil[j] = stencilVals[j] - 1; + } + } + } + break; + case PIPE_STENCIL_OP_INCR_WRAP: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + newstencil[j] = stencilVals[j] + 1; + } + } + break; + case PIPE_STENCIL_OP_DECR_WRAP: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + newstencil[j] = stencilVals[j] - 1; + } + } + break; + case PIPE_STENCIL_OP_INVERT: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + newstencil[j] = ~stencilVals[j]; + } + } + break; + default: + assert(0); + } - /* write updated zquad to zbuffer */ - sps->write_quad_z(sps, quad->x0, quad->y0, bzzzz); + /* + * update the stencil values + */ + if (wrtMask != STENCIL_MAX) { + /* apply bit-wise stencil buffer writemask */ + for (j = 0; j < QUAD_SIZE; j++) { + stencilVals[j] = (wrtMask & newstencil[j]) | (~wrtMask & stencilVals[j]); + } } + else { + for (j = 0; j < QUAD_SIZE; j++) { + stencilVals[j] = newstencil[j]; + } + } +} + + +/** + * Do stencil (and depth) testing. Stenciling depends on the outcome of + * depth testing. + */ +static void +stencil_test_quad(struct quad_stage *qs, struct quad_header *quad) +{ + struct softpipe_context *softpipe = qs->softpipe; + struct softpipe_surface *s_surf = softpipe_surface(softpipe->framebuffer.sbuf); + GLuint func, zFailOp, zPassOp, failOp; + GLuint face = 0; + GLubyte ref, wrtMask, valMask; + GLubyte stencilVals[QUAD_SIZE]; + + /* choose front or back face function, operator, etc */ + if (softpipe->stencil.back_enabled && face == 1) { + func = softpipe->stencil.back_func; + failOp = softpipe->stencil.back_fail_op; + zFailOp = softpipe->stencil.back_zfail_op; + zPassOp = softpipe->stencil.back_zpass_op; + ref = softpipe->stencil.ref_value[1]; + wrtMask = softpipe->stencil.write_mask[1]; + valMask = softpipe->stencil.value_mask[1]; + } + else { + func = softpipe->stencil.front_func; + failOp = softpipe->stencil.front_fail_op; + zFailOp = softpipe->stencil.front_zfail_op; + zPassOp = softpipe->stencil.front_zpass_op; + ref = softpipe->stencil.ref_value[0]; + wrtMask = softpipe->stencil.write_mask[0]; + valMask = softpipe->stencil.value_mask[0]; + } + + assert(s_surf); /* shouldn't get here if there's no stencil buffer */ + s_surf->read_quad_stencil(s_surf, quad->x0, quad->y0, stencilVals); + + /* do the stencil test first */ + { + GLbitfield passMask, failMask; + passMask = do_stencil_test(stencilVals, func, ref, valMask); + failMask = quad->mask & ~passMask; + quad->mask &= passMask; + + if (failOp != PIPE_STENCIL_OP_KEEP) { + apply_stencil_op(stencilVals, failMask, failOp, ref, wrtMask); + } + } + + if (!quad->mask) + return; + + /* now the pixels that passed the stencil test are depth tested */ + if (softpipe->depth_test.enabled) { + const GLbitfield origMask = quad->mask; + + sp_depth_test_quad(qs, quad); /* quad->mask is updated */ + + /* update stencil buffer values according to z pass/fail result */ + if (zFailOp != PIPE_STENCIL_OP_KEEP) { + const GLbitfield failMask = origMask & ~quad->mask; + apply_stencil_op(stencilVals, failMask, zFailOp, ref, wrtMask); + } + + if (zPassOp != PIPE_STENCIL_OP_KEEP) { + const GLbitfield passMask = origMask & quad->mask; + apply_stencil_op(stencilVals, passMask, zPassOp, ref, wrtMask); + } + } + else { + /* no depth test, apply Zpass operator to stencil buffer values */ + apply_stencil_op(stencilVals, quad->mask, zPassOp, ref, wrtMask); + } + + s_surf->write_quad_stencil(s_surf, quad->x0, quad->y0, stencilVals); if (quad->mask) qs->next->run(qs->next, quad); diff --git a/src/mesa/pipe/softpipe/sp_surface.h b/src/mesa/pipe/softpipe/sp_surface.h index 450542abddb..3ba732cebe4 100644 --- a/src/mesa/pipe/softpipe/sp_surface.h +++ b/src/mesa/pipe/softpipe/sp_surface.h @@ -82,6 +82,11 @@ struct softpipe_surface { GLint x, GLint y, GLuint zzzz[QUAD_SIZE]); void (*write_quad_z)(struct softpipe_surface *, GLint x, GLint y, const GLuint zzzz[QUAD_SIZE]); + + void (*read_quad_stencil)(struct softpipe_surface *, + GLint x, GLint y, GLubyte ssss[QUAD_SIZE]); + void (*write_quad_stencil)(struct softpipe_surface *, + GLint x, GLint y, const GLubyte ssss[QUAD_SIZE]); }; |