X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fswrast%2Fs_stencil.c;h=a8aa1d4b6dc26b805008d69692e85075b53988c1;hb=25ea5ea27e7fa4bd7151723d7549a0c33ac1ceda;hp=775868cb677696475072e2b04ffa63dbc900ad1a;hpb=77df88727cb0a423dd5cb41498c2302d9df4fce7;p=mesa.git diff --git a/src/mesa/swrast/s_stencil.c b/src/mesa/swrast/s_stencil.c index 775868cb677..a8aa1d4b6dc 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.25 2002/08/07 00:45:07 brianp Exp $ */ - /* * Mesa 3-D graphics library - * Version: 4.1 + * Version: 6.5 * - * Copyright (C) 1999-2002 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,12 +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_stencil.h" +#include "s_span.h" @@ -52,30 +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, +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) { @@ -120,7 +112,7 @@ apply_stencil_op( const GLcontext *ctx, GLenum oper, for (i=0;iStencil.ValueMask[face]; ASSERT(n <= MAX_WIDTH); @@ -251,7 +245,7 @@ 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: /* 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; @@ -285,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; @@ -304,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; @@ -323,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; @@ -342,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; @@ -361,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; @@ -390,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; @@ -412,9 +406,10 @@ do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[], * */ static GLboolean -stencil_and_ztest_span(GLcontext *ctx, struct sw_span *span) +stencil_and_ztest_span(GLcontext *ctx, SWspan *span, GLuint face) { - SWcontext *swrast = SWRAST_CONTEXT(ctx); + struct gl_framebuffer *fb = ctx->DrawBuffer; + struct gl_renderbuffer *rb = fb->_StencilBuffer; GLstencil stencilRow[MAX_WIDTH]; GLstencil *stencil; const GLuint n = span->end; @@ -430,26 +425,24 @@ stencil_and_ztest_span(GLcontext *ctx, struct sw_span *span) 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 = (GLstencil *) rb->GetPointer(ctx, rb, x, y); + if (!stencil) { + rb->GetRow(ctx, rb, 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, 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; } @@ -461,7 +454,7 @@ stencil_and_ztest_span(GLcontext *ctx, struct sw_span *span) /* * 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 { /* @@ -471,10 +464,10 @@ stencil_and_ztest_span(GLcontext *ctx, struct sw_span *span) 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, span); + _swrast_depth_test_span(ctx, span); /* Set the stencil pass/fail flags according to result of depth testing. * if oldmask[i] == 0 then @@ -493,20 +486,21 @@ stencil_and_ztest_span(GLcontext *ctx, struct sw_span *span) } /* 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 (swrast->Driver.WriteStencilSpan) { - ASSERT(stencil == stencilRow); - (swrast->Driver.WriteStencilSpan)(ctx, n, x, y, stencil, mask ); + if (!rb->GetPointer(ctx, rb, 0, 0)) { + rb->PutRow(ctx, rb, n, x, y, stencil, NULL); } span->writeAll = GL_FALSE; @@ -516,6 +510,12 @@ stencil_and_ztest_span(GLcontext *ctx, struct sw_span *span) +/* + * Return the address of a stencil buffer value given the window coords: + */ +#define STENCIL_ADDRESS(X, Y) (stencilStart + (Y) * stride + (X)) + + /** * Apply the given stencil operator for each pixel in the array whose @@ -527,16 +527,22 @@ stencil_and_ztest_span(GLcontext *ctx, struct sw_span *span) * 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(!SWRAST_CONTEXT(ctx)->Driver.WriteStencilSpan); /* software stencil buffer only! */ + ASSERT(rb->GetPointer(ctx, rb, 0, 0)); + ASSERT(sizeof(GLstencil) == 1); switch (oper) { case GL_KEEP: @@ -583,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; - /* software stencil buffer only! */ - ASSERT(ctx->DrawBuffer->UseSoftwareStencilBuffer); - ASSERT(!SWRAST_CONTEXT(ctx)->Driver.ReadStencilSpan); - ASSERT(!SWRAST_CONTEXT(ctx)->Driver.WriteStencilSpan); + ASSERT(rb->GetPointer(ctx, rb, 0, 0)); + ASSERT(sizeof(GLstencil) == 1); /* * Perform stencil test. The results of this operation are stored @@ -718,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; @@ -753,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; @@ -773,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; @@ -793,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; @@ -813,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; @@ -833,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; @@ -863,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; @@ -890,85 +900,84 @@ stencil_test_pixels( GLcontext *ctx, GLuint n, * GL_TRUE - one or more fragments passed the testing */ static GLboolean -stencil_and_ztest_pixels( GLcontext *ctx, struct sw_span *span ) +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; - 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 ***/ + if (!rb->GetPointer(ctx, rb, 0, 0)) { + /* No direct access */ GLstencil stencil[MAX_WIDTH]; GLubyte origMask[MAX_WIDTH]; - ASSERT(!ctx->DrawBuffer->UseSoftwareStencilBuffer); - ASSERT(swrast->Driver.ReadStencilPixels); - (*swrast->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_span(ctx, span); + _swrast_depth_test_span(ctx, span); - if (ctx->Stencil.ZFailFunc != GL_KEEP) { + 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) { + 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 */ - (swrast->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 */ - ASSERT(ctx->DrawBuffer->UseSoftwareStencilBuffer); - - 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[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_span(ctx, span); + _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); } } @@ -996,15 +1007,50 @@ stencil_and_ztest_pixels( GLcontext *ctx, struct sw_span *span ) * GL_FALSE = all fragments failed. */ GLboolean -_mesa_stencil_and_ztest_span(GLcontext *ctx, struct sw_span *span) +_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); + return stencil_and_ztest_pixels(ctx, span, span->facing); else - return stencil_and_ztest_span(ctx, span); + 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 @@ -1013,14 +1059,11 @@ _mesa_stencil_and_ztest_span(GLcontext *ctx, struct sw_span *span) * 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[]) { - SWcontext *swrast = SWRAST_CONTEXT(ctx); - const GLint bufWidth = (GLint) ctx->DrawBuffer->Width; - const GLint bufHeight = (GLint) ctx->DrawBuffer->Height; - - if (y < 0 || y >= bufHeight || x + n <= 0 || x >= bufWidth) { + if (y < 0 || y >= (GLint) rb->Height || + x + n <= 0 || x >= (GLint) rb->Width) { /* span is completely outside framebuffer */ return; /* undefined values OK */ } @@ -1031,285 +1074,189 @@ _mesa_read_stencil_span( GLcontext *ctx, n -= dx; stencil += dx; } - if (x + n > bufWidth) { - GLint dx = x + n - bufWidth; + if (x + n > (GLint) rb->Width) { + GLint dx = x + n - rb->Width; n -= dx; } if (n <= 0) { return; } - - ASSERT(n >= 0); - if (swrast->Driver.ReadStencilSpan) { - (*swrast->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[] ) { - SWcontext *swrast = SWRAST_CONTEXT(ctx); - const GLstencil *ssrc = stencil; - const GLint bufWidth = (GLint) ctx->DrawBuffer->Width; - const GLint bufHeight = (GLint) ctx->DrawBuffer->Height; + 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 >= bufHeight || x + n <= 0 || x >= bufWidth) { + if (y < 0 || y >= (GLint) rb->Height || + x + n <= 0 || x >= (GLint) rb->Width) { /* span is completely outside framebuffer */ return; /* undefined values OK */ } - if (x < 0) { GLint dx = -x; x = 0; n -= dx; - ssrc += dx; + stencil += dx; } - if (x + n > bufWidth) { - GLint dx = x + n - bufWidth; + if (x + n > (GLint) rb->Width) { + GLint dx = x + n - rb->Width; n -= dx; } if (n <= 0) { return; } - if (swrast->Driver.WriteStencilSpan) { - (*swrast->Driver.WriteStencilSpan)( ctx, n, x, y, ssrc, 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, ssrc, 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( GLframebuffer *buffer ) +_swrast_clear_stencil_buffer( GLcontext *ctx, struct gl_renderbuffer *rb ) { - /* deallocate current stencil buffer if present */ - if (buffer->Stencil) { - MESA_PBUFFER_FREE(buffer->Stencil); - buffer->Stencil = NULL; - } - - /* allocate new stencil buffer */ - buffer->Stencil = (GLstencil *) - MESA_PBUFFER_ALLOC(buffer->Width * buffer->Height * sizeof(GLstencil)); - if (!buffer->Stencil) { - /* out of memory */ - _mesa_error( NULL, GL_OUT_OF_MEMORY, "_mesa_alloc_stencil_buffer" ); - } -} - - - -/** - * Clear the software (malloc'd) stencil buffer. - */ -static void -clear_software_stencil_buffer( GLcontext *ctx ) -{ - 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 == (GLint) 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 ) -{ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - ASSERT(swrast->Driver.WriteStencilSpan); - ASSERT(swrast->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; - (*swrast->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); + } } - (*swrast->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++) { - (*swrast->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; - (*swrast->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); } - (*swrast->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->Height; - 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; } - for (y = 0; y < height; y++) { - (*swrast->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL); + else { + clear = &clear16; + } + for (i = 0; i < height; i++) { + rb->PutMonoRow(ctx, rb, width, x, y + i, clear, NULL); } } } } - - - -/** - * Clear the stencil buffer (hardware or software). - */ -void -_mesa_clear_stencil_buffer( GLcontext *ctx ) -{ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - if (swrast->Driver.WriteStencilSpan) { - ASSERT(swrast->Driver.ReadStencilSpan); - clear_hardware_stencil_buffer(ctx); - } - else { - clear_software_stencil_buffer(ctx); - } -}