static void unconvert_teximage_al88( struct gl_texture_convert *convert ) { const GLubyte *src = (const GLubyte *)convert->srcImage; GLint texels, i; texels = convert->width * convert->height * convert->depth; switch ( convert->format ) { case GL_LUMINANCE_ALPHA: MEMCPY( convert->dstImage, src, texels * 2 ); break; case GL_ALPHA: { GLubyte *dst = (GLubyte *)convert->dstImage; for ( i = 0 ; i < texels ; i++ ) { *dst++ = src[1]; src += 2; } break; } case GL_LUMINANCE: { GLubyte *dst = (GLubyte *)convert->dstImage; for ( i = 0 ; i < texels ; i++ ) { *dst++ = src[0]; src += 2; } break; } default: gl_problem(NULL, "texture unconvert error"); } }
static void unconvert_teximage_argb8888( struct gl_texture_convert *convert ) { const GLubyte *src = (const GLubyte *)convert->srcImage; GLint texels, i; texels = convert->width * convert->height * convert->depth; switch ( convert->format ) { case GL_RGBA: { GLuint *dst = (GLuint *)convert->dstImage; for ( i = 0 ; i < texels ; i++ ) { *dst++ = PACK_COLOR_8888( src[3], src[0], src[1], src[2] ); src += 4; } break; } case GL_RGB: { GLubyte *dst = (GLubyte *)convert->dstImage; for ( i = 0 ; i < texels ; i++ ) { *dst++ = src[2]; *dst++ = src[1]; *dst++ = src[0]; src += 4; } break; } default: gl_problem(NULL, "texture unconvert error"); } }
static void unconvert_teximage_rgb565( struct gl_texture_convert *convert ) { const GLushort *src = (const GLushort *)convert->srcImage; GLubyte *dst = (GLubyte *)convert->dstImage; GLint texels, i; texels = convert->width * convert->height * convert->depth; switch ( convert->format ) { case GL_RGBA: for ( i = 0 ; i < texels ; i++ ) { GLushort s = *src++; *dst++ = ((s >> 8) & 0xf8) * 255 / 0xf8; *dst++ = ((s >> 3) & 0xfc) * 255 / 0xfc; *dst++ = ((s << 3) & 0xf8) * 255 / 0xf8; *dst++ = 0xff; } break; case GL_RGB: for ( i = 0 ; i < texels ; i++ ) { GLushort s = *src++; *dst++ = ((s >> 8) & 0xf8) * 255 / 0xf8; *dst++ = ((s >> 3) & 0xfc) * 255 / 0xfc; *dst++ = ((s << 3) & 0xf8) * 255 / 0xf8; } break; default: gl_problem(NULL, "texture unconvert error"); } }
void gl_test_all_normal_transform_functions( char *description ) { int masked; int mtype; long benchmark_tab[0xf][0x4]; static int first_time = 1; if ( first_time ) { first_time = 0; mesa_profile = getenv( "MESA_PROFILE" ); } #ifdef RUN_XFORM_BENCHMARK if ( mesa_profile ) { if ( need_counter ) { need_counter = 0; INIT_COUNTER(); printf( "counter overhead: %ld cycles\n\n", counter_overhead ); } printf( "normal transform results after hooking in %s functions:\n", description ); } #endif for ( masked = 0 ; masked <= 1 ; masked++ ) { int cma = masked ? CULL_MASK_ACTIVE : 0; char *cmastring = masked ? "CULL_MASK_ACTIVE" : "0"; #ifdef RUN_XFORM_BENCHMARK if ( mesa_profile ) { printf( "\n culling: %s \n", masked ? "CULL_MASK_ACTIVE" : "0" ); printf( "\n-------------------------------------------------------\n" ); } #endif for ( mtype = 0 ; mtype < 8 ; mtype++ ) { normal_func func = gl_normal_tab[norm_types[mtype]][cma]; long *cycles = &(benchmark_tab[mtype][cma]); if ( test_norm_function( func, mtype, masked, cycles ) == 0 ) { char buf[100]; sprintf( buf, "gl_normal_tab[%s][%s] failed test (%s)", cmastring, norm_strings[mtype], description ); gl_problem( NULL, buf ); } #ifdef RUN_XFORM_BENCHMARK if ( mesa_profile ) { printf( " %li\t", benchmark_tab[mtype][cma] ); printf( " | [%s]\n", norm_strings[mtype] ); } } if ( mesa_profile ) printf( "\n" ); #else } #endif }
/* * Apply the alpha test to a span of pixels. * In: rgba - array of pixels * In/Out: mask - current pixel mask. Pixels which fail the alpha test * will set the corresponding mask flag to 0. * Return: 0 = all pixels in the span failed the alpha test. * 1 = one or more pixels passed the alpha test. */ GLint _mesa_alpha_test( const GLcontext *ctx, GLuint n, CONST GLubyte rgba[][4], GLubyte mask[] ) { GLuint i; GLubyte ref = ctx->Color.AlphaRef; /* switch cases ordered from most frequent to less frequent */ switch (ctx->Color.AlphaFunc) { case GL_LESS: for (i=0;i<n;i++) { mask[i] &= (rgba[i][ACOMP] < ref); } return 1; case GL_LEQUAL: for (i=0;i<n;i++) { mask[i] &= (rgba[i][ACOMP] <= ref); } return 1; case GL_GEQUAL: for (i=0;i<n;i++) { mask[i] &= (rgba[i][ACOMP] >= ref); } return 1; case GL_GREATER: for (i=0;i<n;i++) { mask[i] &= (rgba[i][ACOMP] > ref); } return 1; case GL_NOTEQUAL: for (i=0;i<n;i++) { mask[i] &= (rgba[i][ACOMP] != ref); } return 1; case GL_EQUAL: for (i=0;i<n;i++) { mask[i] &= (rgba[i][ACOMP] == ref); } return 1; case GL_ALWAYS: /* do nothing */ return 1; case GL_NEVER: /* caller should check for zero! */ return 0; default: gl_problem( ctx, "Invalid alpha test in gl_alpha_test" ); return 0; } /* Never get here */ /*return 1;*/ }
static void unconvert_teximage_ci8( struct gl_texture_convert *convert ) { const GLubyte *src = (const GLubyte *)convert->srcImage; GLint texels; texels = convert->width * convert->height * convert->depth; switch ( convert->format ) { case GL_ALPHA: case GL_LUMINANCE: case GL_INTENSITY: case GL_COLOR_INDEX: MEMCPY( convert->dstImage, src, texels ); break; default: gl_problem(NULL, "texture unconvert error"); } }
static void unconvert_teximage_rgb332( struct gl_texture_convert *convert ) { gl_problem(NULL, "texture unconvert error"); }
static int test_transform_function( transform_func func, int psize, int mtype, int masked, long *cycles ) { GLvector4f source[1], dest[1], ref[1]; GLmatrix mat[1]; GLfloat *m; GLubyte mask[TEST_COUNT]; int i, j; #ifdef RUN_XFORM_BENCHMARK int cycle_i; /* the counter for the benchmarks we run */ #endif (void) cycles; if ( psize > 4 ) { gl_problem( NULL, "test_transform_function called with psize > 4\n" ); return 0; } mat->m = (GLfloat *) ALIGN_MALLOC( 16 * sizeof(GLfloat), 16 ); mat->type = mtypes[mtype]; m = mat->m; m[0] = 63.0; m[4] = 43.0; m[ 8] = 29.0; m[12] = 43.0; m[1] = 55.0; m[5] = 17.0; m[ 9] = 31.0; m[13] = 7.0; m[2] = 44.0; m[6] = 9.0; m[10] = 7.0; m[14] = 3.0; m[3] = 11.0; m[7] = 23.0; m[11] = 91.0; m[15] = 9.0; for ( i = 0 ; i < 4 ; i++ ) { for ( j = 0 ; j < 4 ; j++ ) { switch ( templates[mtype][i * 4 + j] ) { case NIL: m[j * 4 + i] = 0.0; break; case ONE: m[j * 4 + i] = 1.0; break; case NEG: m[j * 4 + i] = -1.0; break; case VAR: break; default: abort(); } } } for ( i = 0 ; i < TEST_COUNT ; i++) { mask[i] = i % 2; /* mask every 2nd element */ d[i][0] = s[i][0] = 0.0; d[i][1] = s[i][1] = 0.0; d[i][2] = s[i][2] = 0.0; d[i][3] = s[i][3] = 1.0; for ( j = 0 ; j < psize ; j++ ) s[i][j] = rnd(); } source->data = (GLfloat(*)[4])s; source->start = (GLfloat *)s; source->count = TEST_COUNT; source->stride = sizeof(s[0]); source->size = 4; source->flags = 0; dest->data = (GLfloat(*)[4])d; dest->start = (GLfloat *)d; dest->count = TEST_COUNT; dest->stride = sizeof(float[4]); dest->size = 0; dest->flags = 0; ref->data = (GLfloat(*)[4])r; ref->start = (GLfloat *)r; ref->count = TEST_COUNT; ref->stride = sizeof(float[4]); ref->size = 0; ref->flags = 0; ref_transform( ref, mat, source, NULL, 0 ); if ( mesa_profile ) { if ( masked ) { BEGIN_RACE( *cycles ); func( dest, mat->m, source, mask, 1 ); END_RACE( *cycles ); } else { BEGIN_RACE( *cycles ); func( dest, mat->m, source, NULL, 0 ); END_RACE( *cycles ); } } else { if ( masked ) { func( dest, mat->m, source, mask, 1 ); } else { func( dest, mat->m, source, NULL, 0 ); } } for ( i = 0 ; i < TEST_COUNT ; i++ ) { if ( masked && (mask[i] & 1) ) continue; for ( j = 0 ; j < 4 ; j++ ) { if ( significand_match( d[i][j], r[i][j] ) < REQUIRED_PRECISION ) { printf( "-----------------------------\n" ); printf( "(i = %i, j = %i)\n", i, j ); printf( "%f \t %f \t [diff = %e - %i bit missed]\n", d[i][0], r[i][0], r[i][0]-d[i][0], MAX_PRECISION - significand_match( d[i][0], r[i][0] ) ); printf( "%f \t %f \t [diff = %e - %i bit missed]\n", d[i][1], r[i][1], r[i][1]-d[i][1], MAX_PRECISION - significand_match( d[i][1], r[i][1] ) ); printf( "%f \t %f \t [diff = %e - %i bit missed]\n", d[i][2], r[i][2], r[i][2]-d[i][2], MAX_PRECISION - significand_match( d[i][2], r[i][2] ) ); printf( "%f \t %f \t [diff = %e - %i bit missed]\n", d[i][3], r[i][3], r[i][3]-d[i][3], MAX_PRECISION - significand_match( d[i][3], r[i][3] ) ); return 0; } } } ALIGN_FREE( mat->m ); return 1; }
/* * glDepthFunc( any ) and glDepthMask( GL_TRUE or GL_FALSE ). */ void gl_depth_test_pixels_generic( GLcontext* ctx, GLuint n, const GLint x[], const GLint y[], const GLdepth z[], GLubyte mask[] ) { register GLdepth *zptr; register GLuint i; /* switch cases ordered from most frequent to less frequent */ switch (ctx->Depth.Func) { case GL_LESS: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); if (z[i] < *zptr) { /* pass */ *zptr = z[i]; } else { /* fail */ mask[i] = 0; } } } } else { /* Don't update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); if (z[i] < *zptr) { /* pass */ } else { /* fail */ mask[i] = 0; } } } } break; case GL_LEQUAL: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); if (z[i] <= *zptr) { /* pass */ *zptr = z[i]; } else { /* fail */ mask[i] = 0; } } } } else { /* Don't update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); if (z[i] <= *zptr) { /* pass */ } else { /* fail */ mask[i] = 0; } } } } break; case GL_GEQUAL: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); if (z[i] >= *zptr) { /* pass */ *zptr = z[i]; } else { /* fail */ mask[i] = 0; } } } } else { /* Don't update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); if (z[i] >= *zptr) { /* pass */ } else { /* fail */ mask[i] = 0; } } } } break; case GL_GREATER: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); if (z[i] > *zptr) { /* pass */ *zptr = z[i]; } else { /* fail */ mask[i] = 0; } } } } else { /* Don't update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); if (z[i] > *zptr) { /* pass */ } else { /* fail */ mask[i] = 0; } } } } break; case GL_NOTEQUAL: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); if (z[i] != *zptr) { /* pass */ *zptr = z[i]; } else { /* fail */ mask[i] = 0; } } } } else { /* Don't update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); if (z[i] != *zptr) { /* pass */ } else { /* fail */ mask[i] = 0; } } } } break; case GL_EQUAL: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); if (z[i] == *zptr) { /* pass */ *zptr = z[i]; } else { /* fail */ mask[i] = 0; } } } } else { /* Don't update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); if (z[i] == *zptr) { /* pass */ } else { /* fail */ mask[i] = 0; } } } } break; case GL_ALWAYS: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0; i<n; i++) { if (mask[i]) { zptr = Z_ADDRESS(ctx,x[i],y[i]); *zptr = z[i]; } } } else { /* Don't update Z buffer or mask */ } break; case GL_NEVER: /* depth test never passes */ for (i=0;i<n;i++) { mask[i] = 0; } break; default: gl_problem(ctx, "Bad depth func in gl_depth_test_pixels_generic"); } /*switch*/ }
/* * glDepthFunc( any ) and glDepthMask( GL_TRUE or GL_FALSE ). */ GLuint gl_depth_test_span_generic( GLcontext* ctx, GLuint n, GLint x, GLint y, const GLdepth z[], GLubyte mask[] ) { GLdepth *zptr = Z_ADDRESS( ctx, x, y ); GLubyte *m = mask; GLuint i; GLuint passed = 0; /* switch cases ordered from most frequent to less frequent */ switch (ctx->Depth.Func) { case GL_LESS: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0; i<n; i++,zptr++,m++) { if (*m) { if (z[i] < *zptr) { /* pass */ *zptr = z[i]; passed++; } else { /* fail */ *m = 0; } } } } else { /* Don't update Z buffer */ for (i=0; i<n; i++,zptr++,m++) { if (*m) { if (z[i] < *zptr) { /* pass */ passed++; } else { *m = 0; } } } } break; case GL_LEQUAL: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0;i<n;i++,zptr++,m++) { if (*m) { if (z[i] <= *zptr) { *zptr = z[i]; passed++; } else { *m = 0; } } } } else { /* Don't update Z buffer */ for (i=0;i<n;i++,zptr++,m++) { if (*m) { if (z[i] <= *zptr) { /* pass */ passed++; } else { *m = 0; } } } } break; case GL_GEQUAL: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0;i<n;i++,zptr++,m++) { if (*m) { if (z[i] >= *zptr) { *zptr = z[i]; passed++; } else { *m = 0; } } } } else { /* Don't update Z buffer */ for (i=0;i<n;i++,zptr++,m++) { if (*m) { if (z[i] >= *zptr) { /* pass */ passed++; } else { *m = 0; } } } } break; case GL_GREATER: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0;i<n;i++,zptr++,m++) { if (*m) { if (z[i] > *zptr) { *zptr = z[i]; passed++; } else { *m = 0; } } } } else { /* Don't update Z buffer */ for (i=0;i<n;i++,zptr++,m++) { if (*m) { if (z[i] > *zptr) { /* pass */ passed++; } else { *m = 0; } } } } break; case GL_NOTEQUAL: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0;i<n;i++,zptr++,m++) { if (*m) { if (z[i] != *zptr) { *zptr = z[i]; passed++; } else { *m = 0; } } } } else { /* Don't update Z buffer */ for (i=0;i<n;i++,zptr++,m++) { if (*m) { if (z[i] != *zptr) { /* pass */ passed++; } else { *m = 0; } } } } break; case GL_EQUAL: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0;i<n;i++,zptr++,m++) { if (*m) { if (z[i] == *zptr) { *zptr = z[i]; passed++; } else { *m =0; } } } } else { /* Don't update Z buffer */ for (i=0;i<n;i++,zptr++,m++) { if (*m) { if (z[i] == *zptr) { /* pass */ passed++; } else { *m =0; } } } } break; case GL_ALWAYS: if (ctx->Depth.Mask) { /* Update Z buffer */ for (i=0;i<n;i++,zptr++,m++) { if (*m) { *zptr = z[i]; passed++; } } } else { /* Don't update Z buffer or mask */ passed = n; } break; case GL_NEVER: for (i=0;i<n;i++) { mask[i] = 0; } break; default: gl_problem(ctx, "Bad depth func in gl_depth_test_span_generic"); } /*switch*/ return passed; }
/* * Apply stencil test to an array of pixels before depth buffering. * Used for software stencil buffer only. * Input: n - number of pixels in the span * x, y - array of [n] pixels to stencil * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel * Output: mask - pixels which fail the stencil test will have their * mask flag set to 0. * Return: 0 = all pixels failed, 1 = zero or more pixels passed. */ static GLboolean stencil_test_pixels( GLcontext *ctx, GLuint n, const GLint x[], const GLint y[], GLubyte mask[] ) { GLubyte fail[PB_SIZE]; GLstencil r, s; GLuint i; GLboolean allfail = GL_FALSE; ASSERT(!ctx->Driver.WriteStencilSpan); /* software stencil buffer only! */ /* * Perform stencil test. The results of this operation are stored * in the fail[] array: * IF fail[i] is non-zero THEN * the stencil fail operator is to be applied * ELSE * the stencil fail operator is not to be applied * ENDIF */ switch (ctx->Stencil.Function) { case GL_NEVER: /* always fail */ for (i=0;i<n;i++) { if (mask[i]) { mask[i] = 0; fail[i] = 1; } else { fail[i] = 0; } } allfail = GL_TRUE; break; case GL_LESS: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); s = (GLstencil) (*sptr & ctx->Stencil.ValueMask); if (r < s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_LEQUAL: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); s = (GLstencil) (*sptr & ctx->Stencil.ValueMask); if (r <= s) { /* pass */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_GREATER: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); s = (GLstencil) (*sptr & ctx->Stencil.ValueMask); if (r > s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_GEQUAL: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); s = (GLstencil) (*sptr & ctx->Stencil.ValueMask); if (r >= s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_EQUAL: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); s = (GLstencil) (*sptr & ctx->Stencil.ValueMask); if (r == s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_NOTEQUAL: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); s = (GLstencil) (*sptr & ctx->Stencil.ValueMask); if (r != s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_ALWAYS: /* always pass */ for (i=0;i<n;i++) { fail[i] = 0; } break; default: gl_problem(ctx, "Bad stencil func in gl_stencil_pixels"); return 0; } if (ctx->Stencil.FailFunc != GL_KEEP) { apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail ); } return !allfail; }
/* * Apply the given stencil operator for each pixel in the array whose * mask flag is set. 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, GLuint n, const GLint x[], const GLint y[], GLenum oper, const GLubyte mask[] ) { const GLstencil ref = ctx->Stencil.Ref; const GLstencil wrtmask = ctx->Stencil.WriteMask; const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask); GLuint i; ASSERT(!ctx->Driver.WriteStencilSpan); /* software stencil buffer only! */ switch (oper) { case GL_KEEP: /* do nothing */ break; case GL_ZERO: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = 0; } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) (invmask & *sptr); } } } break; case GL_REPLACE: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = ref; } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref)); } } } break; case GL_INCR: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); if (*sptr < STENCIL_MAX) { *sptr = (GLstencil) (*sptr + 1); } } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); if (*sptr < STENCIL_MAX) { *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1))); } } } } break; case GL_DECR: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); if (*sptr>0) { *sptr = (GLstencil) (*sptr - 1); } } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); if (*sptr>0) { *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1))); } } } } break; case GL_INCR_WRAP_EXT: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) (*sptr + 1); } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1))); } } } break; case GL_DECR_WRAP_EXT: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) (*sptr - 1); } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1))); } } } break; case GL_INVERT: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) (~*sptr); } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr)); } } } break; default: gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels"); } }
/* * Apply stencil test to an array of stencil values (before depth buffering). * Input: n - number of pixels in the array * stencil - array of [n] stencil values * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel * Output: mask - pixels which fail the stencil test will have their * mask flag set to 0. * stencil - updated stencil values (where the test passed) * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed. */ static GLboolean do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[], GLubyte mask[] ) { GLubyte fail[PB_SIZE]; GLboolean allfail = GL_FALSE; GLuint i; GLstencil r, s; ASSERT(n <= PB_SIZE); /* * Perform stencil test. The results of this operation are stored * in the fail[] array: * IF fail[i] is non-zero THEN * the stencil fail operator is to be applied * ELSE * the stencil fail operator is not to be applied * ENDIF */ switch (ctx->Stencil.Function) { case GL_NEVER: /* always fail */ for (i=0;i<n;i++) { if (mask[i]) { mask[i] = 0; fail[i] = 1; } else { fail[i] = 0; } } allfail = GL_TRUE; break; case GL_LESS: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); if (r < s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_LEQUAL: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); if (r <= s) { /* pass */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_GREATER: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); if (r > s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_GEQUAL: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); if (r >= s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_EQUAL: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); if (r == s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_NOTEQUAL: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); if (r != s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_ALWAYS: /* always pass */ for (i=0;i<n;i++) { fail[i] = 0; } break; default: gl_problem(ctx, "Bad stencil func in gl_stencil_span"); return 0; } if (ctx->Stencil.FailFunc != GL_KEEP) { apply_stencil_op( ctx, ctx->Stencil.FailFunc, n, stencil, fail ); } return !allfail; }
/* * 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 * 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[] ) { const GLstencil ref = ctx->Stencil.Ref; const GLstencil wrtmask = ctx->Stencil.WriteMask; const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask); GLuint i; switch (oper) { case GL_KEEP: /* do nothing */ break; case GL_ZERO: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { stencil[i] = 0; } } } else { for (i=0;i<n;i++) { if (mask[i]) { stencil[i] = (GLstencil) (stencil[i] & invmask); } } } break; case GL_REPLACE: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { stencil[i] = ref; } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; stencil[i] = (GLstencil) ((invmask & s ) | (wrtmask & ref)); } } } break; case GL_INCR: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; if (s < STENCIL_MAX) { stencil[i] = (GLstencil) (s+1); } } } } else { for (i=0;i<n;i++) { if (mask[i]) { /* VERIFY logic of adding 1 to a write-masked value */ GLstencil s = stencil[i]; if (s < STENCIL_MAX) { stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1))); } } } } break; case GL_DECR: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; if (s>0) { stencil[i] = (GLstencil) (s-1); } } } } else { for (i=0;i<n;i++) { if (mask[i]) { /* VERIFY logic of subtracting 1 to a write-masked value */ GLstencil s = stencil[i]; if (s>0) { stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1))); } } } } break; case GL_INCR_WRAP_EXT: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { stencil[i]++; } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1))); } } } break; case GL_DECR_WRAP_EXT: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { stencil[i]--; } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1))); } } } break; case GL_INVERT: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; stencil[i] = (GLstencil) ~s; } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & ~s)); } } } break; default: gl_problem(ctx, "Bad stencil op in apply_stencil_op"); } }
/* * Apply stencil test to a span of pixels before depth buffering. * Input: n - number of pixels in the span * x, y - coordinate of left-most pixel in the span * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel * Output: mask - pixels which fail the stencil test will have their * mask flag set to 0. * Return: 0 = all pixels failed, 1 = zero or more pixels passed. */ GLint gl_stencil_span( GLcontext *ctx, GLuint n, GLint x, GLint y, GLubyte mask[] ) { GLubyte fail[MAX_WIDTH]; GLint allfail = 0; GLuint i; GLstencil r, s; GLstencil *stencil; stencil = STENCIL_ADDRESS( x, y ); /* * Perform stencil test. The results of this operation are stored * in the fail[] array: * IF fail[i] is non-zero THEN * the stencil fail operator is to be applied * ELSE * the stencil fail operator is not to be applied * ENDIF */ switch (ctx->Stencil.Function) { case GL_NEVER: /* always fail */ for (i=0;i<n;i++) { if (mask[i]) { mask[i] = 0; fail[i] = 1; } else { fail[i] = 0; } } allfail = 1; break; case GL_LESS: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); if (r < s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_LEQUAL: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); if (r <= s) { /* pass */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_GREATER: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); if (r > s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_GEQUAL: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); if (r >= s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_EQUAL: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); if (r == s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_NOTEQUAL: r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); if (r != s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_ALWAYS: /* always pass */ for (i=0;i<n;i++) { fail[i] = 0; } break; default: gl_problem(ctx, "Bad stencil func in gl_stencil_span"); return 0; } apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.FailFunc, fail ); return (allfail) ? 0 : 1; }
/* * Apply logic operator to rgba pixels. * Input: ctx - the context * n - number of pixels * mask - pixel mask array * In/Out: src - incoming pixels which will be modified * Input: dest - frame buffer values * * Note: Since the R, G, B, and A channels are all treated the same we * process them as 4-byte GLuints instead of four GLubytes. */ static void rgba_logicop( const GLcontext *ctx, GLuint n, const GLubyte mask[], GLuint src[], const GLuint dest[] ) { GLuint i; switch (ctx->Color.LogicOp) { case GL_CLEAR: for (i=0;i<n;i++) { if (mask[i]) { src[i] = 0; } } break; case GL_SET: for (i=0;i<n;i++) { if (mask[i]) { src[i] = 0xffffffff; } } break; case GL_COPY: /* do nothing */ break; case GL_COPY_INVERTED: for (i=0;i<n;i++) { if (mask[i]) { src[i] = ~src[i]; } } break; case GL_NOOP: for (i=0;i<n;i++) { if (mask[i]) { src[i] = dest[i]; } } break; case GL_INVERT: for (i=0;i<n;i++) { if (mask[i]) { src[i] = ~dest[i]; } } break; case GL_AND: for (i=0;i<n;i++) { if (mask[i]) { src[i] &= dest[i]; } } break; case GL_NAND: for (i=0;i<n;i++) { if (mask[i]) { src[i] = ~(src[i] & src[i]); } } break; case GL_OR: for (i=0;i<n;i++) { if (mask[i]) { src[i]|= dest[i]; } } break; case GL_NOR: for (i=0;i<n;i++) { if (mask[i]) { src[i] = ~(src[i] | dest[i]); } } break; case GL_XOR: for (i=0;i<n;i++) { if (mask[i]) { src[i] ^= dest[i]; } } break; case GL_EQUIV: for (i=0;i<n;i++) { if (mask[i]) { src[i] = ~(src[i] ^ dest[i]); } } break; case GL_AND_REVERSE: for (i=0;i<n;i++) { if (mask[i]) { src[i] = src[i] & ~dest[i]; } } break; case GL_AND_INVERTED: for (i=0;i<n;i++) { if (mask[i]) { src[i] = ~src[i] & dest[i]; } } break; case GL_OR_REVERSE: for (i=0;i<n;i++) { if (mask[i]) { src[i] = src[i] | ~dest[i]; } } break; case GL_OR_INVERTED: for (i=0;i<n;i++) { if (mask[i]) { src[i] = ~src[i] | dest[i]; } } break; default: /* should never happen */ gl_problem(ctx, "Bad function in rgba_logicop"); } }