/** * Apply the current logic operator to a span of RGBA pixels. * We can handle horizontal runs of pixels (spans) or arrays of x/y * pixel coordinates. */ void _swrast_logicop_rgba_span(GLcontext *ctx, struct gl_renderbuffer *rb, const struct sw_span *span, GLchan rgba[][4]) { GLchan dest[MAX_WIDTH][4]; ASSERT(span->end < MAX_WIDTH); ASSERT(span->arrayMask & SPAN_RGBA); ASSERT(rb->DataType == GL_UNSIGNED_BYTE); if (span->arrayMask & SPAN_XY) { _swrast_get_values(ctx, rb, span->end, span->array->x, span->array->y, dest, 4 * sizeof(GLchan)); } else { _swrast_read_rgba_span(ctx, rb, span->end, span->x, span->y, dest); } /* XXX make this a runtime test */ #if CHAN_TYPE == GL_UNSIGNED_BYTE /* treat 4*GLubyte as GLuint */ logicop_uint(ctx, span->end, (GLuint *) rgba, (const GLuint *) dest, span->array->mask); #elif CHAN_TYPE == GL_UNSIGNED_SHORT logicop_ushort(ctx, 4 * span->end, (GLushort *) rgba, (const GLushort *) dest, span->array->mask); #elif CHAN_TYPE == GL_FLOAT logicop_uint(ctx, 4 * span->end, (GLuint *) rgba, (const GLuint *) dest, span->array->mask); #endif (void) logicop_ubyte; (void) logicop_ushort; (void) logicop_uint; }
/* * Apply the current logic operator to a span of CI pixels. This is only * used if the device driver can't do logic ops. */ void _swrast_logicop_ci_span(GLcontext *ctx, struct gl_renderbuffer *rb, const struct sw_span *span, GLuint index[]) { GLuint dest[MAX_WIDTH]; ASSERT(span->end < MAX_WIDTH); ASSERT(rb->DataType == GL_UNSIGNED_INT); /* Read dest values from frame buffer */ if (span->arrayMask & SPAN_XY) { _swrast_get_values(ctx, rb, span->end, span->array->x, span->array->y, dest, sizeof(GLuint)); } else { rb->GetRow(ctx, rb, span->end, span->x, span->y, dest); } logicop_uint(ctx, span->end, index, dest, span->array->mask); }
/** * 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 */ } }