From 73daa688541ec88119804ad190ce5b429e50ea44 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 10 Jul 2007 18:59:17 -0600 Subject: [PATCH] Checkpoint: stencil roughly working, some bugs to fix... --- src/mesa/drivers/x11/xm_surface.c | 65 ++++- src/mesa/pipe/p_defines.h | 5 +- src/mesa/pipe/softpipe/sp_context.c | 1 + src/mesa/pipe/softpipe/sp_quad.h | 1 + src/mesa/pipe/softpipe/sp_quad_depth_test.c | 15 +- src/mesa/pipe/softpipe/sp_quad_stencil.c | 277 +++++++++++++++----- src/mesa/pipe/softpipe/sp_surface.h | 5 + 7 files changed, 303 insertions(+), 66 deletions(-) diff --git a/src/mesa/drivers/x11/xm_surface.c b/src/mesa/drivers/x11/xm_surface.c index 5158e42d9a0..2bef5e6b9e6 100644 --- a/src/mesa/drivers/x11/xm_surface.c +++ b/src/mesa/drivers/x11/xm_surface.c @@ -244,6 +244,8 @@ xmesa_get_color_surface(GLcontext *ctx, GLuint buf) } + + static void read_quad_z(struct softpipe_surface *sps, GLint x, GLint y, GLuint zzzz[QUAD_SIZE]) @@ -296,6 +298,51 @@ create_z_surface(XMesaContext xmctx, struct gl_renderbuffer *rb) return xmsurf; } + + + +static void +read_quad_stencil(struct softpipe_surface *sps, + GLint x, GLint y, GLubyte ssss[QUAD_SIZE]) +{ + struct xmesa_surface *xmsurf = xmesa_surface(sps); + struct gl_renderbuffer *rb = xmsurf->rb; + GET_CURRENT_CONTEXT(ctx); + rb->GetRow(ctx, rb, 2, x, y, ssss); + rb->GetRow(ctx, rb, 2, x, y + 1, ssss + 2); +} + +static void +write_quad_stencil(struct softpipe_surface *sps, + GLint x, GLint y, const GLubyte ssss[QUAD_SIZE]) +{ + struct xmesa_surface *xmsurf = xmesa_surface(sps); + struct gl_renderbuffer *rb = xmsurf->rb; + GET_CURRENT_CONTEXT(ctx); + rb->PutRow(ctx, rb, 2, x, y, ssss, NULL); + rb->PutRow(ctx, rb, 2, x, y + 1, ssss + 2, NULL); +} + +static struct xmesa_surface * +create_stencil_surface(XMesaContext xmctx, struct gl_renderbuffer *rb) +{ + struct xmesa_surface *xmsurf; + + xmsurf = CALLOC_STRUCT(xmesa_surface); + if (xmsurf) { + xmsurf->sps.surface.format = PIPE_FORMAT_S8; + xmsurf->sps.surface.width = rb->Width; + xmsurf->sps.surface.height = rb->Height; + xmsurf->sps.read_quad_stencil = read_quad_stencil; + xmsurf->sps.write_quad_stencil = write_quad_stencil; + xmsurf->rb = rb; + } + return xmsurf; +} + + + + /** * Return a pipe_surface that wraps the current Z/depth buffer. * XXX this is pretty much a total hack until gl_renderbuffers and @@ -327,6 +374,22 @@ xmesa_get_z_surface(GLcontext *ctx) struct pipe_surface * xmesa_get_stencil_surface(GLcontext *ctx) { - return NULL; + XMesaContext xmctx = XMESA_CONTEXT(ctx); + struct gl_renderbuffer *rb = ctx->DrawBuffer->_StencilBuffer; + static struct xmesa_surface *xms = NULL; + + if (!rb) + return NULL; + + if (!xms) { + xms = create_stencil_surface(xmctx, rb); + } + else if (xms->sps.surface.width != rb->Width || + xms->sps.surface.height != rb->Height) { + free_surface(&xms->sps); + xms = create_stencil_surface(xmctx, rb); + } + + return (struct pipe_surface *) &xms->sps.surface; } diff --git a/src/mesa/pipe/p_defines.h b/src/mesa/pipe/p_defines.h index 7212040b362..fbdd015619d 100644 --- a/src/mesa/pipe/p_defines.h +++ b/src/mesa/pipe/p_defines.h @@ -125,7 +125,7 @@ #define PIPE_TEX_COMPARE_R_TO_TEXTURE 1 /** - * Texture/surface image formats + * Texture/surface image formats (preliminary) */ #define PIPE_FORMAT_U_R8_G8_B8_A8 0 /**< ubyte[4] RGBA */ #define PIPE_FORMAT_U_A8_R8_G8_B8 1 /**< ubyte[4] ARGB */ @@ -138,6 +138,9 @@ #define PIPE_FORMAT_F_Z32 8 /**< float Z/depth */ #define PIPE_FORMAT_YCBCR 9 #define PIPE_FORMAT_YCBCR_REV 10 +#define PIPE_FORMAT_S8 11 /**< 8-bit stencil */ +#define PIPE_FORMAT_Z24_S8 12 /**< 24-bit Z + 8-bit stencil */ + /** * Texture typess 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]); }; -- 2.30.2