X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fswrast%2Fs_stencil.c;h=dbab6b3c20bc7c5857a92744e3f846077c1e3762;hb=c9b33ecd7c07cace0a6553ccfdaf7b021959c934;hp=af782aa7856eb2acf586b2b79dea34f06e26a247;hpb=22144ab7552f0799bcfca506bf4ffa7f70a06649;p=mesa.git diff --git a/src/mesa/swrast/s_stencil.c b/src/mesa/swrast/s_stencil.c index af782aa7856..dbab6b3c20b 100644 --- a/src/mesa/swrast/s_stencil.c +++ b/src/mesa/swrast/s_stencil.c @@ -1,10 +1,8 @@ -/* $Id: s_stencil.c,v 1.10 2001/03/12 00:48:42 gareth Exp $ */ - /* * Mesa 3-D graphics library - * Version: 3.5 + * Version: 6.5 * - * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -27,15 +25,12 @@ #include "glheader.h" #include "context.h" -#include "macros.h" -#include "mem.h" +#include "imports.h" #include "s_context.h" #include "s_depth.h" -#include "s_pb.h" #include "s_stencil.h" - - +#include "s_span.h" @@ -55,32 +50,24 @@ ENDIF */ - - -/* - * Return the address of a stencil buffer value given the window coords: - */ -#define STENCIL_ADDRESS(X,Y) \ - (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X)) - - - -/* +/** * Apply the given stencil operator to the array of stencil values. * Don't touch stencil[i] if mask[i] is zero. * Input: n - size of stencil array * oper - the stencil buffer operator + * face - 0 or 1 for front or back face operation * stencil - array of stencil values * mask - array [n] of flag: 1=apply operator, 0=don't apply operator * Output: stencil - modified values */ -static void apply_stencil_op( const GLcontext *ctx, GLenum oper, - GLuint n, GLstencil stencil[], - const GLubyte mask[] ) +static void +apply_stencil_op( const GLcontext *ctx, GLenum oper, GLuint face, + GLuint n, GLstencil stencil[], const GLubyte mask[] ) { - const GLstencil ref = ctx->Stencil.Ref; - const GLstencil wrtmask = ctx->Stencil.WriteMask; - const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask); + const GLstencil ref = ctx->Stencil.Ref[face]; + const GLstencil wrtmask = ctx->Stencil.WriteMask[face]; + const GLstencil invmask = (GLstencil) (~wrtmask); + const GLstencil stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; GLuint i; switch (oper) { @@ -125,7 +112,7 @@ static void apply_stencil_op( const GLcontext *ctx, GLenum oper, for (i=0;iStencil.ValueMask[face]; - ASSERT(n <= PB_SIZE); + ASSERT(n <= MAX_WIDTH); /* * Perform stencil test. The results of this operation are stored @@ -256,9 +245,9 @@ do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[], * the stencil fail operator is not to be applied * ENDIF */ - switch (ctx->Stencil.Function) { + switch (ctx->Stencil.Function[face]) { case GL_NEVER: - /* always fail */ + /* never pass; always fail */ for (i=0;iStencil.Ref & ctx->Stencil.ValueMask); + r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;iStencil.ValueMask); + s = (GLstencil) (stencil[i] & valueMask); if (r < s) { /* passed */ fail[i] = 0; @@ -290,10 +279,10 @@ do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[], } break; case GL_LEQUAL: - r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); + r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;iStencil.ValueMask); + s = (GLstencil) (stencil[i] & valueMask); if (r <= s) { /* pass */ fail[i] = 0; @@ -309,10 +298,10 @@ do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[], } break; case GL_GREATER: - r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); + r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;iStencil.ValueMask); + s = (GLstencil) (stencil[i] & valueMask); if (r > s) { /* passed */ fail[i] = 0; @@ -328,10 +317,10 @@ do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[], } break; case GL_GEQUAL: - r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); + r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;iStencil.ValueMask); + s = (GLstencil) (stencil[i] & valueMask); if (r >= s) { /* passed */ fail[i] = 0; @@ -347,10 +336,10 @@ do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[], } break; case GL_EQUAL: - r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); + r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;iStencil.ValueMask); + s = (GLstencil) (stencil[i] & valueMask); if (r == s) { /* passed */ fail[i] = 0; @@ -366,10 +355,10 @@ do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[], } break; case GL_NOTEQUAL: - r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); + r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;iStencil.ValueMask); + s = (GLstencil) (stencil[i] & valueMask); if (r != s) { /* passed */ fail[i] = 0; @@ -395,8 +384,8 @@ do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[], return 0; } - if (ctx->Stencil.FailFunc != GL_KEEP) { - apply_stencil_op( ctx, ctx->Stencil.FailFunc, n, stencil, fail ); + if (ctx->Stencil.FailFunc[face] != GL_KEEP) { + apply_stencil_op( ctx, ctx->Stencil.FailFunc[face], face, n, stencil, fail ); } return !allfail; @@ -404,47 +393,68 @@ do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[], - -/* - * Apply stencil and depth testing to an array of pixels. - * Hardware or software stencil buffer acceptable. +/** + * 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 - * 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 + * 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, GLuint n, GLint x, GLint y, - const GLdepth z[], GLstencil stencil[], - GLubyte mask[] ) +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 <= PB_SIZE); + 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, n, stencil, mask ) == GL_FALSE) { + 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) { + 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 ); + apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, mask ); } else { /* @@ -454,10 +464,10 @@ stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y, GLuint i; /* save the current mask bits */ - MEMCPY(oldmask, mask, n * sizeof(GLubyte)); + _mesa_memcpy(oldmask, mask, n * sizeof(GLubyte)); /* apply the depth test */ - _mesa_depth_test_span(ctx, n, x, y, z, mask); + _swrast_depth_test_span(ctx, span); /* Set the stencil pass/fail flags according to result of depth testing. * if oldmask[i] == 0 then @@ -476,87 +486,63 @@ stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y, } /* 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.ZFailFunc[face] != GL_KEEP) { + apply_stencil_op( ctx, ctx->Stencil.ZFailFunc[face], face, + n, stencil, failmask ); } - if (ctx->Stencil.ZPassFunc != GL_KEEP) { - apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask ); + 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_TRUE - all fragments failed the testing - * GL_FALSE - one or more fragments passed the testing - * + * Return the address of a stencil buffer value given the window coords: */ -GLboolean -_mesa_stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y, - const GLdepth z[], GLubyte mask[] ) -{ - GLstencil stencilRow[MAX_WIDTH]; - GLstencil *stencil; - GLboolean result; +#define STENCIL_ADDRESS(X, Y) (stencilStart + (Y) * stride + (X)) - ASSERT(ctx->Stencil.Enabled); - ASSERT(n <= MAX_WIDTH); - - /* Get initial stencil values */ - if (ctx->Driver.WriteStencilSpan) { - ASSERT(ctx->Driver.ReadStencilSpan); - /* Get stencil values from the hardware stencil buffer */ - (*ctx->Driver.ReadStencilSpan)(ctx, n, x, y, stencilRow); - stencil = stencilRow; - } - else { - /* software stencil buffer */ - stencil = STENCIL_ADDRESS(x, y); - } - /* do all the stencil/depth testing/updating */ - result = stencil_and_ztest_span( ctx, n, x, y, z, stencil, mask ); - if (ctx->Driver.WriteStencilSpan) { - /* Write updated stencil values into hardware stencil buffer */ - (ctx->Driver.WriteStencilSpan)(ctx, n, x, y, stencil, mask ); - } - - return result; -} - - - - -/* +/** * Apply the given stencil operator for each pixel in the array whose - * mask flag is set. This is for software stencil buffers only. + * mask flag is set. + * \note This is for software stencil buffers only. * Input: n - number of pixels in the span * x, y - array of [n] pixels * operator - the stencil buffer operator * mask - array [n] of flag: 1=apply operator, 0=don't apply operator */ static void -apply_stencil_op_to_pixels( const GLcontext *ctx, +apply_stencil_op_to_pixels( GLcontext *ctx, GLuint n, const GLint x[], const GLint y[], - GLenum oper, const GLubyte mask[] ) + GLenum oper, GLuint face, const GLubyte mask[] ) { - const GLstencil ref = ctx->Stencil.Ref; - const GLstencil wrtmask = ctx->Stencil.WriteMask; - const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask); + struct gl_framebuffer *fb = ctx->DrawBuffer; + struct gl_renderbuffer *rb = fb->_StencilBuffer; + const GLstencil stencilMax = (1 << fb->Visual.stencilBits) - 1; + const GLstencil ref = ctx->Stencil.Ref[face]; + const GLstencil wrtmask = ctx->Stencil.WriteMask[face]; + const GLstencil invmask = (GLstencil) (~wrtmask); GLuint i; + GLstencil *stencilStart = (GLubyte *) rb->Data; + const GLuint stride = rb->Width; - ASSERT(!ctx->Driver.WriteStencilSpan); /* software stencil buffer only! */ + ASSERT(rb->GetPointer(ctx, rb, 0, 0)); + ASSERT(sizeof(GLstencil) == 1); switch (oper) { case GL_KEEP: @@ -603,7 +589,7 @@ apply_stencil_op_to_pixels( const GLcontext *ctx, for (i=0;iDrawBuffer; + struct gl_renderbuffer *rb = fb->_StencilBuffer; + GLubyte fail[MAX_WIDTH]; GLstencil r, s; GLuint i; GLboolean allfail = GL_FALSE; + const GLuint valueMask = ctx->Stencil.ValueMask[face]; + const GLstencil *stencilStart = (GLstencil *) rb->Data; + const GLuint stride = rb->Width; - ASSERT(!ctx->Driver.WriteStencilSpan); /* software stencil buffer only! */ + ASSERT(rb->GetPointer(ctx, rb, 0, 0)); + ASSERT(sizeof(GLstencil) == 1); /* * Perform stencil test. The results of this operation are stored @@ -734,7 +727,7 @@ stencil_test_pixels( GLcontext *ctx, GLuint n, * ENDIF */ - switch (ctx->Stencil.Function) { + switch (ctx->Stencil.Function[face]) { case GL_NEVER: /* always fail */ for (i=0;iStencil.Ref & ctx->Stencil.ValueMask); + r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;iStencil.ValueMask); + const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); + s = (GLstencil) (*sptr & valueMask); if (r < s) { /* passed */ fail[i] = 0; @@ -769,11 +762,11 @@ stencil_test_pixels( GLcontext *ctx, GLuint n, } break; case GL_LEQUAL: - r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); + r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;iStencil.ValueMask); + const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); + s = (GLstencil) (*sptr & valueMask); if (r <= s) { /* pass */ fail[i] = 0; @@ -789,11 +782,11 @@ stencil_test_pixels( GLcontext *ctx, GLuint n, } break; case GL_GREATER: - r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); + r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;iStencil.ValueMask); + const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); + s = (GLstencil) (*sptr & valueMask); if (r > s) { /* passed */ fail[i] = 0; @@ -809,11 +802,11 @@ stencil_test_pixels( GLcontext *ctx, GLuint n, } break; case GL_GEQUAL: - r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); + r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;iStencil.ValueMask); + const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); + s = (GLstencil) (*sptr & valueMask); if (r >= s) { /* passed */ fail[i] = 0; @@ -829,11 +822,11 @@ stencil_test_pixels( GLcontext *ctx, GLuint n, } break; case GL_EQUAL: - r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); + r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;iStencil.ValueMask); + const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); + s = (GLstencil) (*sptr & valueMask); if (r == s) { /* passed */ fail[i] = 0; @@ -849,11 +842,11 @@ stencil_test_pixels( GLcontext *ctx, GLuint n, } break; case GL_NOTEQUAL: - r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); + r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;iStencil.ValueMask); + const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); + s = (GLstencil) (*sptr & valueMask); if (r != s) { /* passed */ fail[i] = 0; @@ -879,8 +872,9 @@ stencil_test_pixels( GLcontext *ctx, GLuint n, return 0; } - if (ctx->Stencil.FailFunc != GL_KEEP) { - apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail ); + if (ctx->Stencil.FailFunc[face] != GL_KEEP) { + apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc[face], + face, fail ); } return !allfail; @@ -889,7 +883,7 @@ stencil_test_pixels( GLcontext *ctx, GLuint n, -/* +/** * Apply stencil and depth testing to an array of pixels. * This is used both for software and hardware stencil buffers. * @@ -902,81 +896,88 @@ stencil_test_pixels( GLcontext *ctx, GLuint n, * 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 + * Return: GL_FALSE - all fragments failed the testing + * GL_TRUE - 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[] ) +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 <= PB_SIZE); + ASSERT(n <= MAX_WIDTH); - if (ctx->Driver.WriteStencilPixels) { - /*** Hardware stencil buffer ***/ - GLstencil stencil[PB_SIZE]; - GLubyte origMask[PB_SIZE]; + if (!rb->GetPointer(ctx, rb, 0, 0)) { + /* No direct access */ + GLstencil stencil[MAX_WIDTH]; + GLubyte origMask[MAX_WIDTH]; - ASSERT(ctx->Driver.ReadStencilPixels); - (*ctx->Driver.ReadStencilPixels)(ctx, n, x, y, stencil); + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + _swrast_get_values(ctx, rb, n, x, y, stencil, sizeof(GLubyte)); - MEMCPY(origMask, mask, n * sizeof(GLubyte)); + _mesa_memcpy(origMask, mask, n * sizeof(GLubyte)); - (void) do_stencil_test(ctx, n, stencil, mask); + (void) do_stencil_test(ctx, face, n, stencil, mask); if (ctx->Depth.Test == GL_FALSE) { - apply_stencil_op(ctx, ctx->Stencil.ZPassFunc, n, stencil, mask); + apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, + n, stencil, mask); } else { - _mesa_depth_test_pixels(ctx, n, x, y, z, mask); + _swrast_depth_test_span(ctx, span); - if (ctx->Stencil.ZFailFunc != GL_KEEP) { - GLubyte failmask[PB_SIZE]; + 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, + apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face, n, stencil, failmask); } - if (ctx->Stencil.ZPassFunc != GL_KEEP) { - GLubyte passmask[PB_SIZE]; + 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, + apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, passmask); } } /* Write updated stencil values into hardware stencil buffer */ - (ctx->Driver.WriteStencilPixels)(ctx, n, x, y, stencil, origMask); + rb->PutValues(ctx, rb, n, x, y, stencil, origMask); return GL_TRUE; } else { - /*** Software stencil buffer ***/ + /* Direct access to stencil buffer */ - if (stencil_test_pixels(ctx, n, x, y, mask) == GL_FALSE) { + 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, mask); + ctx->Stencil.ZPassFunc[face], face, mask); } else { - GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE]; + GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH]; GLuint i; - MEMCPY(oldmask, mask, n * sizeof(GLubyte)); + _mesa_memcpy(oldmask, mask, n * sizeof(GLubyte)); - _mesa_depth_test_pixels(ctx, n, x, y, z, mask); + _swrast_depth_test_span(ctx, span); for (i=0;iStencil.ZFailFunc != GL_KEEP) { + if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { apply_stencil_op_to_pixels(ctx, n, x, y, - ctx->Stencil.ZFailFunc, failmask); + ctx->Stencil.ZFailFunc[face], + face, failmask); } - if (ctx->Stencil.ZPassFunc != GL_KEEP) { + if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { apply_stencil_op_to_pixels(ctx, n, x, y, - ctx->Stencil.ZPassFunc, passmask); + ctx->Stencil.ZPassFunc[face], + face, passmask); } } @@ -999,8 +1002,56 @@ _mesa_stencil_and_ztest_pixels( GLcontext *ctx, } +/** + * /return GL_TRUE = one or more fragments passed, + * GL_FALSE = all fragments failed. + */ +GLboolean +_swrast_stencil_and_ztest_span(GLcontext *ctx, SWspan *span) +{ + /* span->facing can only be non-zero if using two-sided stencil */ + ASSERT(ctx->Stencil._TestTwoSide || span->facing == 0); + if (span->arrayMask & SPAN_XY) + return stencil_and_ztest_pixels(ctx, span, span->facing); + else + return stencil_and_ztest_span(ctx, span, span->facing); +} + + +#if 0 +GLuint +clip_span(GLuint bufferWidth, GLuint bufferHeight, + GLint x, GLint y, GLuint *count) +{ + GLuint n = *count; + GLuint skipPixels = 0; -/* + if (y < 0 || y >= bufferHeight || x + n <= 0 || x >= bufferWidth) { + /* totally out of bounds */ + n = 0; + } + else { + /* left clip */ + if (x < 0) { + skipPixels = -x; + x = 0; + n -= skipPixels; + } + /* right clip */ + if (x + n > bufferWidth) { + GLint dx = x + n - bufferWidth; + n -= dx; + } + } + + *count = n; + + return skipPixels; +} +#endif + + +/** * Return a span of stencil values from the stencil buffer. * Used for glRead/CopyPixels * Input: n - how many pixels @@ -1008,11 +1059,10 @@ _mesa_stencil_and_ztest_pixels( GLcontext *ctx, * Output: stencil - the array of stencil values */ void -_mesa_read_stencil_span( GLcontext *ctx, - GLint n, GLint x, GLint y, GLstencil stencil[] ) +_swrast_read_stencil_span(GLcontext *ctx, struct gl_renderbuffer *rb, + GLint n, GLint x, GLint y, GLstencil stencil[]) { - if (y < 0 || y >= ctx->DrawBuffer->Height || - x + n <= 0 || x >= ctx->DrawBuffer->Width) { + if (y < 0 || y >= rb->Height || x + n <= 0 || x >= rb->Width) { /* span is completely outside framebuffer */ return; /* undefined values OK */ } @@ -1023,281 +1073,188 @@ _mesa_read_stencil_span( GLcontext *ctx, n -= dx; stencil += dx; } - if (x + n > ctx->DrawBuffer->Width) { - GLint dx = x + n - ctx->DrawBuffer->Width; + if (x + n > rb->Width) { + GLint dx = x + n - rb->Width; n -= dx; } if (n <= 0) { return; } - - ASSERT(n >= 0); - if (ctx->Driver.ReadStencilSpan) { - (*ctx->Driver.ReadStencilSpan)( ctx, (GLuint) n, x, y, stencil ); - } - else if (ctx->DrawBuffer->Stencil) { - const GLstencil *s = STENCIL_ADDRESS( x, y ); -#if STENCIL_BITS == 8 - MEMCPY( stencil, s, n * sizeof(GLstencil) ); -#else - GLuint i; - for (i=0;iGetRow(ctx, rb, n, x, y, stencil); } -/* - * Write a span of stencil values to the stencil buffer. +/** + * Write a span of stencil values to the stencil buffer. This function + * applies the stencil write mask when needed. * Used for glDraw/CopyPixels * Input: n - how many pixels * x, y - location of first pixel * stencil - the array of stencil values */ void -_mesa_write_stencil_span( GLcontext *ctx, GLint n, GLint x, GLint y, - const GLstencil stencil[] ) +_swrast_write_stencil_span(GLcontext *ctx, GLint n, GLint x, GLint y, + const GLstencil stencil[] ) { - if (y < 0 || y >= ctx->DrawBuffer->Height || - x + n <= 0 || x >= ctx->DrawBuffer->Width) { + struct gl_framebuffer *fb = ctx->DrawBuffer; + struct gl_renderbuffer *rb = fb->_StencilBuffer; + const GLuint stencilMax = (1 << fb->Visual.stencilBits) - 1; + const GLuint stencilMask = ctx->Stencil.WriteMask[0]; + + if (y < 0 || y >= rb->Height || x + n <= 0 || x >= rb->Width) { /* span is completely outside framebuffer */ return; /* undefined values OK */ } - if (x < 0) { GLint dx = -x; x = 0; n -= dx; stencil += dx; } - if (x + n > ctx->DrawBuffer->Width) { - GLint dx = x + n - ctx->DrawBuffer->Width; + if (x + n > rb->Width) { + GLint dx = x + n - rb->Width; n -= dx; } if (n <= 0) { return; } - if (ctx->Driver.WriteStencilSpan) { - (*ctx->Driver.WriteStencilSpan)( ctx, n, x, y, stencil, NULL ); + if ((stencilMask & stencilMax) != stencilMax) { + /* need to apply writemask */ + GLstencil destVals[MAX_WIDTH], newVals[MAX_WIDTH]; + GLint i; + rb->GetRow(ctx, rb, n, x, y, destVals); + for (i = 0; i < n; i++) { + newVals[i] + = (stencil[i] & stencilMask) | (destVals[i] & ~stencilMask); + } + rb->PutRow(ctx, rb, n, x, y, newVals, NULL); } - else if (ctx->DrawBuffer->Stencil) { - GLstencil *s = STENCIL_ADDRESS( x, y ); -#if STENCIL_BITS == 8 - MEMCPY( s, stencil, n * sizeof(GLstencil) ); -#else - GLuint i; - for (i=0;iPutRow(ctx, rb, n, x, y, stencil, NULL); } } -/* - * Allocate a new stencil buffer. If there's an old one it will be - * deallocated first. The new stencil buffer will be uninitialized. +/** + * Clear the stencil buffer. */ void -_mesa_alloc_stencil_buffer( GLcontext *ctx ) -{ - GLuint buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height; - - /* deallocate current stencil buffer if present */ - if (ctx->DrawBuffer->Stencil) { - FREE(ctx->DrawBuffer->Stencil); - ctx->DrawBuffer->Stencil = NULL; - } - - /* allocate new stencil buffer */ - ctx->DrawBuffer->Stencil = (GLstencil *) MALLOC(buffersize * sizeof(GLstencil)); - if (!ctx->DrawBuffer->Stencil) { - /* out of memory */ -/* _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE ); */ - _mesa_error( ctx, GL_OUT_OF_MEMORY, "_mesa_alloc_stencil_buffer" ); - } -} - - - -/* - * Clear the software (malloc'd) stencil buffer. - */ -static void -clear_software_stencil_buffer( GLcontext *ctx ) +_swrast_clear_stencil_buffer( GLcontext *ctx, struct gl_renderbuffer *rb ) { - if (ctx->Visual.stencilBits==0 || !ctx->DrawBuffer->Stencil) { - /* no stencil buffer */ + const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits; + const GLuint mask = ctx->Stencil.WriteMask[0]; + const GLuint invMask = ~mask; + const GLuint clearVal = (ctx->Stencil.Clear & mask); + const GLuint stencilMax = (1 << stencilBits) - 1; + GLint x, y, width, height; + + if (!rb || mask == 0) return; - } - if (ctx->Scissor.Enabled) { - /* clear scissor region only */ - const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; - if (ctx->Stencil.WriteMask != STENCIL_MAX) { - /* must apply mask to the clear */ - GLint y; - for (y = ctx->DrawBuffer->_Ymin; y < ctx->DrawBuffer->_Ymax; y++) { - const GLstencil mask = ctx->Stencil.WriteMask; - const GLstencil invMask = ~mask; - const GLstencil clearVal = (ctx->Stencil.Clear & mask); - GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->_Xmin, y ); - GLint i; - for (i = 0; i < width; i++) { - stencil[i] = (stencil[i] & invMask) | clearVal; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE || + rb->DataType == GL_UNSIGNED_SHORT); + + ASSERT(rb->_BaseFormat == GL_STENCIL_INDEX); + + /* compute region to clear */ + x = ctx->DrawBuffer->_Xmin; + y = ctx->DrawBuffer->_Ymin; + width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; + height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; + + if (rb->GetPointer(ctx, rb, 0, 0)) { + /* Direct buffer access */ + if ((mask & stencilMax) != stencilMax) { + /* need to mask the clear */ + if (rb->DataType == GL_UNSIGNED_BYTE) { + GLint i, j; + for (i = 0; i < height; i++) { + GLubyte *stencil = (GLubyte*) rb->GetPointer(ctx, rb, x, y + i); + for (j = 0; j < width; j++) { + stencil[j] = (stencil[j] & invMask) | clearVal; + } } } - } - else { - /* no masking */ - GLint y; - for (y = ctx->DrawBuffer->_Ymin; y < ctx->DrawBuffer->_Ymax; y++) { - GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->_Xmin, y ); -#if STENCIL_BITS==8 - MEMSET( stencil, ctx->Stencil.Clear, width * sizeof(GLstencil) ); -#else - GLint i; - for (i = 0; i < width; i++) - stencil[x] = ctx->Stencil.Clear; -#endif - } - } - } - else { - /* clear whole stencil buffer */ - if (ctx->Stencil.WriteMask != STENCIL_MAX) { - /* must apply mask to the clear */ - const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height; - GLstencil *stencil = ctx->DrawBuffer->Stencil; - const GLstencil mask = ctx->Stencil.WriteMask; - const GLstencil invMask = ~mask; - const GLstencil clearVal = (ctx->Stencil.Clear & mask); - GLuint i; - for (i = 0; i < n; i++) { - stencil[i] = (stencil[i] & invMask) | clearVal; + else { + GLint i, j; + for (i = 0; i < height; i++) { + GLushort *stencil = (GLushort*) rb->GetPointer(ctx, rb, x, y + i); + for (j = 0; j < width; j++) { + stencil[j] = (stencil[j] & invMask) | clearVal; + } + } } } else { - /* clear whole buffer without masking */ - const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height; - GLstencil *stencil = ctx->DrawBuffer->Stencil; - -#if STENCIL_BITS==8 - MEMSET(stencil, ctx->Stencil.Clear, n * sizeof(GLstencil) ); -#else - GLuint i; - for (i = 0; i < n; i++) { - stencil[i] = ctx->Stencil.Clear; + /* no bit masking */ + if (width == rb->Width && rb->DataType == GL_UNSIGNED_BYTE) { + /* optimized case */ + /* Note: bottom-to-top raster assumed! */ + GLubyte *stencil = (GLubyte *) rb->GetPointer(ctx, rb, x, y); + GLuint len = width * height * sizeof(GLubyte); + _mesa_memset(stencil, clearVal, len); } -#endif - } - } -} - - - -/* - * Clear the hardware (in graphics card) stencil buffer. - * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan() - * functions. - * Actually, if there is a hardware stencil buffer it really should have - * been cleared in Driver.Clear()! However, if the hardware does not - * support scissored clears or masked clears (i.e. glStencilMask) then - * we have to use the span-based functions. - */ -static void -clear_hardware_stencil_buffer( GLcontext *ctx ) -{ - ASSERT(ctx->Driver.WriteStencilSpan); - ASSERT(ctx->Driver.ReadStencilSpan); - - if (ctx->Scissor.Enabled) { - /* clear scissor region only */ - const GLint x = ctx->DrawBuffer->_Xmin; - const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; - if (ctx->Stencil.WriteMask != STENCIL_MAX) { - /* must apply mask to the clear */ - GLint y; - for (y = ctx->DrawBuffer->_Ymin; y < ctx->DrawBuffer->_Ymax; y++) { - const GLstencil mask = ctx->Stencil.WriteMask; - const GLstencil invMask = ~mask; - const GLstencil clearVal = (ctx->Stencil.Clear & mask); - GLstencil stencil[MAX_WIDTH]; + else { + /* general case */ GLint i; - (*ctx->Driver.ReadStencilSpan)(ctx, width, x, y, stencil); - for (i = 0; i < width; i++) { - stencil[i] = (stencil[i] & invMask) | clearVal; + for (i = 0; i < height; i++) { + GLvoid *stencil = rb->GetPointer(ctx, rb, x, y + i); + if (rb->DataType == GL_UNSIGNED_BYTE) { + _mesa_memset(stencil, clearVal, width); + } + else { + _mesa_memset16((short unsigned int*) stencil, clearVal, width); + } } - (*ctx->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL); - } - } - else { - /* no masking */ - GLstencil stencil[MAX_WIDTH]; - GLint y, i; - for (i = 0; i < width; i++) { - stencil[i] = ctx->Stencil.Clear; - } - for (y = ctx->DrawBuffer->_Ymin; y < ctx->DrawBuffer->_Ymax; y++) { - (*ctx->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL); } } } else { - /* clear whole stencil buffer */ - if (ctx->Stencil.WriteMask != STENCIL_MAX) { - /* must apply mask to the clear */ - const GLstencil mask = ctx->Stencil.WriteMask; - const GLstencil invMask = ~mask; - const GLstencil clearVal = (ctx->Stencil.Clear & mask); - const GLint width = ctx->DrawBuffer->Width; - const GLint height = ctx->DrawBuffer->Height; - const GLint x = ctx->DrawBuffer->_Xmin; - GLint y; - for (y = 0; y < height; y++) { - GLstencil stencil[MAX_WIDTH]; - GLint i; - (*ctx->Driver.ReadStencilSpan)(ctx, width, x, y, stencil); - for (i = 0; i < width; i++) { - stencil[i] = (stencil[i] & invMask) | clearVal; + /* no direct access */ + if ((mask & stencilMax) != stencilMax) { + /* need to mask the clear */ + if (rb->DataType == GL_UNSIGNED_BYTE) { + GLint i, j; + for (i = 0; i < height; i++) { + GLubyte stencil[MAX_WIDTH]; + rb->GetRow(ctx, rb, width, x, y + i, stencil); + for (j = 0; j < width; j++) { + stencil[j] = (stencil[j] & invMask) | clearVal; + } + rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL); + } + } + else { + GLint i, j; + for (i = 0; i < height; i++) { + GLushort stencil[MAX_WIDTH]; + rb->GetRow(ctx, rb, width, x, y + i, stencil); + for (j = 0; j < width; j++) { + stencil[j] = (stencil[j] & invMask) | clearVal; + } + rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL); } - (*ctx->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL); } } else { - /* clear whole buffer without masking */ - const GLint width = ctx->DrawBuffer->Width; - const GLint height = ctx->DrawBuffer->Width; - const GLint x = ctx->DrawBuffer->_Xmin; - GLstencil stencil[MAX_WIDTH]; - GLint y, i; - for (i = 0; i < width; i++) { - stencil[i] = ctx->Stencil.Clear; + /* no bit masking */ + const GLubyte clear8 = (GLubyte) clearVal; + const GLushort clear16 = (GLushort) clearVal; + const void *clear; + GLint i; + if (rb->DataType == GL_UNSIGNED_BYTE) { + clear = &clear8; + } + else { + clear = &clear16; } - for (y = 0; y < height; y++) { - (*ctx->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL); + for (i = 0; i < height; i++) { + rb->PutMonoRow(ctx, rb, width, x, y + i, clear, NULL); } } } } - - - -/* - * Clear the stencil buffer. - */ -void -_mesa_clear_stencil_buffer( GLcontext *ctx ) -{ - if (ctx->Driver.WriteStencilSpan) { - ASSERT(ctx->Driver.ReadStencilSpan); - clear_hardware_stencil_buffer(ctx); - } - else { - clear_software_stencil_buffer(ctx); - } -}