home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mesa5.zip / mesa5src.zip / swrast / s_accum.cpp < prev    next >
C/C++ Source or Header  |  2002-10-30  |  19KB  |  530 lines

  1. /* $Id: s_accum.c,v 1.20 2002/10/30 19:49:30 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  4.1
  6.  *
  7.  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  8.  *
  9.  * Permission is hereby granted, free of charge, to any person obtaining a
  10.  * copy of this software and associated documentation files (the "Software"),
  11.  * to deal in the Software without restriction, including without limitation
  12.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  13.  * and/or sell copies of the Software, and to permit persons to whom the
  14.  * Software is furnished to do so, subject to the following conditions:
  15.  *
  16.  * The above copyright notice and this permission notice shall be included
  17.  * in all copies or substantial portions of the Software.
  18.  *
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  22.  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  23.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  24.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  */
  26.  
  27.  
  28. #include "glheader.h"
  29. #include "context.h"
  30. #include "macros.h"
  31. #include "mmath.h"
  32. #include "imports.h"
  33.  
  34. #include "s_accum.h"
  35. #include "s_alphabuf.h"
  36. #include "s_context.h"
  37. #include "s_masking.h"
  38. #include "s_span.h"
  39.  
  40.  
  41. /*
  42.  * Accumulation buffer notes
  43.  *
  44.  * Normally, accumulation buffer values are GLshorts with values in
  45.  * [-32767, 32767] which represent floating point colors in [-1, 1],
  46.  * as suggested by the OpenGL specification.
  47.  *
  48.  * We optimize for the common case used for full-scene antialiasing:
  49.  *    // start with accum buffer cleared to zero
  50.  *    glAccum(GL_LOAD, w);   // or GL_ACCUM the first image
  51.  *    glAccum(GL_ACCUM, w);
  52.  *    ...
  53.  *    glAccum(GL_ACCUM, w);
  54.  *    glAccum(GL_RETURN, 1.0);
  55.  * That is, we start with an empty accumulation buffer and accumulate
  56.  * n images, each with weight w = 1/n.
  57.  * In this scenario, we can simply store unscaled integer values in
  58.  * the accum buffer instead of scaled integers.  We'll also keep track
  59.  * of the w value so when we do GL_RETURN we simply divide the accumulated
  60.  * values by n (=1/w).
  61.  * This lets us avoid _many_ int->float->int conversions.
  62.  */
  63.  
  64.  
  65. #if CHAN_BITS == 8 && ACCUM_BITS < 32
  66. #define USE_OPTIMIZED_ACCUM   /* enable the optimization */
  67. #endif
  68.  
  69.  
  70. void
  71. _mesa_alloc_accum_buffer( GLframebuffer *buffer )
  72. {
  73.    GET_CURRENT_CONTEXT(ctx);
  74.    GLint n;
  75.  
  76.    if (buffer->Accum) {
  77.       MESA_PBUFFER_FREE( buffer->Accum );
  78.       buffer->Accum = NULL;
  79.    }
  80.  
  81.    /* allocate accumulation buffer if not already present */
  82.    n = buffer->Width * buffer->Height * 4 * sizeof(GLaccum);
  83.    buffer->Accum = (GLaccum *) MESA_PBUFFER_ALLOC( n );
  84.    if (!buffer->Accum) {
  85.       /* unable to setup accumulation buffer */
  86.       _mesa_error( NULL, GL_OUT_OF_MEMORY, "glAccum" );
  87.    }
  88.  
  89.    if (ctx) {
  90.       SWcontext *swrast = SWRAST_CONTEXT(ctx);
  91.       /* XXX these fields should probably be in the GLframebuffer */
  92. #ifdef USE_OPTIMIZED_ACCUM
  93.       swrast->_IntegerAccumMode = GL_TRUE;
  94. #else
  95.       swrast->_IntegerAccumMode = GL_FALSE;
  96. #endif
  97.       swrast->_IntegerAccumScaler = 0.0;
  98.    }
  99. }
  100.  
  101.  
  102. /*
  103.  * This is called when we fall out of optimized/unscaled accum buffer mode.
  104.  * That is, we convert each unscaled accum buffer value into a scaled value
  105.  * representing the range[-1, 1].
  106.  */
  107. static void rescale_accum( GLcontext *ctx )
  108. {
  109.    SWcontext *swrast = SWRAST_CONTEXT(ctx);
  110.    const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height * 4;
  111.    const GLfloat s = swrast->_IntegerAccumScaler * (32767.0F / CHAN_MAXF);
  112.    GLaccum *accum = ctx->DrawBuffer->Accum;
  113.    GLuint i;
  114.  
  115.    assert(swrast->_IntegerAccumMode);
  116.    assert(accum);
  117.  
  118.    for (i = 0; i < n; i++) {
  119.       accum[i] = (GLaccum) (accum[i] * s);
  120.    }
  121.  
  122.    swrast->_IntegerAccumMode = GL_FALSE;
  123. }
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130. /*
  131.  * Clear the accumulation Buffer.
  132.  */
  133. void
  134. _mesa_clear_accum_buffer( GLcontext *ctx )
  135. {
  136.    SWcontext *swrast = SWRAST_CONTEXT(ctx);
  137.    GLuint buffersize;
  138.    GLfloat acc_scale;
  139.  
  140.    if (ctx->Visual.accumRedBits==0) {
  141.       /* No accumulation buffer! */
  142.       return;
  143.    }
  144.  
  145.    if (sizeof(GLaccum)==1) {
  146.       acc_scale = 127.0;
  147.    }
  148.    else if (sizeof(GLaccum)==2) {
  149.       acc_scale = 32767.0;
  150.    }
  151.    else {
  152.       acc_scale = 1.0F;
  153.    }
  154.  
  155.    /* number of pixels */
  156.    buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
  157.  
  158.    if (!ctx->DrawBuffer->Accum) {
  159.       /* try to alloc accumulation buffer */
  160.       ctx->DrawBuffer->Accum = (GLaccum *)
  161.                        MALLOC( buffersize * 4 * sizeof(GLaccum) );
  162.    }
  163.  
  164.    if (ctx->DrawBuffer->Accum) {
  165.       if (ctx->Scissor.Enabled) {
  166.      /* Limit clear to scissor box */
  167.      const GLaccum r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
  168.      const GLaccum g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
  169.      const GLaccum b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
  170.      const GLaccum a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
  171.      GLint i, j;
  172.          GLint width, height;
  173.          GLaccum *row;
  174.          /* size of region to clear */
  175.          width = 4 * (ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin);
  176.          height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
  177.          /* ptr to first element to clear */
  178.          row = ctx->DrawBuffer->Accum
  179.                + 4 * (ctx->DrawBuffer->_Ymin * ctx->DrawBuffer->Width
  180.                       + ctx->DrawBuffer->_Xmin);
  181.          for (j=0;j<height;j++) {
  182.             for (i=0;i<width;i+=4) {
  183.                row[i+0] = r;
  184.                row[i+1] = g;
  185.                row[i+2] = b;
  186.                row[i+3] = a;
  187.         }
  188.             row += 4 * ctx->DrawBuffer->Width;
  189.      }
  190.       }
  191.       else {
  192.      /* clear whole buffer */
  193.      if (ctx->Accum.ClearColor[0]==0.0 &&
  194.          ctx->Accum.ClearColor[1]==0.0 &&
  195.          ctx->Accum.ClearColor[2]==0.0 &&
  196.          ctx->Accum.ClearColor[3]==0.0) {
  197.         /* Black */
  198.         _mesa_bzero( ctx->DrawBuffer->Accum,
  199.                          buffersize * 4 * sizeof(GLaccum) );
  200.      }
  201.      else {
  202.         /* Not black */
  203.         const GLaccum r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
  204.         const GLaccum g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
  205.         const GLaccum b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
  206.         const GLaccum a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
  207.         GLaccum *acc = ctx->DrawBuffer->Accum;
  208.         GLuint i;
  209.         for (i=0;i<buffersize;i++) {
  210.            *acc++ = r;
  211.            *acc++ = g;
  212.            *acc++ = b;
  213.            *acc++ = a;
  214.         }
  215.      }
  216.       }
  217.  
  218.       /* update optimized accum state vars */
  219.       if (ctx->Accum.ClearColor[0] == 0.0 && ctx->Accum.ClearColor[1] == 0.0 &&
  220.           ctx->Accum.ClearColor[2] == 0.0 && ctx->Accum.ClearColor[3] == 0.0) {
  221. #ifdef USE_OPTIMIZED_ACCUM
  222.          swrast->_IntegerAccumMode = GL_TRUE;
  223. #else
  224.          swrast->_IntegerAccumMode = GL_FALSE;
  225. #endif
  226.          swrast->_IntegerAccumScaler = 0.0;  /* denotes empty accum buffer */
  227.       }
  228.       else {
  229.          swrast->_IntegerAccumMode = GL_FALSE;
  230.       }
  231.    }
  232. }
  233.  
  234.  
  235. void
  236. _swrast_Accum( GLcontext *ctx, GLenum op, GLfloat value,
  237.            GLint xpos, GLint ypos,
  238.            GLint width, GLint height )
  239.  
  240. {
  241.    SWcontext *swrast = SWRAST_CONTEXT(ctx);
  242.    GLuint width4;
  243.    GLfloat acc_scale;
  244.    GLchan rgba[MAX_WIDTH][4];
  245.    const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
  246.  
  247.  
  248.    if (SWRAST_CONTEXT(ctx)->NewState)
  249.       _swrast_validate_derived( ctx );
  250.  
  251.    if (!ctx->DrawBuffer->Accum) {
  252.       _mesa_warning(ctx,
  253.             "Calling glAccum() without an accumulation "
  254.             "buffer (low memory?)");
  255.       return;
  256.    }
  257.  
  258.    if (sizeof(GLaccum)==1) {
  259.       acc_scale = 127.0;
  260.    }
  261.    else if (sizeof(GLaccum)==2) {
  262.       acc_scale = 32767.0;
  263.    }
  264.    else {
  265.       acc_scale = 1.0F;
  266.    }
  267.  
  268.    width4 = 4 * width;
  269.  
  270.    switch (op) {
  271.       case GL_ADD:
  272.          if (value != 0.0F) {
  273.         const GLaccum val = (GLaccum) (value * acc_scale);
  274.         GLint j;
  275.             /* Leave optimized accum buffer mode */
  276.             if (swrast->_IntegerAccumMode)
  277.                rescale_accum(ctx);
  278.         for (j = 0; j < height; j++) {
  279.            GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + 4*xpos;
  280.                GLuint i;
  281.            for (i = 0; i < width4; i++) {
  282.                   acc[i] += val;
  283.            }
  284.            ypos++;
  285.         }
  286.      }
  287.      break;
  288.  
  289.       case GL_MULT:
  290.          if (value != 1.0F) {
  291.         GLint j;
  292.             /* Leave optimized accum buffer mode */
  293.             if (swrast->_IntegerAccumMode)
  294.                rescale_accum(ctx);
  295.         for (j = 0; j < height; j++) {
  296.            GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + 4 * xpos;
  297.                GLuint i;
  298.            for (i = 0; i < width4; i++) {
  299.                   acc[i] = (GLaccum) ( (GLfloat) acc[i] * value );
  300.            }
  301.            ypos++;
  302.         }
  303.      }
  304.      break;
  305.  
  306.       case GL_ACCUM:
  307.          if (value == 0.0F)
  308.             return;
  309.  
  310.          _swrast_use_read_buffer(ctx);
  311.  
  312.          /* May have to leave optimized accum buffer mode */
  313.          if (swrast->_IntegerAccumScaler == 0.0 && value > 0.0 && value <= 1.0)
  314.             swrast->_IntegerAccumScaler = value;
  315.          if (swrast->_IntegerAccumMode && value != swrast->_IntegerAccumScaler)
  316.             rescale_accum(ctx);
  317.  
  318.          RENDER_START(swrast,ctx);
  319.  
  320.          if (swrast->_IntegerAccumMode) {
  321.             /* simply add integer color values into accum buffer */
  322.             GLint j;
  323.             GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
  324.             assert(swrast->_IntegerAccumScaler > 0.0);
  325.             assert(swrast->_IntegerAccumScaler <= 1.0);
  326.             for (j = 0; j < height; j++) {
  327.  
  328.                GLint i, i4;
  329.                _mesa_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
  330.                for (i = i4 = 0; i < width; i++, i4+=4) {
  331.                   acc[i4+0] += rgba[i][RCOMP];
  332.                   acc[i4+1] += rgba[i][GCOMP];
  333.                   acc[i4+2] += rgba[i][BCOMP];
  334.                   acc[i4+3] += rgba[i][ACOMP];
  335.                }
  336.                acc += width4;
  337.                ypos++;
  338.             }
  339.          }
  340.          else {
  341.             /* scaled integer (or float) accum buffer */
  342.             const GLfloat rscale = value * acc_scale / CHAN_MAXF;
  343.             const GLfloat gscale = value * acc_scale / CHAN_MAXF;
  344.             const GLfloat bscale = value * acc_scale / CHAN_MAXF;
  345.             const GLfloat ascale = value * acc_scale / CHAN_MAXF;
  346.             GLint j;
  347.             for (j=0;j<height;j++) {
  348.                GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
  349.                GLint i;
  350.                _mesa_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
  351.                for (i=0;i<width;i++) {
  352.                   acc[0] += (GLaccum) ( (GLfloat) rgba[i][RCOMP] * rscale );
  353.                   acc[1] += (GLaccum) ( (GLfloat) rgba[i][GCOMP] * gscale );
  354.                   acc[2] += (GLaccum) ( (GLfloat) rgba[i][BCOMP] * bscale );
  355.                   acc[3] += (GLaccum) ( (GLfloat) rgba[i][ACOMP] * ascale );
  356.                   acc += 4;
  357.                }
  358.                ypos++;
  359.             }
  360.          }
  361.          /* restore read buffer = draw buffer (the default) */
  362.          _swrast_use_draw_buffer(ctx);
  363.  
  364.          RENDER_FINISH(swrast,ctx);
  365.      break;
  366.  
  367.       case GL_LOAD:
  368.          _swrast_use_read_buffer(ctx);
  369.  
  370.          /* This is a change to go into optimized accum buffer mode */
  371.          if (value > 0.0 && value <= 1.0) {
  372. #ifdef USE_OPTIMIZED_ACCUM
  373.             swrast->_IntegerAccumMode = GL_TRUE;
  374. #else
  375.             swrast->_IntegerAccumMode = GL_FALSE;
  376. #endif
  377.             swrast->_IntegerAccumScaler = value;
  378.          }
  379.          else {
  380.             swrast->_IntegerAccumMode = GL_FALSE;
  381.             swrast->_IntegerAccumScaler = 0.0;
  382.          }
  383.  
  384.          RENDER_START(swrast,ctx);
  385.          if (swrast->_IntegerAccumMode) {
  386.             /* just copy values into accum buffer */
  387.             GLint j;
  388.             GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
  389.             assert(swrast->_IntegerAccumScaler > 0.0);
  390.             assert(swrast->_IntegerAccumScaler <= 1.0);
  391.             for (j = 0; j < height; j++) {
  392.                GLint i, i4;
  393.                _mesa_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
  394.                for (i = i4 = 0; i < width; i++, i4 += 4) {
  395.                   acc[i4+0] = rgba[i][RCOMP];
  396.                   acc[i4+1] = rgba[i][GCOMP];
  397.                   acc[i4+2] = rgba[i][BCOMP];
  398.                   acc[i4+3] = rgba[i][ACOMP];
  399.                }
  400.                acc += width4;
  401.                ypos++;
  402.             }
  403.          }
  404.          else {
  405.             /* scaled integer (or float) accum buffer */
  406.             const GLfloat rscale = value * acc_scale / CHAN_MAXF;
  407.             const GLfloat gscale = value * acc_scale / CHAN_MAXF;
  408.             const GLfloat bscale = value * acc_scale / CHAN_MAXF;
  409.             const GLfloat ascale = value * acc_scale / CHAN_MAXF;
  410. #if 0
  411.             const GLfloat d = 3.0 / acc_scale;  /* XXX what's this? */
  412. #endif
  413.             GLint i, j;
  414.             for (j = 0; j < height; j++) {
  415.                GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
  416.                _mesa_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
  417.                for (i=0;i<width;i++) {
  418. #if 0
  419.                   *acc++ = (GLaccum) ((GLfloat) rgba[i][RCOMP] * rscale + d);
  420.                   *acc++ = (GLaccum) ((GLfloat) rgba[i][GCOMP] * gscale + d);
  421.                   *acc++ = (GLaccum) ((GLfloat) rgba[i][BCOMP] * bscale + d);
  422.                   *acc++ = (GLaccum) ((GLfloat) rgba[i][ACOMP] * ascale + d);
  423. #else
  424.                   *acc++ = (GLaccum) ((GLfloat) rgba[i][RCOMP] * rscale);
  425.                   *acc++ = (GLaccum) ((GLfloat) rgba[i][GCOMP] * gscale);
  426.                   *acc++ = (GLaccum) ((GLfloat) rgba[i][BCOMP] * bscale);
  427.                   *acc++ = (GLaccum) ((GLfloat) rgba[i][ACOMP] * ascale);
  428. #endif
  429.                }
  430.                ypos++;
  431.             }
  432.          }
  433.  
  434.          /* restore read buffer = draw buffer (the default) */
  435.          _swrast_use_draw_buffer(ctx);
  436.  
  437.          RENDER_FINISH(swrast,ctx);
  438.      break;
  439.  
  440.       case GL_RETURN:
  441.          /* May have to leave optimized accum buffer mode */
  442.          if (swrast->_IntegerAccumMode && value != 1.0)
  443.             rescale_accum(ctx);
  444.  
  445.          RENDER_START(swrast,ctx);
  446. #ifdef USE_OPTIMIZED_ACCUM
  447.          if (swrast->_IntegerAccumMode && swrast->_IntegerAccumScaler > 0) {
  448.             /* build lookup table to avoid many floating point multiplies */
  449.             static GLchan multTable[32768];
  450.             static GLfloat prevMult = 0.0;
  451.             const GLfloat mult = swrast->_IntegerAccumScaler;
  452.             const GLint max = MIN2((GLint) (256 / mult), 32767);
  453.             GLint j;
  454.             if (mult != prevMult) {
  455.                for (j = 0; j < max; j++)
  456.                   multTable[j] = IROUND((GLfloat) j * mult);
  457.                prevMult = mult;
  458.             }
  459.  
  460.             assert(swrast->_IntegerAccumScaler > 0.0);
  461.             assert(swrast->_IntegerAccumScaler <= 1.0);
  462.             for (j = 0; j < height; j++) {
  463.                const GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos*4;
  464.                GLint i, i4;
  465.                for (i = i4 = 0; i < width; i++, i4 += 4) {
  466.                   ASSERT(acc[i4+0] < max);
  467.                   ASSERT(acc[i4+1] < max);
  468.                   ASSERT(acc[i4+2] < max);
  469.                   ASSERT(acc[i4+3] < max);
  470.                   rgba[i][RCOMP] = multTable[acc[i4+0]];
  471.                   rgba[i][GCOMP] = multTable[acc[i4+1]];
  472.                   rgba[i][BCOMP] = multTable[acc[i4+2]];
  473.                   rgba[i][ACOMP] = multTable[acc[i4+3]];
  474.                }
  475.                if (colorMask != 0xffffffff) {
  476.                   _mesa_mask_rgba_array( ctx, width, xpos, ypos, rgba );
  477.                }
  478.                (*swrast->Driver.WriteRGBASpan)( ctx, width, xpos, ypos,
  479.                                              (const GLchan (*)[4])rgba, NULL );
  480.                if (ctx->DrawBuffer->UseSoftwareAlphaBuffers
  481.                    && ctx->Color.ColorMask[ACOMP]) {
  482.                   _mesa_write_alpha_span(ctx, width, xpos, ypos,
  483.                                          (CONST GLchan (*)[4]) rgba, NULL);
  484.                }
  485.                ypos++;
  486.             }
  487.          }
  488.          else
  489. #endif /* USE_OPTIMIZED_ACCUM */
  490.          {
  491.             /* scaled integer (or float) accum buffer */
  492.             const GLfloat rscale = value / acc_scale * CHAN_MAXF;
  493.             const GLfloat gscale = value / acc_scale * CHAN_MAXF;
  494.             const GLfloat bscale = value / acc_scale * CHAN_MAXF;
  495.             const GLfloat ascale = value / acc_scale * CHAN_MAXF;
  496.             GLint i, j;
  497.             for (j=0;j<height;j++) {
  498.                const GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos*4;
  499.                for (i=0;i<width;i++) {
  500.                   GLint r = IROUND( (GLfloat) (acc[0]) * rscale );
  501.                   GLint g = IROUND( (GLfloat) (acc[1]) * gscale );
  502.                   GLint b = IROUND( (GLfloat) (acc[2]) * bscale );
  503.                   GLint a = IROUND( (GLfloat) (acc[3]) * ascale );
  504.                   acc += 4;
  505.                   rgba[i][RCOMP] = CLAMP( r, 0, CHAN_MAX );
  506.                   rgba[i][GCOMP] = CLAMP( g, 0, CHAN_MAX );
  507.                   rgba[i][BCOMP] = CLAMP( b, 0, CHAN_MAX );
  508.                   rgba[i][ACOMP] = CLAMP( a, 0, CHAN_MAX );
  509.                }
  510.                if (colorMask != 0xffffffff) {
  511.                   _mesa_mask_rgba_array( ctx, width, xpos, ypos, rgba );
  512.                }
  513.                (*swrast->Driver.WriteRGBASpan)( ctx, width, xpos, ypos,
  514.                                              (const GLchan (*)[4])rgba, NULL );
  515.                if (ctx->DrawBuffer->UseSoftwareAlphaBuffers
  516.                    && ctx->Color.ColorMask[ACOMP]) {
  517.                   _mesa_write_alpha_span(ctx, width, xpos, ypos,
  518.                                          (CONST GLchan (*)[4]) rgba, NULL);
  519.                }
  520.                ypos++;
  521.             }
  522.      }
  523.          RENDER_FINISH(swrast,ctx);
  524.      break;
  525.  
  526.       default:
  527.          _mesa_error( ctx, GL_INVALID_ENUM, "glAccum" );
  528.    }
  529. }
  530.