summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBrian <brian.paul@tungstengraphics.com>2007-07-10 18:59:17 -0600
committerBrian <brian.paul@tungstengraphics.com>2007-07-10 18:59:17 -0600
commit73daa688541ec88119804ad190ce5b429e50ea44 (patch)
tree51b54851b3f74557a82bae2a88f0af6af7a08fc9 /src
parente6eca5c37e13fd0f9100de127075b1bbed0821c0 (diff)
Checkpoint: stencil roughly working, some bugs to fix...
Diffstat (limited to 'src')
-rw-r--r--src/mesa/drivers/x11/xm_surface.c65
-rw-r--r--src/mesa/pipe/p_defines.h5
-rw-r--r--src/mesa/pipe/softpipe/sp_context.c1
-rw-r--r--src/mesa/pipe/softpipe/sp_quad.h1
-rw-r--r--src/mesa/pipe/softpipe/sp_quad_depth_test.c15
-rw-r--r--src/mesa/pipe/softpipe/sp_quad_stencil.c277
-rw-r--r--src/mesa/pipe/softpipe/sp_surface.h5
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 5158e42d9a..2bef5e6b9e 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 7212040b36..fbdd015619 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 6afc0c1320..50434600c3 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 c09905c249..df416dfa7f 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 f7dc5c877b..d47c4c42b8 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 9f59d09906..5b59addce2 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 450542abdd..3ba732cebe 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]);
};