Ejemplo n.º 1
0
/**
 * 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 */
   }
}
Ejemplo n.º 2
0
/*
 * 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 */
   }
}
Ejemplo n.º 3
0
/**
 * 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 */
   }
}