/* * 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 */ } }
/* * When the pixel buffer is full, or needs to be flushed, call this * function. All the pixels in the pixel buffer will be subjected * to texturing, scissoring, stippling, alpha testing, stenciling, * depth testing, blending, and finally written to the frame buffer. */ void _mesa_flush_pb( GLcontext *ctx ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); GLuint RasterMask = swrast->_RasterMask; /* Pixel colors may be changed if any of these raster ops enabled */ const GLuint modBits = FOG_BIT | TEXTURE_BIT | BLEND_BIT | MASKING_BIT | LOGIC_OP_BIT; struct pixel_buffer *PB = swrast->PB; GLubyte mask[PB_SIZE]; if (PB->count == 0) goto CleanUp; /* initialize mask array and clip pixels simultaneously */ { const GLint xmin = ctx->DrawBuffer->_Xmin; const GLint xmax = ctx->DrawBuffer->_Xmax; const GLint ymin = ctx->DrawBuffer->_Ymin; const GLint ymax = ctx->DrawBuffer->_Ymax; const GLuint n = PB->count; GLint *x = PB->x; GLint *y = PB->y; GLuint i; for (i = 0; i < n; i++) { mask[i] = (x[i] >= xmin) & (x[i] < xmax) & (y[i] >= ymin) & (y[i] < ymax); } } if (ctx->Visual.rgbMode) { /* * RGBA COLOR PIXELS */ /* If each pixel can be of a different color... */ if ((RasterMask & modBits) || !PB->mono) { if (PB->mono) { /* copy mono color into rgba array */ GLuint i; for (i = 0; i < PB->count; i++) { COPY_CHAN4(PB->rgba[i], PB->currentColor); } } if (ctx->Texture._ReallyEnabled) { GLchan primary_rgba[PB_SIZE][4]; GLuint texUnit; /* must make a copy of primary colors since they may be modified */ MEMCPY(primary_rgba, PB->rgba, 4 * PB->count * sizeof(GLchan)); for (texUnit = 0; texUnit < ctx->Const.MaxTextureUnits; texUnit++){ _swrast_texture_fragments( ctx, texUnit, PB->count, PB->s[texUnit], PB->t[texUnit], PB->u[texUnit], PB->lambda[texUnit], (CONST GLchan (*)[4]) primary_rgba, PB->rgba ); } } if ((ctx->Fog.ColorSumEnabled || (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR && ctx->Light.Enabled)) && PB->haveSpec) { /* add specular color to primary color */ add_colors( PB->count, PB->rgba, (const GLchan (*)[3]) PB->spec ); } if (ctx->Fog.Enabled) { if (swrast->_PreferPixelFog) _mesa_depth_fog_rgba_pixels( ctx, PB->count, PB->z, PB->rgba ); else _mesa_fog_rgba_pixels( ctx, PB->count, PB->fog, PB->rgba ); } /* Antialias coverage application */ if (PB->haveCoverage) { const GLuint n = PB->count; GLuint i; for (i = 0; i < n; i++) { PB->rgba[i][ACOMP] = (GLchan) (PB->rgba[i][ACOMP] * PB->coverage[i]); } } /* Scissoring already done above */ if (ctx->Color.AlphaEnabled) { if (_mesa_alpha_test( ctx, PB->count, (const GLchan (*)[4]) PB->rgba, mask )==0) { goto CleanUp; } } if (ctx->Stencil.Enabled) { /* first stencil test */ if (_mesa_stencil_and_ztest_pixels(ctx, PB->count, PB->x, PB->y, PB->z, mask) == 0) { goto CleanUp; } } else if (ctx->Depth.Test) { /* regular depth testing */ _mesa_depth_test_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask ); } if (RasterMask & MULTI_DRAW_BIT) { multi_write_rgba_pixels( ctx, PB->count, PB->x, PB->y, (const GLchan (*)[4])PB->rgba, mask ); } else { /* normal case: write to exactly one buffer */ const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); if (ctx->Color.ColorLogicOpEnabled) { _mesa_logicop_rgba_pixels( ctx, PB->count, PB->x, PB->y, PB->rgba, mask); } else if (ctx->Color.BlendEnabled) { _mesa_blend_pixels( ctx, PB->count, PB->x, PB->y, PB->rgba, mask); } if (colorMask == 0x0) { goto CleanUp; } else if (colorMask != 0xffffffff) { _mesa_mask_rgba_pixels(ctx, PB->count, PB->x, PB->y, PB->rgba, mask); } (*swrast->Driver.WriteRGBAPixels)( ctx, PB->count, PB->x, PB->y, (const GLchan (*)[4]) PB->rgba, mask ); if (RasterMask & ALPHABUF_BIT) { _mesa_write_alpha_pixels( ctx, PB->count, PB->x, PB->y, (const GLchan (*)[4]) PB->rgba, mask ); } } } else { /* Same color for all pixels */ /* Scissoring already done above */ if (ctx->Color.AlphaEnabled) { if (_mesa_alpha_test( ctx, PB->count, (const GLchan (*)[4]) PB->rgba, mask )==0) { goto CleanUp; } } if (ctx->Stencil.Enabled) { /* first stencil test */ if (_mesa_stencil_and_ztest_pixels(ctx, PB->count, PB->x, PB->y, PB->z, mask) == 0) { goto CleanUp; } } else if (ctx->Depth.Test) { /* regular depth testing */ _mesa_depth_test_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask ); } if (ctx->Color.DrawBuffer == GL_NONE) { goto CleanUp; } if (RasterMask & MULTI_DRAW_BIT) { if (PB->mono) { /* copy mono color into rgba array */ GLuint i; for (i = 0; i < PB->count; i++) { COPY_CHAN4(PB->rgba[i], PB->currentColor); } } multi_write_rgba_pixels( ctx, PB->count, PB->x, PB->y, (const GLchan (*)[4]) PB->rgba, mask ); } else { /* normal case: write to exactly one buffer */ (*swrast->Driver.WriteMonoRGBAPixels)( ctx, PB->count, PB->x, PB->y, PB->currentColor, mask ); if (RasterMask & ALPHABUF_BIT) { _mesa_write_mono_alpha_pixels( ctx, PB->count, PB->x, PB->y, PB->currentColor[ACOMP], mask ); } } /*** ALL DONE ***/ } } else { /* * COLOR INDEX PIXELS */ /* If we may be writting pixels with different indexes... */ if ((RasterMask & modBits) || !PB->mono) { if (PB->mono) { GLuint i; for (i = 0; i < PB->count; i++) { PB->index[i] = PB->currentIndex; } } if (ctx->Fog.Enabled) { if (swrast->_PreferPixelFog) _mesa_depth_fog_ci_pixels( ctx, PB->count, PB->z, PB->index ); else _mesa_fog_ci_pixels( ctx, PB->count, PB->fog, PB->index ); } /* Antialias coverage application */ if (PB->haveCoverage) { const GLuint n = PB->count; GLuint i; for (i = 0; i < n; i++) { GLint frac = (GLint) (15.0 * PB->coverage[i]); PB->index[i] = (PB->index[i] & ~0xf) | frac; } } /* Scissoring already done above */ if (ctx->Stencil.Enabled) { /* first stencil test */ if (_mesa_stencil_and_ztest_pixels(ctx, PB->count, PB->x, PB->y, PB->z, mask) == 0) { goto CleanUp; } } else if (ctx->Depth.Test) { /* regular depth testing */ _mesa_depth_test_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask ); } if (RasterMask & MULTI_DRAW_BIT) { multi_write_index_pixels( ctx, PB->count, PB->x, PB->y, PB->index, mask ); } else { /* normal case: write to exactly one buffer */ if (ctx->Color.IndexLogicOpEnabled) { _mesa_logicop_ci_pixels(ctx, PB->count, PB->x, PB->y, PB->index, mask); } if (ctx->Color.IndexMask != 0xffffffff) { _mesa_mask_index_pixels(ctx, PB->count, PB->x, PB->y, PB->index, mask); } (*swrast->Driver.WriteCI32Pixels)( ctx, PB->count, PB->x, PB->y, PB->index, mask ); } /*** ALL DONE ***/ } else { /* Same color index for all pixels */ /* Scissoring already done above */ if (ctx->Stencil.Enabled) { /* first stencil test */ if (_mesa_stencil_and_ztest_pixels(ctx, PB->count, PB->x, PB->y, PB->z, mask) == 0) { goto CleanUp; } } else if (ctx->Depth.Test) { /* regular depth testing */ _mesa_depth_test_pixels(ctx, PB->count, PB->x, PB->y, PB->z, mask); } if (RasterMask & MULTI_DRAW_BIT) { multi_write_index_pixels(ctx, PB->count, PB->x, PB->y, PB->index, mask); } else { /* normal case: write to exactly one buffer */ (*swrast->Driver.WriteMonoCIPixels)(ctx, PB->count, PB->x, PB->y, PB->currentIndex, mask); } } } CleanUp: PB->count = 0; PB->mono = GL_TRUE; PB->haveSpec = GL_FALSE; PB->haveCoverage = GL_FALSE; }