/* * Apply stencil and depth testing to an array of pixels. * Hardware or software stencil buffer acceptable. * Input: n - number of pixels in the span * z - array [n] of z values * stencil - array [n] of stencil values * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) * Output: stencil - modified stencil values * mask - array [n] of flags (1=stencil and depth test passed) * Return: GL_TRUE - all fragments failed the testing * GL_FALSE - one or more fragments passed the testing * */ static GLboolean stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y, const GLdepth z[], GLstencil stencil[], GLubyte mask[] ) { ASSERT(ctx->Stencil.Enabled); ASSERT(n <= PB_SIZE); /* * Apply the stencil test to the fragments. * failMask[i] is 1 if the stencil test failed. */ if (do_stencil_test( ctx, n, stencil, mask ) == GL_FALSE) { /* all fragments failed the stencil test, we're done. */ return GL_FALSE; } /* * Some fragments passed the stencil test, apply depth test to them * and apply Zpass and Zfail stencil ops. */ if (ctx->Depth.Test==GL_FALSE) { /* * No depth buffer, just apply zpass stencil function to active pixels. */ apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask ); } else { /* * Perform depth buffering, then apply zpass or zfail stencil function. */ GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH]; GLuint i; /* save the current mask bits */ MEMCPY(oldmask, mask, n * sizeof(GLubyte)); /* apply the depth test */ _mesa_depth_test_span(ctx, n, x, y, z, mask); /* Set the stencil pass/fail flags according to result of depth testing. * if oldmask[i] == 0 then * Don't touch the stencil value * else if oldmask[i] and newmask[i] then * Depth test passed * else * assert(oldmask[i] && !newmask[i]) * Depth test failed * endif */ for (i=0;i<n;i++) { ASSERT(mask[i] == 0 || mask[i] == 1); passmask[i] = oldmask[i] & mask[i]; failmask[i] = oldmask[i] & (mask[i] ^ 1); } /* apply the pass and fail operations */ if (ctx->Stencil.ZFailFunc != GL_KEEP) { apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask ); } if (ctx->Stencil.ZPassFunc != GL_KEEP) { apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask ); } } return GL_TRUE; /* one or more fragments passed both tests */ }
/** * Apply stencil and depth testing to an array of pixels. * This is used both for software and hardware stencil buffers. * * The comments in this function are a bit sparse but the code is * almost identical to stencil_and_ztest_span(), which is well * commented. * * Input: n - number of pixels in the array * x, y - array of [n] pixel positions * z - array [n] of z values * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) * Output: mask - array [n] of flags (1=stencil and depth test passed) * Return: GL_FALSE - all fragments failed the testing * GL_TRUE - one or more fragments passed the testing */ static GLboolean stencil_and_ztest_pixels( GLcontext *ctx, struct sw_span *span, GLuint face ) { const GLuint n = span->end; const GLint *x = span->array->x; const GLint *y = span->array->y; GLubyte *mask = span->array->mask; SWcontext *swrast = SWRAST_CONTEXT(ctx); ASSERT(span->arrayMask & SPAN_XY); ASSERT(ctx->Stencil.Enabled); ASSERT(n <= MAX_WIDTH); if (swrast->Driver.WriteStencilPixels) { /*** Hardware stencil buffer ***/ GLstencil stencil[MAX_WIDTH]; GLubyte origMask[MAX_WIDTH]; ASSERT(!ctx->DrawBuffer->UseSoftwareStencilBuffer); ASSERT(swrast->Driver.ReadStencilPixels); (*swrast->Driver.ReadStencilPixels)(ctx, n, x, y, stencil); MEMCPY(origMask, mask, n * sizeof(GLubyte)); (void) do_stencil_test(ctx, face, n, stencil, mask); if (ctx->Depth.Test == GL_FALSE) { apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, mask); } else { _swrast_depth_test_span(ctx, span); if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { GLubyte failmask[MAX_WIDTH]; GLuint i; for (i = 0; i < n; i++) { ASSERT(mask[i] == 0 || mask[i] == 1); failmask[i] = origMask[i] & (mask[i] ^ 1); } apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face, n, stencil, failmask); } if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { GLubyte passmask[MAX_WIDTH]; GLuint i; for (i = 0; i < n; i++) { ASSERT(mask[i] == 0 || mask[i] == 1); passmask[i] = origMask[i] & mask[i]; } apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, passmask); } } /* Write updated stencil values into hardware stencil buffer */ (swrast->Driver.WriteStencilPixels)(ctx, n, x, y, stencil, origMask); return GL_TRUE; } else { /*** Software stencil buffer ***/ ASSERT(ctx->DrawBuffer->UseSoftwareStencilBuffer); if (stencil_test_pixels(ctx, face, n, x, y, mask) == GL_FALSE) { /* all fragments failed the stencil test, we're done. */ return GL_FALSE; } if (ctx->Depth.Test==GL_FALSE) { apply_stencil_op_to_pixels(ctx, n, x, y, ctx->Stencil.ZPassFunc[face], face, mask); } else { GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH]; GLuint i; MEMCPY(oldmask, mask, n * sizeof(GLubyte)); _swrast_depth_test_span(ctx, span); for (i=0;i<n;i++) { ASSERT(mask[i] == 0 || mask[i] == 1); passmask[i] = oldmask[i] & mask[i]; failmask[i] = oldmask[i] & (mask[i] ^ 1); } if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { apply_stencil_op_to_pixels(ctx, n, x, y, ctx->Stencil.ZFailFunc[face], face, failmask); } if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { apply_stencil_op_to_pixels(ctx, n, x, y, ctx->Stencil.ZPassFunc[face], face, passmask); } } return GL_TRUE; /* one or more fragments passed both tests */ } }
/* * Apply stencil and depth testing to an array of pixels. * This is used both for software and hardware stencil buffers. * * The comments in this function are a bit sparse but the code is * almost identical to stencil_and_ztest_span(), which is well * commented. * * Input: n - number of pixels in the array * x, y - array of [n] pixel positions * z - array [n] of z values * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) * Output: mask - array [n] of flags (1=stencil and depth test passed) * Return: GL_TRUE - all fragments failed the testing * GL_FALSE - one or more fragments passed the testing */ GLboolean _mesa_stencil_and_ztest_pixels( GLcontext *ctx, GLuint n, const GLint x[], const GLint y[], const GLdepth z[], GLubyte mask[] ) { ASSERT(ctx->Stencil.Enabled); ASSERT(n <= PB_SIZE); if (ctx->Driver.WriteStencilPixels) { /*** Hardware stencil buffer ***/ GLstencil stencil[PB_SIZE]; GLubyte origMask[PB_SIZE]; ASSERT(ctx->Driver.ReadStencilPixels); (*ctx->Driver.ReadStencilPixels)(ctx, n, x, y, stencil); MEMCPY(origMask, mask, n * sizeof(GLubyte)); (void) do_stencil_test( ctx, n, stencil, mask ); if (ctx->Depth.Test == GL_FALSE) { apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask ); } else { _mesa_depth_test_pixels(ctx, n, x, y, z, mask); if (ctx->Stencil.ZFailFunc != GL_KEEP) { GLubyte failmask[PB_SIZE]; GLuint i; for (i = 0; i < n; i++) { ASSERT(mask[i] == 0 || mask[i] == 1); failmask[i] = origMask[i] & (mask[i] ^ 1); } apply_stencil_op(ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask); } if (ctx->Stencil.ZPassFunc != GL_KEEP) { GLubyte passmask[PB_SIZE]; GLuint i; for (i = 0; i < n; i++) { ASSERT(mask[i] == 0 || mask[i] == 1); passmask[i] = origMask[i] & mask[i]; } apply_stencil_op(ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask); } } /* Write updated stencil values into hardware stencil buffer */ (ctx->Driver.WriteStencilPixels)(ctx, n, x, y, stencil, origMask ); return GL_TRUE; } else { /*** Software stencil buffer ***/ if (stencil_test_pixels(ctx, n, x, y, mask) == GL_FALSE) { /* all fragments failed the stencil test, we're done. */ return GL_FALSE; } if (ctx->Depth.Test==GL_FALSE) { apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask ); } else { GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE]; GLuint i; MEMCPY(oldmask, mask, n * sizeof(GLubyte)); _mesa_depth_test_pixels(ctx, n, x, y, z, mask); for (i=0;i<n;i++) { ASSERT(mask[i] == 0 || mask[i] == 1); passmask[i] = oldmask[i] & mask[i]; failmask[i] = oldmask[i] & (mask[i] ^ 1); } if (ctx->Stencil.ZFailFunc != GL_KEEP) { apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZFailFunc, failmask ); } if (ctx->Stencil.ZPassFunc != GL_KEEP) { apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, passmask ); } } return GL_TRUE; /* one or more fragments passed both tests */ } }
/** * Apply stencil and depth testing to the span of pixels. * Both software and hardware stencil buffers are acceptable. * Input: n - number of pixels in the span * x, y - location of leftmost pixel in span * z - array [n] of z values * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) * Output: mask - array [n] of flags (1=stencil and depth test passed) * Return: GL_FALSE - all fragments failed the testing * GL_TRUE - one or more fragments passed the testing * */ static GLboolean stencil_and_ztest_span(GLcontext *ctx, struct sw_span *span, GLuint face) { SWcontext *swrast = SWRAST_CONTEXT(ctx); GLstencil stencilRow[MAX_WIDTH]; GLstencil *stencil; const GLuint n = span->end; const GLint x = span->x; const GLint y = span->y; GLubyte *mask = span->array->mask; ASSERT((span->arrayMask & SPAN_XY) == 0); ASSERT(ctx->Stencil.Enabled); ASSERT(n <= MAX_WIDTH); #ifdef DEBUG if (ctx->Depth.Test) { ASSERT(span->arrayMask & SPAN_Z); } #endif /* Get initial stencil values */ if (swrast->Driver.WriteStencilSpan) { /* Get stencil values from the hardware stencil buffer */ ASSERT(swrast->Driver.ReadStencilSpan); (*swrast->Driver.ReadStencilSpan)(ctx, n, x, y, stencilRow); stencil = stencilRow; } else { /* Get pointer into software stencil buffer */ stencil = STENCIL_ADDRESS(x, y); } /* * Apply the stencil test to the fragments. * failMask[i] is 1 if the stencil test failed. */ if (do_stencil_test( ctx, face, n, stencil, mask ) == GL_FALSE) { /* all fragments failed the stencil test, we're done. */ span->writeAll = GL_FALSE; return GL_FALSE; } /* * Some fragments passed the stencil test, apply depth test to them * and apply Zpass and Zfail stencil ops. */ if (ctx->Depth.Test == GL_FALSE) { /* * No depth buffer, just apply zpass stencil function to active pixels. */ apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, mask ); } else { /* * Perform depth buffering, then apply zpass or zfail stencil function. */ GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH]; GLuint i; /* save the current mask bits */ MEMCPY(oldmask, mask, n * sizeof(GLubyte)); /* apply the depth test */ _swrast_depth_test_span(ctx, span); /* Set the stencil pass/fail flags according to result of depth testing. * if oldmask[i] == 0 then * Don't touch the stencil value * else if oldmask[i] and newmask[i] then * Depth test passed * else * assert(oldmask[i] && !newmask[i]) * Depth test failed * endif */ for (i=0;i<n;i++) { ASSERT(mask[i] == 0 || mask[i] == 1); passmask[i] = oldmask[i] & mask[i]; failmask[i] = oldmask[i] & (mask[i] ^ 1); } /* apply the pass and fail operations */ if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { apply_stencil_op( ctx, ctx->Stencil.ZFailFunc[face], face, n, stencil, failmask ); } if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, passmask ); } } /* * Write updated stencil values back into hardware stencil buffer. */ if (swrast->Driver.WriteStencilSpan) { ASSERT(stencil == stencilRow); (swrast->Driver.WriteStencilSpan)(ctx, n, x, y, stencil, mask ); } span->writeAll = GL_FALSE; return GL_TRUE; /* one or more fragments passed both tests */ }
/** * /return GL_TRUE = one or more fragments passed, * GL_FALSE = all fragments failed. */ GLboolean _swrast_stencil_and_ztest_span(struct gl_context *ctx, SWspan *span) { struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; const GLint stencilOffset = get_stencil_offset(rb->Format); const GLint stencilStride = _mesa_get_format_bytes(rb->Format); const GLuint face = (span->facing == 0) ? 0 : ctx->Stencil._BackFace; const GLuint count = span->end; GLubyte *mask = span->array->mask; GLubyte stencilTemp[MAX_WIDTH]; GLubyte *stencilBuf; if (span->arrayMask & SPAN_XY) { /* read stencil values from random locations */ get_s8_values(ctx, rb, count, span->array->x, span->array->y, stencilTemp); stencilBuf = stencilTemp; } else { /* Processing a horizontal run of pixels. Since stencil is always * 8 bits for all MESA_FORMATs, we just need to use the right offset * and stride to access them. */ stencilBuf = _swrast_pixel_address(rb, span->x, span->y) + stencilOffset; } /* * Apply the stencil test to the fragments. * failMask[i] is 1 if the stencil test failed. */ if (!do_stencil_test(ctx, face, count, stencilBuf, mask, stencilStride)) { /* all fragments failed the stencil test, we're done. */ span->writeAll = GL_FALSE; if (span->arrayMask & SPAN_XY) { /* need to write the updated stencil values back to the buffer */ put_s8_values(ctx, rb, count, span->array->x, span->array->y, stencilTemp); } return GL_FALSE; } /* * Some fragments passed the stencil test, apply depth test to them * and apply Zpass and Zfail stencil ops. */ if (ctx->Depth.Test == GL_FALSE || ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer == NULL) { /* * No depth buffer, just apply zpass stencil function to active pixels. */ apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, count, stencilBuf, mask, stencilStride); } else { /* * Perform depth buffering, then apply zpass or zfail stencil function. */ GLubyte passMask[MAX_WIDTH], failMask[MAX_WIDTH], origMask[MAX_WIDTH]; /* save the current mask bits */ memcpy(origMask, mask, count * sizeof(GLubyte)); /* apply the depth test */ _swrast_depth_test_span(ctx, span); compute_pass_fail_masks(count, origMask, mask, passMask, failMask); /* apply the pass and fail operations */ if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face, count, stencilBuf, failMask, stencilStride); } if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, count, stencilBuf, passMask, stencilStride); } } /* Write updated stencil values back into hardware stencil buffer */ if (span->arrayMask & SPAN_XY) { put_s8_values(ctx, rb, count, span->array->x, span->array->y, stencilBuf); } span->writeAll = GL_FALSE; return GL_TRUE; /* one or more fragments passed both tests */ }
/** * Apply stencil and depth testing to an array of pixels. * This is used both for software and hardware stencil buffers. * * The comments in this function are a bit sparse but the code is * almost identical to stencil_and_ztest_span(), which is well * commented. * * Input: n - number of pixels in the array * x, y - array of [n] pixel positions * z - array [n] of z values * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) * Output: mask - array [n] of flags (1=stencil and depth test passed) * Return: GL_FALSE - all fragments failed the testing * GL_TRUE - one or more fragments passed the testing */ static GLboolean stencil_and_ztest_pixels( GLcontext *ctx, SWspan *span, GLuint face ) { struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_renderbuffer *rb = fb->_StencilBuffer; const GLuint n = span->end; const GLint *x = span->array->x; const GLint *y = span->array->y; GLubyte *mask = span->array->mask; ASSERT(span->arrayMask & SPAN_XY); ASSERT(ctx->Stencil.Enabled); ASSERT(n <= MAX_WIDTH); if (!rb->GetPointer(ctx, rb, 0, 0)) { /* No direct access */ GLstencil stencil[MAX_WIDTH]; GLubyte origMask[MAX_WIDTH]; ASSERT(rb->DataType == GL_UNSIGNED_BYTE); _swrast_get_values(ctx, rb, n, x, y, stencil, sizeof(GLubyte)); _mesa_memcpy(origMask, mask, n * sizeof(GLubyte)); (void) do_stencil_test(ctx, face, n, stencil, mask); if (ctx->Depth.Test == GL_FALSE) { apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, mask); } else { _swrast_depth_test_span(ctx, span); if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { GLubyte failmask[MAX_WIDTH]; GLuint i; for (i = 0; i < n; i++) { ASSERT(mask[i] == 0 || mask[i] == 1); failmask[i] = origMask[i] & (mask[i] ^ 1); } apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face, n, stencil, failmask); } if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { GLubyte passmask[MAX_WIDTH]; GLuint i; for (i = 0; i < n; i++) { ASSERT(mask[i] == 0 || mask[i] == 1); passmask[i] = origMask[i] & mask[i]; } apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, passmask); } } /* Write updated stencil values into hardware stencil buffer */ rb->PutValues(ctx, rb, n, x, y, stencil, origMask); return GL_TRUE; } else { /* Direct access to stencil buffer */ if (stencil_test_pixels(ctx, face, n, x, y, mask) == GL_FALSE) { /* all fragments failed the stencil test, we're done. */ return GL_FALSE; } if (ctx->Depth.Test==GL_FALSE) { apply_stencil_op_to_pixels(ctx, n, x, y, ctx->Stencil.ZPassFunc[face], face, mask); } else { GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH]; GLuint i; _mesa_memcpy(oldmask, mask, n * sizeof(GLubyte)); _swrast_depth_test_span(ctx, span); for (i=0;i<n;i++) { ASSERT(mask[i] == 0 || mask[i] == 1); passmask[i] = oldmask[i] & mask[i]; failmask[i] = oldmask[i] & (mask[i] ^ 1); } if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { apply_stencil_op_to_pixels(ctx, n, x, y, ctx->Stencil.ZFailFunc[face], face, failmask); } if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { apply_stencil_op_to_pixels(ctx, n, x, y, ctx->Stencil.ZPassFunc[face], face, passmask); } } return GL_TRUE; /* one or more fragments passed both tests */ } }
/** * Apply stencil and depth testing to the span of pixels. * Both software and hardware stencil buffers are acceptable. * Input: n - number of pixels in the span * x, y - location of leftmost pixel in span * z - array [n] of z values * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) * Output: mask - array [n] of flags (1=stencil and depth test passed) * Return: GL_FALSE - all fragments failed the testing * GL_TRUE - one or more fragments passed the testing * */ static GLboolean stencil_and_ztest_span(GLcontext *ctx, SWspan *span, GLuint face) { struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_renderbuffer *rb = fb->_StencilBuffer; GLstencil stencilRow[MAX_WIDTH]; GLstencil *stencil; const GLuint n = span->end; const GLint x = span->x; const GLint y = span->y; GLubyte *mask = span->array->mask; ASSERT((span->arrayMask & SPAN_XY) == 0); ASSERT(ctx->Stencil.Enabled); ASSERT(n <= MAX_WIDTH); #ifdef DEBUG if (ctx->Depth.Test) { ASSERT(span->arrayMask & SPAN_Z); } #endif stencil = (GLstencil *) rb->GetPointer(ctx, rb, x, y); if (!stencil) { rb->GetRow(ctx, rb, n, x, y, stencilRow); stencil = stencilRow; } /* * Apply the stencil test to the fragments. * failMask[i] is 1 if the stencil test failed. */ if (do_stencil_test( ctx, face, n, stencil, mask ) == GL_FALSE) { /* all fragments failed the stencil test, we're done. */ span->writeAll = GL_FALSE; if (!rb->GetPointer(ctx, rb, 0, 0)) { /* put updated stencil values into buffer */ rb->PutRow(ctx, rb, n, x, y, stencil, NULL); } return GL_FALSE; } /* * Some fragments passed the stencil test, apply depth test to them * and apply Zpass and Zfail stencil ops. */ if (ctx->Depth.Test == GL_FALSE) { /* * No depth buffer, just apply zpass stencil function to active pixels. */ apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, mask ); } else { /* * Perform depth buffering, then apply zpass or zfail stencil function. */ GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH]; GLuint i; /* save the current mask bits */ _mesa_memcpy(oldmask, mask, n * sizeof(GLubyte)); /* apply the depth test */ _swrast_depth_test_span(ctx, span); /* Set the stencil pass/fail flags according to result of depth testing. * if oldmask[i] == 0 then * Don't touch the stencil value * else if oldmask[i] and newmask[i] then * Depth test passed * else * assert(oldmask[i] && !newmask[i]) * Depth test failed * endif */ for (i=0;i<n;i++) { ASSERT(mask[i] == 0 || mask[i] == 1); passmask[i] = oldmask[i] & mask[i]; failmask[i] = oldmask[i] & (mask[i] ^ 1); } /* apply the pass and fail operations */ if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { apply_stencil_op( ctx, ctx->Stencil.ZFailFunc[face], face, n, stencil, failmask ); } if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, passmask ); } } /* * Write updated stencil values back into hardware stencil buffer. */ if (!rb->GetPointer(ctx, rb, 0, 0)) { rb->PutRow(ctx, rb, n, x, y, stencil, NULL); } span->writeAll = GL_FALSE; return GL_TRUE; /* one or more fragments passed both tests */ }
/** * Apply stencil and depth testing to the span of pixels. * Both software and hardware stencil buffers are acceptable. * Input: n - number of pixels in the span * x, y - location of leftmost pixel in span * z - array [n] of z values * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) * Output: mask - array [n] of flags (1=stencil and depth test passed) * Return: GL_FALSE - all fragments failed the testing * GL_TRUE - one or more fragments passed the testing * */ static GLboolean stencil_and_ztest_span(struct gl_context *ctx, SWspan *span, GLuint face) { struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_renderbuffer *rb = fb->_StencilBuffer; GLubyte stencilRow[MAX_WIDTH]; GLubyte *stencil; const GLuint n = span->end; const GLint x = span->x; const GLint y = span->y; GLubyte *mask = span->array->mask; ASSERT((span->arrayMask & SPAN_XY) == 0); ASSERT(ctx->Stencil.Enabled); ASSERT(n <= MAX_WIDTH); #ifdef DEBUG if (ctx->Depth.Test) { ASSERT(span->arrayMask & SPAN_Z); } #endif stencil = (GLubyte *) rb->GetPointer(ctx, rb, x, y); if (!stencil) { rb->GetRow(ctx, rb, n, x, y, stencilRow); stencil = stencilRow; } /* * Apply the stencil test to the fragments. * failMask[i] is 1 if the stencil test failed. */ if (do_stencil_test( ctx, face, n, stencil, mask ) == GL_FALSE) { /* all fragments failed the stencil test, we're done. */ span->writeAll = GL_FALSE; if (!rb->GetPointer(ctx, rb, 0, 0)) { /* put updated stencil values into buffer */ rb->PutRow(ctx, rb, n, x, y, stencil, NULL); } return GL_FALSE; } /* * Some fragments passed the stencil test, apply depth test to them * and apply Zpass and Zfail stencil ops. */ if (ctx->Depth.Test == GL_FALSE || ctx->DrawBuffer->_DepthBuffer == NULL) { /* * No depth buffer, just apply zpass stencil function to active pixels. */ apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, mask ); } else { /* * Perform depth buffering, then apply zpass or zfail stencil function. */ GLubyte passMask[MAX_WIDTH], failMask[MAX_WIDTH], origMask[MAX_WIDTH]; /* save the current mask bits */ memcpy(origMask, mask, n * sizeof(GLubyte)); /* apply the depth test */ _swrast_depth_test_span(ctx, span); compute_pass_fail_masks(n, origMask, mask, passMask, failMask); /* apply the pass and fail operations */ if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { apply_stencil_op( ctx, ctx->Stencil.ZFailFunc[face], face, n, stencil, failMask ); } if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, passMask ); } } /* * Write updated stencil values back into hardware stencil buffer. */ if (!rb->GetPointer(ctx, rb, 0, 0)) { rb->PutRow(ctx, rb, n, x, y, stencil, NULL); } span->writeAll = GL_FALSE; return GL_TRUE; /* one or more fragments passed both tests */ }