-/* $Id: accum.c,v 1.6 1999/10/13 18:42:49 brianp Exp $ */
+/* $Id: accum.c,v 1.17 2000/03/19 01:10:11 brianp Exp $ */
/*
* Mesa 3-D graphics library
- * Version: 3.1
+ * Version: 3.3
*
* Copyright (C) 1999 Brian Paul All Rights Reserved.
*
*/
-/* $XFree86: xc/lib/GL/mesa/src/accum.c,v 1.3 1999/04/04 00:20:17 dawes Exp $ */
-
#ifdef PC_HEADER
#include "all.h"
#else
-#ifndef XFree86Server
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#else
-#include "GL/xf86glx.h"
-#endif
-#include <assert.h>
+#include "glheader.h"
#include "accum.h"
#include "context.h"
-#include "macros.h"
+#include "mem.h"
#include "masking.h"
#include "span.h"
+#include "state.h"
#include "types.h"
-#ifdef XFree86Server
-#include "GL/xf86glx.h"
-#endif
#endif
*/
+#define USE_OPTIMIZED_ACCUM /* enable the optimization */
+
+
-void gl_alloc_accum_buffer( GLcontext *ctx )
+void
+_mesa_alloc_accum_buffer( GLcontext *ctx )
{
GLint n;
- if (ctx->Buffer->Accum) {
- FREE( ctx->Buffer->Accum );
- ctx->Buffer->Accum = NULL;
+ if (ctx->DrawBuffer->Accum) {
+ FREE( ctx->DrawBuffer->Accum );
+ ctx->DrawBuffer->Accum = NULL;
}
/* allocate accumulation buffer if not already present */
- n = ctx->Buffer->Width * ctx->Buffer->Height * 4 * sizeof(GLaccum);
- ctx->Buffer->Accum = (GLaccum *) MALLOC( n );
- if (!ctx->Buffer->Accum) {
+ n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height * 4 * sizeof(GLaccum);
+ ctx->DrawBuffer->Accum = (GLaccum *) MALLOC( n );
+ if (!ctx->DrawBuffer->Accum) {
/* unable to setup accumulation buffer */
gl_error( ctx, GL_OUT_OF_MEMORY, "glAccum" );
}
+#ifdef USE_OPTIMIZED_ACCUM
ctx->IntegerAccumMode = GL_TRUE;
+#else
+ ctx->IntegerAccumMode = GL_FALSE;
+#endif
ctx->IntegerAccumScaler = 0.0;
}
-void gl_ClearAccum( GLcontext *ctx,
- GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha )
+void
+_mesa_ClearAccum( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha )
{
+ GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glAccum");
ctx->Accum.ClearColor[0] = CLAMP( red, -1.0, 1.0 );
*/
static void rescale_accum( GLcontext *ctx )
{
- const GLuint n = ctx->Buffer->Width * ctx->Buffer->Height * 4;
- const GLfloat s = ctx->IntegerAccumScaler * (32767.0 / 255.0);
- GLaccum *accum = ctx->Buffer->Accum;
+ const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height * 4;
+ const GLfloat fChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
+ const GLfloat s = ctx->IntegerAccumScaler * (32767.0 / fChanMax);
+ GLaccum *accum = ctx->DrawBuffer->Accum;
GLuint i;
assert(ctx->IntegerAccumMode);
- assert(sizeof(GLchan) == 1); /* if not true, 255.0 above must be fixed */
assert(accum);
for (i = 0; i < n; i++) {
-void gl_Accum( GLcontext *ctx, GLenum op, GLfloat value )
+void
+_mesa_Accum( GLenum op, GLfloat value )
{
+ GET_CURRENT_CONTEXT(ctx);
GLuint xpos, ypos, width, height, width4;
GLfloat acc_scale;
GLubyte rgba[MAX_WIDTH][4];
+ const GLint iChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
+ const GLfloat fChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glAccum");
- if (ctx->Visual->AccumBits==0 || !ctx->Buffer->Accum) {
- /* No accumulation buffer! */
- gl_warning(ctx, "Calling glAccum() without an accumulation buffer");
+ if (ctx->Visual->AccumBits == 0 || ctx->DrawBuffer != ctx->ReadBuffer) {
+ gl_error(ctx, GL_INVALID_OPERATION, "glAccum");
+ return;
+ }
+
+ if (!ctx->DrawBuffer->Accum) {
+ gl_warning(ctx, "Calling glAccum() without an accumulation buffer (low memory?)");
return;
}
/* whole window */
xpos = 0;
ypos = 0;
- width = ctx->Buffer->Width;
- height = ctx->Buffer->Height;
+ width = ctx->DrawBuffer->Width;
+ height = ctx->DrawBuffer->Height;
}
width4 = 4 * width;
{
const GLaccum intVal = (GLaccum) (value * acc_scale);
GLuint j;
- /* May have to leave optimized accum buffer mode */
+ /* Leave optimized accum buffer mode */
if (ctx->IntegerAccumMode)
rescale_accum(ctx);
for (j = 0; j < height; j++) {
- GLaccum * acc = ctx->Buffer->Accum + ypos * width4 + 4 * xpos;
+ GLaccum * acc = ctx->DrawBuffer->Accum + ypos * width4 + 4 * xpos;
GLuint i;
for (i = 0; i < width4; i++) {
acc[i] += intVal;
case GL_MULT:
{
GLuint j;
- /* May have to leave optimized accum buffer mode */
+ /* Leave optimized accum buffer mode */
if (ctx->IntegerAccumMode)
rescale_accum(ctx);
for (j = 0; j < height; j++) {
- GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + 4 * xpos;
+ GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + 4 * xpos;
GLuint i;
for (i = 0; i < width4; i++) {
acc[i] = (GLaccum) ( (GLfloat) acc[i] * value );
break;
case GL_ACCUM:
- (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Pixel.DriverReadBuffer );
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+ ctx->Pixel.DriverReadBuffer );
/* May have to leave optimized accum buffer mode */
if (ctx->IntegerAccumScaler == 0.0 && value > 0.0 && value <= 1.0)
if (ctx->IntegerAccumMode) {
/* simply add integer color values into accum buffer */
GLuint j;
- GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos * 4;
+ GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
assert(ctx->IntegerAccumScaler > 0.0);
assert(ctx->IntegerAccumScaler <= 1.0);
for (j = 0; j < height; j++) {
GLuint i, i4;
- gl_read_rgba_span(ctx, width, xpos, ypos, rgba);
+ gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
for (i = i4 = 0; i < width; i++, i4+=4) {
acc[i4+0] += rgba[i][RCOMP];
acc[i4+1] += rgba[i][GCOMP];
}
else {
/* scaled integer accum buffer */
- const GLfloat rscale = value * acc_scale / 255.0;
- const GLfloat gscale = value * acc_scale / 255.0;
- const GLfloat bscale = value * acc_scale / 255.0;
- const GLfloat ascale = value * acc_scale / 255.0;
+ const GLfloat rscale = value * acc_scale / fChanMax;
+ const GLfloat gscale = value * acc_scale / fChanMax;
+ const GLfloat bscale = value * acc_scale / fChanMax;
+ const GLfloat ascale = value * acc_scale / fChanMax;
GLuint j;
for (j=0;j<height;j++) {
- GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos * 4;
+ GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
GLuint i;
- gl_read_rgba_span(ctx, width, xpos, ypos, rgba);
+ gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
for (i=0;i<width;i++) {
*acc += (GLaccum) ( (GLfloat) rgba[i][RCOMP] * rscale ); acc++;
*acc += (GLaccum) ( (GLfloat) rgba[i][GCOMP] * gscale ); acc++;
ypos++;
}
}
- (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Color.DriverDrawBuffer );
+ /* restore read buffer = draw buffer (the default) */
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
+ ctx->Color.DriverDrawBuffer );
break;
case GL_LOAD:
- (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Pixel.DriverReadBuffer );
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+ ctx->Pixel.DriverReadBuffer );
/* This is a change to go into optimized accum buffer mode */
if (value > 0.0 && value <= 1.0) {
+#ifdef USE_OPTIMIZED_ACCUM
ctx->IntegerAccumMode = GL_TRUE;
+#else
+ ctx->IntegerAccumMode = GL_FALSE;
+#endif
ctx->IntegerAccumScaler = value;
}
else {
if (ctx->IntegerAccumMode) {
/* just copy values into accum buffer */
GLuint j;
- GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos * 4;
+ GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
assert(ctx->IntegerAccumScaler > 0.0);
assert(ctx->IntegerAccumScaler <= 1.0);
for (j = 0; j < height; j++) {
GLuint i, i4;
- gl_read_rgba_span(ctx, width, xpos, ypos, rgba);
+ gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
for (i = i4 = 0; i < width; i++, i4 += 4) {
acc[i4+0] = rgba[i][RCOMP];
acc[i4+1] = rgba[i][GCOMP];
}
else {
/* scaled integer accum buffer */
- const GLfloat rscale = value * acc_scale / 255.0;
- const GLfloat gscale = value * acc_scale / 255.0;
- const GLfloat bscale = value * acc_scale / 255.0;
- const GLfloat ascale = value * acc_scale / 255.0;
+ const GLfloat rscale = value * acc_scale / fChanMax;
+ const GLfloat gscale = value * acc_scale / fChanMax;
+ const GLfloat bscale = value * acc_scale / fChanMax;
+ const GLfloat ascale = value * acc_scale / fChanMax;
+ const GLfloat d = 3.0 / acc_scale;
GLuint i, j;
for (j = 0; j < height; j++) {
- GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos * 4;
- gl_read_rgba_span(ctx, width, xpos, ypos, rgba);
+ GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
+ gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
for (i=0;i<width;i++) {
- *acc++ = (GLaccum) ( (GLfloat) rgba[i][RCOMP] * rscale );
- *acc++ = (GLaccum) ( (GLfloat) rgba[i][GCOMP] * gscale );
- *acc++ = (GLaccum) ( (GLfloat) rgba[i][BCOMP] * bscale );
- *acc++ = (GLaccum) ( (GLfloat) rgba[i][ACOMP] * ascale );
+ *acc++ = (GLaccum) ((GLfloat) rgba[i][RCOMP] * rscale + d);
+ *acc++ = (GLaccum) ((GLfloat) rgba[i][GCOMP] * gscale + d);
+ *acc++ = (GLaccum) ((GLfloat) rgba[i][BCOMP] * bscale + d);
+ *acc++ = (GLaccum) ((GLfloat) rgba[i][ACOMP] * ascale + d);
}
ypos++;
}
}
- (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Color.DriverDrawBuffer );
+
+ /* restore read buffer = draw buffer (the default) */
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
+ ctx->Color.DriverDrawBuffer );
break;
case GL_RETURN:
if (ctx->IntegerAccumMode && value != 1.0)
rescale_accum(ctx);
- if (ctx->IntegerAccumMode) {
- /* build lookup table to avoid integer divides */
- GLint divisor = (GLint) ((1.0F / ctx->IntegerAccumScaler) + 0.5F);
- static GLubyte divTable[32768];
- static GLint prevDivisor = 0.0;
+ if (ctx->IntegerAccumMode && ctx->IntegerAccumScaler > 0) {
+ /* build lookup table to avoid many floating point multiplies */
+ const GLfloat mult = ctx->IntegerAccumScaler;
+ static GLchan multTable[32768];
+ static GLfloat prevMult = 0.0;
GLuint j;
- if (divisor != prevDivisor) {
- assert(divisor * 256 <= 32768);
- for (j = 0; j < divisor * 256; j++)
- divTable[j] = j / divisor;
- prevDivisor = divisor;
+ const GLint max = (GLint) (256 / mult);
+ if (mult != prevMult) {
+ assert(max <= 32768);
+ for (j = 0; j < max; j++)
+ multTable[j] = (GLint) ((GLfloat) j * mult + 0.5F);
+ prevMult = mult;
}
assert(ctx->IntegerAccumScaler > 0.0);
assert(ctx->IntegerAccumScaler <= 1.0);
for (j = 0; j < height; j++) {
- const GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos*4;
+ const GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos*4;
GLuint i, i4;
for (i = i4 = 0; i < width; i++, i4 += 4) {
- ASSERT(acc[i4+0] < divisor * 256);
- ASSERT(acc[i4+1] < divisor * 256);
- ASSERT(acc[i4+2] < divisor * 256);
- ASSERT(acc[i4+3] < divisor * 256);
- rgba[i][RCOMP] = divTable[acc[i4+0]];
- rgba[i][GCOMP] = divTable[acc[i4+1]];
- rgba[i][BCOMP] = divTable[acc[i4+2]];
- rgba[i][ACOMP] = divTable[acc[i4+3]];
+ ASSERT(acc[i4+0] < max);
+ ASSERT(acc[i4+1] < max);
+ ASSERT(acc[i4+2] < max);
+ ASSERT(acc[i4+3] < max);
+ rgba[i][RCOMP] = multTable[acc[i4+0]];
+ rgba[i][GCOMP] = multTable[acc[i4+1]];
+ rgba[i][BCOMP] = multTable[acc[i4+2]];
+ rgba[i][ACOMP] = multTable[acc[i4+3]];
}
if (ctx->Color.SWmasking) {
gl_mask_rgba_span( ctx, width, xpos, ypos, rgba );
}
}
else {
- const GLfloat rscale = value / acc_scale * 255.0F;
- const GLfloat gscale = value / acc_scale * 255.0F;
- const GLfloat bscale = value / acc_scale * 255.0F;
- const GLfloat ascale = value / acc_scale * 255.0F;
+ const GLfloat rscale = value / acc_scale * fChanMax;
+ const GLfloat gscale = value / acc_scale * fChanMax;
+ const GLfloat bscale = value / acc_scale * fChanMax;
+ const GLfloat ascale = value / acc_scale * fChanMax;
GLuint i, j;
for (j=0;j<height;j++) {
- const GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos*4;
+ const GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos*4;
for (i=0;i<width;i++) {
GLint r, g, b, a;
r = (GLint) ( (GLfloat) (*acc++) * rscale + 0.5F );
g = (GLint) ( (GLfloat) (*acc++) * gscale + 0.5F );
b = (GLint) ( (GLfloat) (*acc++) * bscale + 0.5F );
a = (GLint) ( (GLfloat) (*acc++) * ascale + 0.5F );
- rgba[i][RCOMP] = CLAMP( r, 0, 255 );
- rgba[i][GCOMP] = CLAMP( g, 0, 255 );
- rgba[i][BCOMP] = CLAMP( b, 0, 255 );
- rgba[i][ACOMP] = CLAMP( a, 0, 255 );
+ rgba[i][RCOMP] = CLAMP( r, 0, iChanMax );
+ rgba[i][GCOMP] = CLAMP( g, 0, iChanMax );
+ rgba[i][BCOMP] = CLAMP( b, 0, iChanMax );
+ rgba[i][ACOMP] = CLAMP( a, 0, iChanMax );
}
if (ctx->Color.SWmasking) {
gl_mask_rgba_span( ctx, width, xpos, ypos, rgba );
/*
* Clear the accumulation Buffer.
*/
-void gl_clear_accum_buffer( GLcontext *ctx )
+void
+_mesa_clear_accum_buffer( GLcontext *ctx )
{
GLuint buffersize;
GLfloat acc_scale;
}
/* number of pixels */
- buffersize = ctx->Buffer->Width * ctx->Buffer->Height;
+ buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
- if (!ctx->Buffer->Accum) {
+ if (!ctx->DrawBuffer->Accum) {
/* try to alloc accumulation buffer */
- ctx->Buffer->Accum = (GLaccum *)
+ ctx->DrawBuffer->Accum = (GLaccum *)
MALLOC( buffersize * 4 * sizeof(GLaccum) );
}
- if (ctx->Buffer->Accum) {
+ if (ctx->DrawBuffer->Accum) {
if (ctx->Scissor.Enabled) {
/* Limit clear to scissor box */
GLaccum r, g, b, a;
b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
/* size of region to clear */
- width = 4 * (ctx->Buffer->Xmax - ctx->Buffer->Xmin + 1);
- height = ctx->Buffer->Ymax - ctx->Buffer->Ymin + 1;
+ width = 4 * (ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1);
+ height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin + 1;
/* ptr to first element to clear */
- row = ctx->Buffer->Accum
- + 4 * (ctx->Buffer->Ymin * ctx->Buffer->Width
- + ctx->Buffer->Xmin);
+ row = ctx->DrawBuffer->Accum
+ + 4 * (ctx->DrawBuffer->Ymin * ctx->DrawBuffer->Width
+ + ctx->DrawBuffer->Xmin);
for (j=0;j<height;j++) {
for (i=0;i<width;i+=4) {
row[i+0] = r;
row[i+2] = b;
row[i+3] = a;
}
- row += 4 * ctx->Buffer->Width;
+ row += 4 * ctx->DrawBuffer->Width;
}
}
else {
ctx->Accum.ClearColor[2]==0.0 &&
ctx->Accum.ClearColor[3]==0.0) {
/* Black */
- MEMSET( ctx->Buffer->Accum, 0, buffersize * 4 * sizeof(GLaccum) );
+ MEMSET( ctx->DrawBuffer->Accum, 0, buffersize * 4 * sizeof(GLaccum) );
}
else {
/* Not black */
GLaccum *acc, r, g, b, a;
GLuint i;
- acc = ctx->Buffer->Accum;
+ acc = ctx->DrawBuffer->Accum;
r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
/* update optimized accum state vars */
if (ctx->Accum.ClearColor[0] == 0.0 && ctx->Accum.ClearColor[1] == 0.0 &&
ctx->Accum.ClearColor[2] == 0.0 && ctx->Accum.ClearColor[3] == 0.0) {
+#ifdef USE_OPTIMIZED_ACCUM
ctx->IntegerAccumMode = GL_TRUE;
+#else
+ ctx->IntegerAccumMode = GL_FALSE;
+#endif
ctx->IntegerAccumScaler = 0.0; /* denotes empty accum buffer */
}
else {