Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22.  * OTHER DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25. #include "glheader.h"
  26. #include "accum.h"
  27. #include "condrender.h"
  28. #include "context.h"
  29. #include "format_unpack.h"
  30. #include "format_pack.h"
  31. #include "imports.h"
  32. #include "macros.h"
  33. #include "state.h"
  34. #include "mtypes.h"
  35. #include "main/dispatch.h"
  36.  
  37.  
  38. void GLAPIENTRY
  39. _mesa_ClearAccum( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha )
  40. {
  41.    GLfloat tmp[4];
  42.    GET_CURRENT_CONTEXT(ctx);
  43.  
  44.    tmp[0] = CLAMP( red,   -1.0F, 1.0F );
  45.    tmp[1] = CLAMP( green, -1.0F, 1.0F );
  46.    tmp[2] = CLAMP( blue,  -1.0F, 1.0F );
  47.    tmp[3] = CLAMP( alpha, -1.0F, 1.0F );
  48.  
  49.    if (TEST_EQ_4V(tmp, ctx->Accum.ClearColor))
  50.       return;
  51.  
  52.    COPY_4FV( ctx->Accum.ClearColor, tmp );
  53. }
  54.  
  55.  
  56. void GLAPIENTRY
  57. _mesa_Accum( GLenum op, GLfloat value )
  58. {
  59.    GET_CURRENT_CONTEXT(ctx);
  60.    FLUSH_VERTICES(ctx, 0);
  61.  
  62.    switch (op) {
  63.    case GL_ADD:
  64.    case GL_MULT:
  65.    case GL_ACCUM:
  66.    case GL_LOAD:
  67.    case GL_RETURN:
  68.       /* OK */
  69.       break;
  70.    default:
  71.       _mesa_error(ctx, GL_INVALID_ENUM, "glAccum(op)");
  72.       return;
  73.    }
  74.  
  75.    if (ctx->DrawBuffer->Visual.haveAccumBuffer == 0) {
  76.       _mesa_error(ctx, GL_INVALID_OPERATION, "glAccum(no accum buffer)");
  77.       return;
  78.    }
  79.  
  80.    if (ctx->DrawBuffer != ctx->ReadBuffer) {
  81.       /* See GLX_SGI_make_current_read or WGL_ARB_make_current_read,
  82.        * or GL_EXT_framebuffer_blit.
  83.        */
  84.       _mesa_error(ctx, GL_INVALID_OPERATION,
  85.                   "glAccum(different read/draw buffers)");
  86.       return;
  87.    }
  88.  
  89.    if (ctx->NewState)
  90.       _mesa_update_state(ctx);
  91.  
  92.    if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
  93.       _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
  94.                   "glAccum(incomplete framebuffer)");
  95.       return;
  96.    }
  97.  
  98.    if (ctx->RasterDiscard)
  99.       return;
  100.  
  101.    if (ctx->RenderMode == GL_RENDER) {
  102.       _mesa_accum(ctx, op, value);
  103.    }
  104. }
  105.  
  106.  
  107. /**
  108.  * Clear the accumulation buffer by mapping the renderbuffer and
  109.  * writing the clear color to it.  Called by the driver's implementation
  110.  * of the glClear function.
  111.  */
  112. void
  113. _mesa_clear_accum_buffer(struct gl_context *ctx)
  114. {
  115.    GLuint x, y, width, height;
  116.    GLubyte *accMap;
  117.    GLint accRowStride;
  118.    struct gl_renderbuffer *accRb;
  119.  
  120.    if (!ctx->DrawBuffer)
  121.       return;
  122.  
  123.    accRb = ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
  124.    if (!accRb)
  125.       return;   /* missing accum buffer, not an error */
  126.  
  127.    /* bounds, with scissor */
  128.    x = ctx->DrawBuffer->_Xmin;
  129.    y = ctx->DrawBuffer->_Ymin;
  130.    width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
  131.    height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
  132.  
  133.    ctx->Driver.MapRenderbuffer(ctx, accRb, x, y, width, height,
  134.                                GL_MAP_WRITE_BIT, &accMap, &accRowStride);
  135.  
  136.    if (!accMap) {
  137.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
  138.       return;
  139.    }
  140.  
  141.    if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) {
  142.       const GLshort clearR = FLOAT_TO_SHORT(ctx->Accum.ClearColor[0]);
  143.       const GLshort clearG = FLOAT_TO_SHORT(ctx->Accum.ClearColor[1]);
  144.       const GLshort clearB = FLOAT_TO_SHORT(ctx->Accum.ClearColor[2]);
  145.       const GLshort clearA = FLOAT_TO_SHORT(ctx->Accum.ClearColor[3]);
  146.       GLuint i, j;
  147.  
  148.       for (j = 0; j < height; j++) {
  149.          GLshort *row = (GLshort *) accMap;
  150.          
  151.          for (i = 0; i < width; i++) {
  152.             row[i * 4 + 0] = clearR;
  153.             row[i * 4 + 1] = clearG;
  154.             row[i * 4 + 2] = clearB;
  155.             row[i * 4 + 3] = clearA;
  156.          }
  157.          accMap += accRowStride;
  158.       }
  159.    }
  160.    else {
  161.       /* other types someday? */
  162.       _mesa_warning(ctx, "unexpected accum buffer type");
  163.    }
  164.  
  165.    ctx->Driver.UnmapRenderbuffer(ctx, accRb);
  166. }
  167.  
  168.  
  169. /**
  170.  * if (bias)
  171.  *    Accum += value
  172.  * else
  173.  *    Accum *= value
  174.  */
  175. static void
  176. accum_scale_or_bias(struct gl_context *ctx, GLfloat value,
  177.                     GLint xpos, GLint ypos, GLint width, GLint height,
  178.                     GLboolean bias)
  179. {
  180.    struct gl_renderbuffer *accRb =
  181.       ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
  182.    GLubyte *accMap;
  183.    GLint accRowStride;
  184.  
  185.    assert(accRb);
  186.  
  187.    ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height,
  188.                                GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
  189.                                &accMap, &accRowStride);
  190.  
  191.    if (!accMap) {
  192.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
  193.       return;
  194.    }
  195.  
  196.    if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) {
  197.       const GLshort incr = (GLshort) (value * 32767.0f);
  198.       GLint i, j;
  199.       if (bias) {
  200.          for (j = 0; j < height; j++) {
  201.             GLshort *acc = (GLshort *) accMap;
  202.             for (i = 0; i < 4 * width; i++) {
  203.                acc[i] += incr;
  204.             }
  205.             accMap += accRowStride;
  206.          }
  207.       }
  208.       else {
  209.          /* scale */
  210.          for (j = 0; j < height; j++) {
  211.             GLshort *acc = (GLshort *) accMap;
  212.             for (i = 0; i < 4 * width; i++) {
  213.                acc[i] = (GLshort) (acc[i] * value);
  214.             }
  215.             accMap += accRowStride;
  216.          }
  217.       }
  218.    }
  219.    else {
  220.       /* other types someday? */
  221.    }
  222.  
  223.    ctx->Driver.UnmapRenderbuffer(ctx, accRb);
  224. }
  225.  
  226.  
  227. /**
  228.  * if (load)
  229.  *    Accum = ColorBuf * value
  230.  * else
  231.  *    Accum += ColorBuf * value
  232.  */
  233. static void
  234. accum_or_load(struct gl_context *ctx, GLfloat value,
  235.               GLint xpos, GLint ypos, GLint width, GLint height,
  236.               GLboolean load)
  237. {
  238.    struct gl_renderbuffer *accRb =
  239.       ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
  240.    struct gl_renderbuffer *colorRb = ctx->ReadBuffer->_ColorReadBuffer;
  241.    GLubyte *accMap, *colorMap;
  242.    GLint accRowStride, colorRowStride;
  243.    GLbitfield mappingFlags;
  244.  
  245.    if (!colorRb) {
  246.       /* no read buffer - OK */
  247.       return;
  248.    }
  249.  
  250.    assert(accRb);
  251.  
  252.    mappingFlags = GL_MAP_WRITE_BIT;
  253.    if (!load) /* if we're accumulating */
  254.       mappingFlags |= GL_MAP_READ_BIT;
  255.  
  256.    /* Map accum buffer */
  257.    ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height,
  258.                                mappingFlags, &accMap, &accRowStride);
  259.    if (!accMap) {
  260.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
  261.       return;
  262.    }
  263.  
  264.    /* Map color buffer */
  265.    ctx->Driver.MapRenderbuffer(ctx, colorRb, xpos, ypos, width, height,
  266.                                GL_MAP_READ_BIT,
  267.                                &colorMap, &colorRowStride);
  268.    if (!colorMap) {
  269.       ctx->Driver.UnmapRenderbuffer(ctx, accRb);
  270.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
  271.       return;
  272.    }
  273.  
  274.    if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) {
  275.       const GLfloat scale = value * 32767.0f;
  276.       GLint i, j;
  277.       GLfloat (*rgba)[4];
  278.  
  279.       rgba = malloc(width * 4 * sizeof(GLfloat));
  280.       if (rgba) {
  281.          for (j = 0; j < height; j++) {
  282.             GLshort *acc = (GLshort *) accMap;
  283.  
  284.             /* read colors from source color buffer */
  285.             _mesa_unpack_rgba_row(colorRb->Format, width, colorMap, rgba);
  286.  
  287.             if (load) {
  288.                for (i = 0; i < width; i++) {
  289.                   acc[i * 4 + 0] = (GLshort) (rgba[i][RCOMP] * scale);
  290.                   acc[i * 4 + 1] = (GLshort) (rgba[i][GCOMP] * scale);
  291.                   acc[i * 4 + 2] = (GLshort) (rgba[i][BCOMP] * scale);
  292.                   acc[i * 4 + 3] = (GLshort) (rgba[i][ACOMP] * scale);
  293.                }
  294.             }
  295.             else {
  296.                /* accumulate */
  297.                for (i = 0; i < width; i++) {
  298.                   acc[i * 4 + 0] += (GLshort) (rgba[i][RCOMP] * scale);
  299.                   acc[i * 4 + 1] += (GLshort) (rgba[i][GCOMP] * scale);
  300.                   acc[i * 4 + 2] += (GLshort) (rgba[i][BCOMP] * scale);
  301.                   acc[i * 4 + 3] += (GLshort) (rgba[i][ACOMP] * scale);
  302.                }
  303.             }
  304.  
  305.             colorMap += colorRowStride;
  306.             accMap += accRowStride;
  307.          }
  308.  
  309.          free(rgba);
  310.       }
  311.       else {
  312.          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
  313.       }
  314.    }
  315.    else {
  316.       /* other types someday? */
  317.    }
  318.  
  319.    ctx->Driver.UnmapRenderbuffer(ctx, accRb);
  320.    ctx->Driver.UnmapRenderbuffer(ctx, colorRb);
  321. }
  322.  
  323.  
  324. /**
  325.  * ColorBuffer = Accum * value
  326.  */
  327. static void
  328. accum_return(struct gl_context *ctx, GLfloat value,
  329.              GLint xpos, GLint ypos, GLint width, GLint height)
  330. {
  331.    struct gl_framebuffer *fb = ctx->DrawBuffer;
  332.    struct gl_renderbuffer *accRb = fb->Attachment[BUFFER_ACCUM].Renderbuffer;
  333.    GLubyte *accMap, *colorMap;
  334.    GLint accRowStride, colorRowStride;
  335.    GLuint buffer;
  336.  
  337.    /* Map accum buffer */
  338.    ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height,
  339.                                GL_MAP_READ_BIT,
  340.                                &accMap, &accRowStride);
  341.    if (!accMap) {
  342.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
  343.       return;
  344.    }
  345.  
  346.    /* Loop over destination buffers */
  347.    for (buffer = 0; buffer < fb->_NumColorDrawBuffers; buffer++) {
  348.       struct gl_renderbuffer *colorRb = fb->_ColorDrawBuffers[buffer];
  349.       const GLboolean masking = (!ctx->Color.ColorMask[buffer][RCOMP] ||
  350.                                  !ctx->Color.ColorMask[buffer][GCOMP] ||
  351.                                  !ctx->Color.ColorMask[buffer][BCOMP] ||
  352.                                  !ctx->Color.ColorMask[buffer][ACOMP]);
  353.       GLbitfield mappingFlags = GL_MAP_WRITE_BIT;
  354.  
  355.       if (masking)
  356.          mappingFlags |= GL_MAP_READ_BIT;
  357.  
  358.       /* Map color buffer */
  359.       ctx->Driver.MapRenderbuffer(ctx, colorRb, xpos, ypos, width, height,
  360.                                   mappingFlags, &colorMap, &colorRowStride);
  361.       if (!colorMap) {
  362.          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
  363.          continue;
  364.       }
  365.  
  366.       if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) {
  367.          const GLfloat scale = value / 32767.0f;
  368.          GLint i, j;
  369.          GLfloat (*rgba)[4], (*dest)[4];
  370.  
  371.          rgba = malloc(width * 4 * sizeof(GLfloat));
  372.          dest = malloc(width * 4 * sizeof(GLfloat));
  373.  
  374.          if (rgba && dest) {
  375.             for (j = 0; j < height; j++) {
  376.                GLshort *acc = (GLshort *) accMap;
  377.  
  378.                for (i = 0; i < width; i++) {
  379.                   rgba[i][0] = acc[i * 4 + 0] * scale;
  380.                   rgba[i][1] = acc[i * 4 + 1] * scale;
  381.                   rgba[i][2] = acc[i * 4 + 2] * scale;
  382.                   rgba[i][3] = acc[i * 4 + 3] * scale;
  383.                }
  384.  
  385.                if (masking) {
  386.  
  387.                   /* get existing colors from dest buffer */
  388.                   _mesa_unpack_rgba_row(colorRb->Format, width, colorMap, dest);
  389.  
  390.                   /* use the dest colors where mask[channel] = 0 */
  391.                   if (ctx->Color.ColorMask[buffer][RCOMP] == 0) {
  392.                      for (i = 0; i < width; i++)
  393.                         rgba[i][RCOMP] = dest[i][RCOMP];
  394.                   }
  395.                   if (ctx->Color.ColorMask[buffer][GCOMP] == 0) {
  396.                      for (i = 0; i < width; i++)
  397.                         rgba[i][GCOMP] = dest[i][GCOMP];
  398.                   }
  399.                   if (ctx->Color.ColorMask[buffer][BCOMP] == 0) {
  400.                      for (i = 0; i < width; i++)
  401.                         rgba[i][BCOMP] = dest[i][BCOMP];
  402.                   }
  403.                   if (ctx->Color.ColorMask[buffer][ACOMP] == 0) {
  404.                      for (i = 0; i < width; i++)
  405.                         rgba[i][ACOMP] = dest[i][ACOMP];
  406.                   }
  407.                }
  408.  
  409.                _mesa_pack_float_rgba_row(colorRb->Format, width,
  410.                                          (const GLfloat (*)[4]) rgba, colorMap);
  411.  
  412.                accMap += accRowStride;
  413.                colorMap += colorRowStride;
  414.             }
  415.          }
  416.          else {
  417.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
  418.          }
  419.          free(rgba);
  420.          free(dest);
  421.       }
  422.       else {
  423.          /* other types someday? */
  424.       }
  425.  
  426.       ctx->Driver.UnmapRenderbuffer(ctx, colorRb);
  427.    }
  428.  
  429.    ctx->Driver.UnmapRenderbuffer(ctx, accRb);
  430. }
  431.  
  432.  
  433.  
  434. /**
  435.  * Software fallback for glAccum.  A hardware driver that supports
  436.  * signed 16-bit color channels could implement hardware accumulation
  437.  * operations, but no driver does so at this time.
  438.  */
  439. void
  440. _mesa_accum(struct gl_context *ctx, GLenum op, GLfloat value)
  441. {
  442.    GLint xpos, ypos, width, height;
  443.  
  444.    if (!ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer) {
  445.       _mesa_warning(ctx, "Calling glAccum() without an accumulation buffer");
  446.       return;
  447.    }
  448.  
  449.    if (!_mesa_check_conditional_render(ctx))
  450.       return;
  451.  
  452.    xpos = ctx->DrawBuffer->_Xmin;
  453.    ypos = ctx->DrawBuffer->_Ymin;
  454.    width =  ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
  455.    height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
  456.  
  457.    switch (op) {
  458.    case GL_ADD:
  459.       if (value != 0.0F) {
  460.          accum_scale_or_bias(ctx, value, xpos, ypos, width, height, GL_TRUE);
  461.       }
  462.       break;
  463.    case GL_MULT:
  464.       if (value != 1.0F) {
  465.          accum_scale_or_bias(ctx, value, xpos, ypos, width, height, GL_FALSE);
  466.       }
  467.       break;
  468.    case GL_ACCUM:
  469.       if (value != 0.0F) {
  470.          accum_or_load(ctx, value, xpos, ypos, width, height, GL_FALSE);
  471.       }
  472.       break;
  473.    case GL_LOAD:
  474.       accum_or_load(ctx, value, xpos, ypos, width, height, GL_TRUE);
  475.       break;
  476.    case GL_RETURN:
  477.       accum_return(ctx, value, xpos, ypos, width, height);
  478.       break;
  479.    default:
  480.       _mesa_problem(ctx, "invalid mode in _mesa_accum()");
  481.       break;
  482.    }
  483. }
  484.  
  485.  
  486. void
  487. _mesa_init_accum( struct gl_context *ctx )
  488. {
  489.    /* Accumulate buffer group */
  490.    ASSIGN_4V( ctx->Accum.ClearColor, 0.0, 0.0, 0.0, 0.0 );
  491. }
  492.