X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Faccum.c;h=e2d7726b5047d2ad11b8beca92a1cd7b02e4d108;hb=aab0ea935290cdbf6c74e4d001d4bbc8178fc14a;hp=6ff4e8071a42735d497b1ccba5791ef6031f9724;hpb=941dcc797e1a6317808c1ec43476817286d576ba;p=mesa.git diff --git a/src/mesa/main/accum.c b/src/mesa/main/accum.c index 6ff4e8071a4..e2d7726b504 100644 --- a/src/mesa/main/accum.c +++ b/src/mesa/main/accum.c @@ -1,21 +1,19 @@ -/* $Id: accum.c,v 1.19 2000/04/04 00:54:23 brianp Exp $ */ - /* * Mesa 3-D graphics library - * Version: 3.3 - * - * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. - * + * Version: 6.5 + * + * 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"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -24,502 +22,480 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - -#ifdef PC_HEADER -#include "all.h" -#else #include "glheader.h" #include "accum.h" +#include "condrender.h" #include "context.h" -#include "mem.h" -#include "masking.h" -#include "span.h" +#include "format_unpack.h" +#include "format_pack.h" +#include "imports.h" +#include "macros.h" +#include "mfeatures.h" #include "state.h" -#include "types.h" -#endif +#include "mtypes.h" +#include "main/dispatch.h" -/* - * Accumulation buffer notes - * - * Normally, accumulation buffer values are GLshorts with values in - * [-32767, 32767] which represent floating point colors in [-1, 1], - * as suggested by the OpenGL specification. - * - * We optimize for the common case used for full-scene antialiasing: - * // start with accum buffer cleared to zero - * glAccum(GL_LOAD, w); // or GL_ACCUM the first image - * glAccum(GL_ACCUM, w); - * ... - * glAccum(GL_ACCUM, w); - * glAccum(GL_RETURN, 1.0); - * That is, we start with an empty accumulation buffer and accumulate - * n images, each with weight w = 1/n. - * In this scenario, we can simply store unscaled integer values in - * the accum buffer instead of scaled integers. We'll also keep track - * of the w value so when we do GL_RETURN we simply divide the accumulated - * values by n (=1/w). - * This lets us avoid _many_ int->float->int conversions. - */ +void GLAPIENTRY +_mesa_ClearAccum( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ) +{ + GLfloat tmp[4]; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + tmp[0] = CLAMP( red, -1.0F, 1.0F ); + tmp[1] = CLAMP( green, -1.0F, 1.0F ); + tmp[2] = CLAMP( blue, -1.0F, 1.0F ); + tmp[3] = CLAMP( alpha, -1.0F, 1.0F ); -#define USE_OPTIMIZED_ACCUM /* enable the optimization */ + if (TEST_EQ_4V(tmp, ctx->Accum.ClearColor)) + return; + COPY_4FV( ctx->Accum.ClearColor, tmp ); +} -void -_mesa_alloc_accum_buffer( GLcontext *ctx ) +static void GLAPIENTRY +_mesa_Accum( GLenum op, GLfloat value ) { - GLint n; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - if (ctx->DrawBuffer->Accum) { - FREE( ctx->DrawBuffer->Accum ); - ctx->DrawBuffer->Accum = NULL; + switch (op) { + case GL_ADD: + case GL_MULT: + case GL_ACCUM: + case GL_LOAD: + case GL_RETURN: + /* OK */ + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glAccum(op)"); + return; } - /* allocate accumulation buffer if not already present */ - 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" ); + if (ctx->DrawBuffer->Visual.haveAccumBuffer == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glAccum(no accum buffer)"); + return; } -#ifdef USE_OPTIMIZED_ACCUM - ctx->IntegerAccumMode = GL_TRUE; -#else - ctx->IntegerAccumMode = GL_FALSE; -#endif - ctx->IntegerAccumScaler = 0.0; -} + if (ctx->DrawBuffer != ctx->ReadBuffer) { + /* See GLX_SGI_make_current_read or WGL_ARB_make_current_read, + * or GL_EXT_framebuffer_blit. + */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glAccum(different read/draw buffers)"); + return; + } + if (ctx->NewState) + _mesa_update_state(ctx); -void -_mesa_ClearAccum( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glAccum"); + if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glAccum(incomplete framebuffer)"); + return; + } + + if (ctx->RasterDiscard) + return; - ctx->Accum.ClearColor[0] = CLAMP( red, -1.0, 1.0 ); - ctx->Accum.ClearColor[1] = CLAMP( green, -1.0, 1.0 ); - ctx->Accum.ClearColor[2] = CLAMP( blue, -1.0, 1.0 ); - ctx->Accum.ClearColor[3] = CLAMP( alpha, -1.0, 1.0 ); + if (ctx->RenderMode == GL_RENDER) { + _mesa_accum(ctx, op, value); + } } +void +_mesa_init_accum_dispatch(struct _glapi_table *disp) +{ + SET_Accum(disp, _mesa_Accum); + SET_ClearAccum(disp, _mesa_ClearAccum); +} -/* - * This is called when we fall out of optimized/unscaled accum buffer mode. - * That is, we convert each unscaled accum buffer value into a scaled value - * representing the range[-1, 1]. + +/** + * Clear the accumulation buffer by mapping the renderbuffer and + * writing the clear color to it. Called by the driver's implementation + * of the glClear function. */ -static void rescale_accum( GLcontext *ctx ) +void +_mesa_clear_accum_buffer(struct gl_context *ctx) { - 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; + GLuint x, y, width, height; + GLubyte *accMap; + GLint accRowStride; + struct gl_renderbuffer *accRb; + + if (!ctx->DrawBuffer) + return; - assert(ctx->IntegerAccumMode); - assert(accum); + accRb = ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer; + if (!accRb) + return; /* missing accum buffer, not an error */ - for (i = 0; i < n; i++) { - accum[i] = (GLaccum) (accum[i] * s); + /* bounds, with scissor */ + x = ctx->DrawBuffer->_Xmin; + y = ctx->DrawBuffer->_Ymin; + width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; + height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; + + ctx->Driver.MapRenderbuffer(ctx, accRb, x, y, width, height, + GL_MAP_WRITE_BIT, &accMap, &accRowStride); + + if (!accMap) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); + return; } - ctx->IntegerAccumMode = GL_FALSE; -} + if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) { + const GLshort clearR = FLOAT_TO_SHORT(ctx->Accum.ClearColor[0]); + const GLshort clearG = FLOAT_TO_SHORT(ctx->Accum.ClearColor[1]); + const GLshort clearB = FLOAT_TO_SHORT(ctx->Accum.ClearColor[2]); + const GLshort clearA = FLOAT_TO_SHORT(ctx->Accum.ClearColor[3]); + GLuint i, j; + + for (j = 0; j < height; j++) { + GLshort *row = (GLshort *) accMap; + + for (i = 0; i < width; i++) { + row[i * 4 + 0] = clearR; + row[i * 4 + 1] = clearG; + row[i * 4 + 2] = clearB; + row[i * 4 + 3] = clearA; + } + accMap += accRowStride; + } + } + else { + /* other types someday? */ + _mesa_warning(ctx, "unexpected accum buffer type"); + } + ctx->Driver.UnmapRenderbuffer(ctx, accRb); +} -void -_mesa_Accum( GLenum op, GLfloat value ) +/** + * if (bias) + * Accum += value + * else + * Accum *= value + */ +static void +accum_scale_or_bias(struct gl_context *ctx, GLfloat value, + GLint xpos, GLint ypos, GLint width, GLint height, + GLboolean bias) { - 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->AccumRedBits == 0 || ctx->DrawBuffer != ctx->ReadBuffer) { - gl_error(ctx, GL_INVALID_OPERATION, "glAccum"); - return; - } + struct gl_renderbuffer *accRb = + ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer; + GLubyte *accMap; + GLint accRowStride; + + assert(accRb); + + ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height, + GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, + &accMap, &accRowStride); - if (!ctx->DrawBuffer->Accum) { - gl_warning(ctx, "Calling glAccum() without an accumulation buffer (low memory?)"); + if (!accMap) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); return; } - if (sizeof(GLaccum)==1) { - acc_scale = 127.0; - } - else if (sizeof(GLaccum)==2) { - acc_scale = 32767.0; + if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) { + const GLshort incr = (GLshort) (value * 32767.0f); + GLint i, j; + if (bias) { + for (j = 0; j < height; j++) { + GLshort *acc = (GLshort *) accMap; + for (i = 0; i < 4 * width; i++) { + acc[i] += incr; + } + accMap += accRowStride; + } + } + else { + /* scale */ + for (j = 0; j < height; j++) { + GLshort *acc = (GLshort *) accMap; + for (i = 0; i < 4 * width; i++) { + acc[i] = (GLshort) (acc[i] * value); + } + accMap += accRowStride; + } + } } else { - /* sizeof(GLaccum) > 2 (Cray) */ - acc_scale = (float) SHRT_MAX; + /* other types someday? */ } - if (ctx->NewState) - gl_update_state( ctx ); - - /* Determine region to operate upon. */ - if (ctx->Scissor.Enabled) { - xpos = ctx->Scissor.X; - ypos = ctx->Scissor.Y; - width = ctx->Scissor.Width; - height = ctx->Scissor.Height; + ctx->Driver.UnmapRenderbuffer(ctx, accRb); +} + + +/** + * if (load) + * Accum = ColorBuf * value + * else + * Accum += ColorBuf * value + */ +static void +accum_or_load(struct gl_context *ctx, GLfloat value, + GLint xpos, GLint ypos, GLint width, GLint height, + GLboolean load) +{ + struct gl_renderbuffer *accRb = + ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer; + struct gl_renderbuffer *colorRb = ctx->ReadBuffer->_ColorReadBuffer; + GLubyte *accMap, *colorMap; + GLint accRowStride, colorRowStride; + GLbitfield mappingFlags; + + if (!colorRb) { + /* no read buffer - OK */ + return; } - else { - /* whole window */ - xpos = 0; - ypos = 0; - width = ctx->DrawBuffer->Width; - height = ctx->DrawBuffer->Height; + + assert(accRb); + + mappingFlags = GL_MAP_WRITE_BIT; + if (!load) /* if we're accumulating */ + mappingFlags |= GL_MAP_READ_BIT; + + /* Map accum buffer */ + ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height, + mappingFlags, &accMap, &accRowStride); + if (!accMap) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); + return; } - width4 = 4 * width; + /* Map color buffer */ + ctx->Driver.MapRenderbuffer(ctx, colorRb, xpos, ypos, width, height, + GL_MAP_READ_BIT, + &colorMap, &colorRowStride); + if (!colorMap) { + ctx->Driver.UnmapRenderbuffer(ctx, accRb); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); + return; + } - switch (op) { - case GL_ADD: - { - const GLaccum intVal = (GLaccum) (value * acc_scale); - GLuint j; - /* Leave optimized accum buffer mode */ - if (ctx->IntegerAccumMode) - rescale_accum(ctx); - for (j = 0; j < height; j++) { - GLaccum * acc = ctx->DrawBuffer->Accum + ypos * width4 + 4 * xpos; - GLuint i; - for (i = 0; i < width4; i++) { - acc[i] += intVal; - } - ypos++; - } - } - break; - - case GL_MULT: - { - GLuint j; - /* Leave optimized accum buffer mode */ - if (ctx->IntegerAccumMode) - rescale_accum(ctx); - for (j = 0; j < height; j++) { - GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + 4 * xpos; - GLuint i; - for (i = 0; i < width4; i++) { - acc[i] = (GLaccum) ( (GLfloat) acc[i] * value ); - } - ypos++; - } - } - break; - - case GL_ACCUM: - (*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) - ctx->IntegerAccumScaler = value; - if (ctx->IntegerAccumMode && value != ctx->IntegerAccumScaler) - rescale_accum(ctx); - - if (ctx->IntegerAccumMode) { - /* simply add integer color values into accum buffer */ - GLuint j; - 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, 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]; - acc[i4+2] += rgba[i][BCOMP]; - acc[i4+3] += rgba[i][ACOMP]; + if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) { + const GLfloat scale = value * 32767.0f; + GLint i, j; + GLfloat (*rgba)[4]; + + rgba = malloc(width * 4 * sizeof(GLfloat)); + if (rgba) { + for (j = 0; j < height; j++) { + GLshort *acc = (GLshort *) accMap; + + /* read colors from source color buffer */ + _mesa_unpack_rgba_row(colorRb->Format, width, colorMap, rgba); + + if (load) { + for (i = 0; i < width; i++) { + acc[i * 4 + 0] = (GLshort) (rgba[i][RCOMP] * scale); + acc[i * 4 + 1] = (GLshort) (rgba[i][GCOMP] * scale); + acc[i * 4 + 2] = (GLshort) (rgba[i][BCOMP] * scale); + acc[i * 4 + 3] = (GLshort) (rgba[i][ACOMP] * scale); } - acc += width4; - ypos++; } - } - else { - /* scaled integer accum buffer */ - 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;jDrawBuffer->Accum + ypos * width4 + xpos * 4; - GLuint i; - gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba); - for (i=0;iDriver.SetReadBuffer)( ctx, ctx->DrawBuffer, - ctx->Color.DriverDrawBuffer ); - break; - - case GL_LOAD: - (*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 { - ctx->IntegerAccumMode = GL_FALSE; - ctx->IntegerAccumScaler = 0.0; - } - if (ctx->IntegerAccumMode) { - /* just copy values into accum buffer */ - GLuint j; - 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, 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]; - acc[i4+2] = rgba[i][BCOMP]; - acc[i4+3] = rgba[i][ACOMP]; - } - acc += width4; - ypos++; - } - } - else { - /* scaled integer accum buffer */ - 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->DrawBuffer->Accum + ypos * width4 + xpos * 4; - gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba); - for (i=0;iDriver.SetReadBuffer)( ctx, ctx->DrawBuffer, - ctx->Color.DriverDrawBuffer ); - break; - - case GL_RETURN: - /* May have to leave optimized accum buffer mode */ - if (ctx->IntegerAccumMode && value != 1.0) - rescale_accum(ctx); - - 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; - 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; - } + free(rgba); + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); + } + } + else { + /* other types someday? */ + } - assert(ctx->IntegerAccumScaler > 0.0); - assert(ctx->IntegerAccumScaler <= 1.0); + ctx->Driver.UnmapRenderbuffer(ctx, accRb); + ctx->Driver.UnmapRenderbuffer(ctx, colorRb); +} + + +/** + * ColorBuffer = Accum * value + */ +static void +accum_return(struct gl_context *ctx, GLfloat value, + GLint xpos, GLint ypos, GLint width, GLint height) +{ + struct gl_framebuffer *fb = ctx->DrawBuffer; + struct gl_renderbuffer *accRb = fb->Attachment[BUFFER_ACCUM].Renderbuffer; + GLubyte *accMap, *colorMap; + GLint accRowStride, colorRowStride; + GLuint buffer; + + /* Map accum buffer */ + ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height, + GL_MAP_READ_BIT, + &accMap, &accRowStride); + if (!accMap) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); + return; + } + + /* Loop over destination buffers */ + for (buffer = 0; buffer < fb->_NumColorDrawBuffers; buffer++) { + struct gl_renderbuffer *colorRb = fb->_ColorDrawBuffers[buffer]; + const GLboolean masking = (!ctx->Color.ColorMask[buffer][RCOMP] || + !ctx->Color.ColorMask[buffer][GCOMP] || + !ctx->Color.ColorMask[buffer][BCOMP] || + !ctx->Color.ColorMask[buffer][ACOMP]); + GLbitfield mappingFlags = GL_MAP_WRITE_BIT; + + if (masking) + mappingFlags |= GL_MAP_READ_BIT; + + /* Map color buffer */ + ctx->Driver.MapRenderbuffer(ctx, colorRb, xpos, ypos, width, height, + mappingFlags, &colorMap, &colorRowStride); + if (!colorMap) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); + continue; + } + + if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) { + const GLfloat scale = value / 32767.0f; + GLint i, j; + GLfloat (*rgba)[4], (*dest)[4]; + + rgba = malloc(width * 4 * sizeof(GLfloat)); + dest = malloc(width * 4 * sizeof(GLfloat)); + + if (rgba && dest) { for (j = 0; j < height; j++) { - 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] < 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]]; + GLshort *acc = (GLshort *) accMap; + + for (i = 0; i < width; i++) { + rgba[i][0] = acc[i * 4 + 0] * scale; + rgba[i][1] = acc[i * 4 + 1] * scale; + rgba[i][2] = acc[i * 4 + 2] * scale; + rgba[i][3] = acc[i * 4 + 3] * scale; } - if (ctx->Color.SWmasking) { - gl_mask_rgba_span( ctx, width, xpos, ypos, rgba ); + + if (masking) { + + /* get existing colors from dest buffer */ + _mesa_unpack_rgba_row(colorRb->Format, width, colorMap, dest); + + /* use the dest colors where mask[channel] = 0 */ + if (ctx->Color.ColorMask[buffer][RCOMP] == 0) { + for (i = 0; i < width; i++) + rgba[i][RCOMP] = dest[i][RCOMP]; + } + if (ctx->Color.ColorMask[buffer][GCOMP] == 0) { + for (i = 0; i < width; i++) + rgba[i][GCOMP] = dest[i][GCOMP]; + } + if (ctx->Color.ColorMask[buffer][BCOMP] == 0) { + for (i = 0; i < width; i++) + rgba[i][BCOMP] = dest[i][BCOMP]; + } + if (ctx->Color.ColorMask[buffer][ACOMP] == 0) { + for (i = 0; i < width; i++) + rgba[i][ACOMP] = dest[i][ACOMP]; + } } - (*ctx->Driver.WriteRGBASpan)( ctx, width, xpos, ypos, - (const GLubyte (*)[4])rgba, NULL ); - ypos++; + + _mesa_pack_float_rgba_row(colorRb->Format, width, + (const GLfloat (*)[4]) rgba, colorMap); + + accMap += accRowStride; + colorMap += colorRowStride; } } else { - 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;jDrawBuffer->Accum + ypos * width4 + xpos*4; - for (i=0;iColor.SWmasking) { - gl_mask_rgba_span( ctx, width, xpos, ypos, rgba ); - } - (*ctx->Driver.WriteRGBASpan)( ctx, width, xpos, ypos, - (const GLubyte (*)[4])rgba, NULL ); - ypos++; - } - } - break; + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); + } + free(rgba); + free(dest); + } + else { + /* other types someday? */ + } - default: - gl_error( ctx, GL_INVALID_ENUM, "glAccum" ); + ctx->Driver.UnmapRenderbuffer(ctx, colorRb); } + + ctx->Driver.UnmapRenderbuffer(ctx, accRb); } -/* - * Clear the accumulation Buffer. +/** + * Software fallback for glAccum. A hardware driver that supports + * signed 16-bit color channels could implement hardware accumulation + * operations, but no driver does so at this time. */ void -_mesa_clear_accum_buffer( GLcontext *ctx ) +_mesa_accum(struct gl_context *ctx, GLenum op, GLfloat value) { - GLuint buffersize; - GLfloat acc_scale; + GLint xpos, ypos, width, height; - if (ctx->Visual->AccumRedBits==0) { - /* No accumulation buffer! */ + if (!ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer) { + _mesa_warning(ctx, "Calling glAccum() without an accumulation buffer"); return; } - if (sizeof(GLaccum)==1) { - acc_scale = 127.0; - } - else if (sizeof(GLaccum)==2) { - acc_scale = 32767.0; - } - else { - /* sizeof(GLaccum) > 2 (Cray) */ - acc_scale = (float) SHRT_MAX; - } - - /* number of pixels */ - buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height; + if (!_mesa_check_conditional_render(ctx)) + return; - if (!ctx->DrawBuffer->Accum) { - /* try to alloc accumulation buffer */ - ctx->DrawBuffer->Accum = (GLaccum *) - MALLOC( buffersize * 4 * sizeof(GLaccum) ); - } + xpos = ctx->DrawBuffer->_Xmin; + ypos = ctx->DrawBuffer->_Ymin; + width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; + height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; - if (ctx->DrawBuffer->Accum) { - if (ctx->Scissor.Enabled) { - /* Limit clear to scissor box */ - GLaccum r, g, b, a; - GLint i, j; - GLint width, height; - GLaccum *row; - r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale); - g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale); - b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale); - a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale); - /* size of region to clear */ - 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->DrawBuffer->Accum - + 4 * (ctx->DrawBuffer->Ymin * ctx->DrawBuffer->Width - + ctx->DrawBuffer->Xmin); - for (j=0;jDrawBuffer->Width; - } + switch (op) { + case GL_ADD: + if (value != 0.0F) { + accum_scale_or_bias(ctx, value, xpos, ypos, width, height, GL_TRUE); } - else { - /* clear whole buffer */ - 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) { - /* Black */ - BZERO( ctx->DrawBuffer->Accum, buffersize * 4 * sizeof(GLaccum) ); - } - else { - /* Not black */ - GLaccum *acc, r, g, b, a; - GLuint i; - - 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); - a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale); - for (i=0;iAccum.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 { - ctx->IntegerAccumMode = GL_FALSE; + break; + case GL_ACCUM: + if (value != 0.0F) { + accum_or_load(ctx, value, xpos, ypos, width, height, GL_FALSE); } + break; + case GL_LOAD: + accum_or_load(ctx, value, xpos, ypos, width, height, GL_TRUE); + break; + case GL_RETURN: + accum_return(ctx, value, xpos, ypos, width, height); + break; + default: + _mesa_problem(ctx, "invalid mode in _mesa_accum()"); + break; } } + + +void +_mesa_init_accum( struct gl_context *ctx ) +{ + /* Accumulate buffer group */ + ASSIGN_4V( ctx->Accum.ClearColor, 0.0, 0.0, 0.0, 0.0 ); +}