convolve.c revision 4a49301e
17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg * Version:  6.5.2
47117f1b4Smrg *
57117f1b4Smrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
67117f1b4Smrg *
77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
87117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
97117f1b4Smrg * to deal in the Software without restriction, including without limitation
107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
127117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
137117f1b4Smrg *
147117f1b4Smrg * The above copyright notice and this permission notice shall be included
157117f1b4Smrg * in all copies or substantial portions of the Software.
167117f1b4Smrg *
177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
207117f1b4Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
217117f1b4Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
227117f1b4Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
237117f1b4Smrg */
247117f1b4Smrg
257117f1b4Smrg
267117f1b4Smrg/*
277117f1b4Smrg * Image convolution functions.
287117f1b4Smrg *
297117f1b4Smrg * Notes: filter kernel elements are indexed by <n> and <m> as in
307117f1b4Smrg * the GL spec.
317117f1b4Smrg */
327117f1b4Smrg
337117f1b4Smrg
347117f1b4Smrg#include "glheader.h"
357117f1b4Smrg#include "bufferobj.h"
367117f1b4Smrg#include "colormac.h"
377117f1b4Smrg#include "convolve.h"
387117f1b4Smrg#include "context.h"
397117f1b4Smrg#include "image.h"
407117f1b4Smrg#include "mtypes.h"
417117f1b4Smrg#include "state.h"
424a49301eSmrg#include "glapi/dispatch.h"
434a49301eSmrg
444a49301eSmrg
454a49301eSmrg#if FEATURE_convolve
467117f1b4Smrg
477117f1b4Smrg
487117f1b4Smrg/*
497117f1b4Smrg * Given an internalFormat token passed to glConvolutionFilter
507117f1b4Smrg * or glSeparableFilter, return the corresponding base format.
517117f1b4Smrg * Return -1 if invalid token.
527117f1b4Smrg */
537117f1b4Smrgstatic GLint
547117f1b4Smrgbase_filter_format( GLenum format )
557117f1b4Smrg{
567117f1b4Smrg   switch (format) {
577117f1b4Smrg      case GL_ALPHA:
587117f1b4Smrg      case GL_ALPHA4:
597117f1b4Smrg      case GL_ALPHA8:
607117f1b4Smrg      case GL_ALPHA12:
617117f1b4Smrg      case GL_ALPHA16:
627117f1b4Smrg         return GL_ALPHA;
637117f1b4Smrg      case GL_LUMINANCE:
647117f1b4Smrg      case GL_LUMINANCE4:
657117f1b4Smrg      case GL_LUMINANCE8:
667117f1b4Smrg      case GL_LUMINANCE12:
677117f1b4Smrg      case GL_LUMINANCE16:
687117f1b4Smrg         return GL_LUMINANCE;
697117f1b4Smrg      case GL_LUMINANCE_ALPHA:
707117f1b4Smrg      case GL_LUMINANCE4_ALPHA4:
717117f1b4Smrg      case GL_LUMINANCE6_ALPHA2:
727117f1b4Smrg      case GL_LUMINANCE8_ALPHA8:
737117f1b4Smrg      case GL_LUMINANCE12_ALPHA4:
747117f1b4Smrg      case GL_LUMINANCE12_ALPHA12:
757117f1b4Smrg      case GL_LUMINANCE16_ALPHA16:
767117f1b4Smrg         return GL_LUMINANCE_ALPHA;
777117f1b4Smrg      case GL_INTENSITY:
787117f1b4Smrg      case GL_INTENSITY4:
797117f1b4Smrg      case GL_INTENSITY8:
807117f1b4Smrg      case GL_INTENSITY12:
817117f1b4Smrg      case GL_INTENSITY16:
827117f1b4Smrg         return GL_INTENSITY;
837117f1b4Smrg      case GL_RGB:
847117f1b4Smrg      case GL_R3_G3_B2:
857117f1b4Smrg      case GL_RGB4:
867117f1b4Smrg      case GL_RGB5:
877117f1b4Smrg      case GL_RGB8:
887117f1b4Smrg      case GL_RGB10:
897117f1b4Smrg      case GL_RGB12:
907117f1b4Smrg      case GL_RGB16:
917117f1b4Smrg         return GL_RGB;
927117f1b4Smrg      case 4:
937117f1b4Smrg      case GL_RGBA:
947117f1b4Smrg      case GL_RGBA2:
957117f1b4Smrg      case GL_RGBA4:
967117f1b4Smrg      case GL_RGB5_A1:
977117f1b4Smrg      case GL_RGBA8:
987117f1b4Smrg      case GL_RGB10_A2:
997117f1b4Smrg      case GL_RGBA12:
1007117f1b4Smrg      case GL_RGBA16:
1017117f1b4Smrg         return GL_RGBA;
1027117f1b4Smrg      default:
1037117f1b4Smrg         return -1;  /* error */
1047117f1b4Smrg   }
1057117f1b4Smrg}
1067117f1b4Smrg
1077117f1b4Smrg
1087117f1b4Smrgvoid GLAPIENTRY
1097117f1b4Smrg_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
1107117f1b4Smrg{
1117117f1b4Smrg   GLint baseFormat;
1127117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
1137117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
1147117f1b4Smrg
1157117f1b4Smrg   if (target != GL_CONVOLUTION_1D) {
1167117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
1177117f1b4Smrg      return;
1187117f1b4Smrg   }
1197117f1b4Smrg
1207117f1b4Smrg   baseFormat = base_filter_format(internalFormat);
1217117f1b4Smrg   if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
1227117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
1237117f1b4Smrg      return;
1247117f1b4Smrg   }
1257117f1b4Smrg
1267117f1b4Smrg   if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
1277117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
1287117f1b4Smrg      return;
1297117f1b4Smrg   }
1307117f1b4Smrg
1317117f1b4Smrg   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
1327117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter1D(format or type)");
1337117f1b4Smrg      return;
1347117f1b4Smrg   }
1357117f1b4Smrg
1367117f1b4Smrg   if (format == GL_COLOR_INDEX ||
1377117f1b4Smrg       format == GL_STENCIL_INDEX ||
1387117f1b4Smrg       format == GL_DEPTH_COMPONENT ||
1397117f1b4Smrg       format == GL_INTENSITY ||
1407117f1b4Smrg       type == GL_BITMAP) {
1417117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
1427117f1b4Smrg      return;
1437117f1b4Smrg   }
1447117f1b4Smrg
1457117f1b4Smrg   ctx->Convolution1D.Format = format;
1467117f1b4Smrg   ctx->Convolution1D.InternalFormat = internalFormat;
1477117f1b4Smrg   ctx->Convolution1D.Width = width;
1487117f1b4Smrg   ctx->Convolution1D.Height = 1;
1497117f1b4Smrg
1504a49301eSmrg   image = _mesa_map_validate_pbo_source(ctx,
1514a49301eSmrg                                        1, &ctx->Unpack, width, 1, 1,
1524a49301eSmrg                                        format, type, image,
1534a49301eSmrg                                        "glConvolutionFilter1D");
1544a49301eSmrg   if (!image)
1557117f1b4Smrg      return;
1567117f1b4Smrg
1577117f1b4Smrg   _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
1587117f1b4Smrg                                 ctx->Convolution1D.Filter,
1597117f1b4Smrg                                 format, type, image, &ctx->Unpack,
1607117f1b4Smrg                                 0); /* transferOps */
1617117f1b4Smrg
1624a49301eSmrg   _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
1637117f1b4Smrg
1647117f1b4Smrg   _mesa_scale_and_bias_rgba(width,
1657117f1b4Smrg                             (GLfloat (*)[4]) ctx->Convolution1D.Filter,
1667117f1b4Smrg                             ctx->Pixel.ConvolutionFilterScale[0][0],
1677117f1b4Smrg                             ctx->Pixel.ConvolutionFilterScale[0][1],
1687117f1b4Smrg                             ctx->Pixel.ConvolutionFilterScale[0][2],
1697117f1b4Smrg                             ctx->Pixel.ConvolutionFilterScale[0][3],
1707117f1b4Smrg                             ctx->Pixel.ConvolutionFilterBias[0][0],
1717117f1b4Smrg                             ctx->Pixel.ConvolutionFilterBias[0][1],
1727117f1b4Smrg                             ctx->Pixel.ConvolutionFilterBias[0][2],
1737117f1b4Smrg                             ctx->Pixel.ConvolutionFilterBias[0][3]);
1747117f1b4Smrg
1757117f1b4Smrg   ctx->NewState |= _NEW_PIXEL;
1767117f1b4Smrg}
1777117f1b4Smrg
1787117f1b4Smrg
1797117f1b4Smrgvoid GLAPIENTRY
1807117f1b4Smrg_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
1817117f1b4Smrg{
1827117f1b4Smrg   GLint baseFormat;
1837117f1b4Smrg   GLint i;
1847117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
1857117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
1867117f1b4Smrg
1877117f1b4Smrg   if (target != GL_CONVOLUTION_2D) {
1887117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
1897117f1b4Smrg      return;
1907117f1b4Smrg   }
1917117f1b4Smrg
1927117f1b4Smrg   baseFormat = base_filter_format(internalFormat);
1937117f1b4Smrg   if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
1947117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
1957117f1b4Smrg      return;
1967117f1b4Smrg   }
1977117f1b4Smrg
1987117f1b4Smrg   if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
1997117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
2007117f1b4Smrg      return;
2017117f1b4Smrg   }
2027117f1b4Smrg   if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
2037117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
2047117f1b4Smrg      return;
2057117f1b4Smrg   }
2067117f1b4Smrg
2077117f1b4Smrg   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
2087117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
2097117f1b4Smrg      return;
2107117f1b4Smrg   }
2117117f1b4Smrg   if (format == GL_COLOR_INDEX ||
2127117f1b4Smrg       format == GL_STENCIL_INDEX ||
2137117f1b4Smrg       format == GL_DEPTH_COMPONENT ||
2147117f1b4Smrg       format == GL_INTENSITY ||
2157117f1b4Smrg       type == GL_BITMAP) {
2167117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
2177117f1b4Smrg      return;
2187117f1b4Smrg   }
2197117f1b4Smrg
2207117f1b4Smrg   /* this should have been caught earlier */
2217117f1b4Smrg   assert(_mesa_components_in_format(format));
2227117f1b4Smrg
2237117f1b4Smrg   ctx->Convolution2D.Format = format;
2247117f1b4Smrg   ctx->Convolution2D.InternalFormat = internalFormat;
2257117f1b4Smrg   ctx->Convolution2D.Width = width;
2267117f1b4Smrg   ctx->Convolution2D.Height = height;
2277117f1b4Smrg
2284a49301eSmrg   image = _mesa_map_validate_pbo_source(ctx,
2294a49301eSmrg                                         2, &ctx->Unpack, width, height, 1,
2304a49301eSmrg                                         format, type, image,
2314a49301eSmrg                                         "glConvolutionFilter2D");
2324a49301eSmrg   if (!image)
2337117f1b4Smrg      return;
2347117f1b4Smrg
2357117f1b4Smrg   /* Unpack filter image.  We always store filters in RGBA format. */
2367117f1b4Smrg   for (i = 0; i < height; i++) {
2377117f1b4Smrg      const GLvoid *src = _mesa_image_address2d(&ctx->Unpack, image, width,
2387117f1b4Smrg                                                height, format, type, i, 0);
2397117f1b4Smrg      GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
2407117f1b4Smrg      _mesa_unpack_color_span_float(ctx, width, GL_RGBA, dst,
2417117f1b4Smrg                                    format, type, src, &ctx->Unpack,
2427117f1b4Smrg                                    0); /* transferOps */
2437117f1b4Smrg   }
2447117f1b4Smrg
2454a49301eSmrg   _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
2467117f1b4Smrg
2477117f1b4Smrg   _mesa_scale_and_bias_rgba(width * height,
2487117f1b4Smrg                             (GLfloat (*)[4]) ctx->Convolution2D.Filter,
2497117f1b4Smrg                             ctx->Pixel.ConvolutionFilterScale[1][0],
2507117f1b4Smrg                             ctx->Pixel.ConvolutionFilterScale[1][1],
2517117f1b4Smrg                             ctx->Pixel.ConvolutionFilterScale[1][2],
2527117f1b4Smrg                             ctx->Pixel.ConvolutionFilterScale[1][3],
2537117f1b4Smrg                             ctx->Pixel.ConvolutionFilterBias[1][0],
2547117f1b4Smrg                             ctx->Pixel.ConvolutionFilterBias[1][1],
2557117f1b4Smrg                             ctx->Pixel.ConvolutionFilterBias[1][2],
2567117f1b4Smrg                             ctx->Pixel.ConvolutionFilterBias[1][3]);
2577117f1b4Smrg
2587117f1b4Smrg   ctx->NewState |= _NEW_PIXEL;
2597117f1b4Smrg}
2607117f1b4Smrg
2617117f1b4Smrg
2624a49301eSmrgstatic void GLAPIENTRY
2637117f1b4Smrg_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
2647117f1b4Smrg{
2657117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2667117f1b4Smrg   GLuint c;
2677117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
2687117f1b4Smrg
2697117f1b4Smrg   switch (target) {
2707117f1b4Smrg      case GL_CONVOLUTION_1D:
2717117f1b4Smrg         c = 0;
2727117f1b4Smrg         break;
2737117f1b4Smrg      case GL_CONVOLUTION_2D:
2747117f1b4Smrg         c = 1;
2757117f1b4Smrg         break;
2767117f1b4Smrg      case GL_SEPARABLE_2D:
2777117f1b4Smrg         c = 2;
2787117f1b4Smrg         break;
2797117f1b4Smrg      default:
2807117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
2817117f1b4Smrg         return;
2827117f1b4Smrg   }
2837117f1b4Smrg
2847117f1b4Smrg   switch (pname) {
2857117f1b4Smrg      case GL_CONVOLUTION_BORDER_MODE:
2867117f1b4Smrg         if (param == (GLfloat) GL_REDUCE ||
2877117f1b4Smrg             param == (GLfloat) GL_CONSTANT_BORDER ||
2887117f1b4Smrg             param == (GLfloat) GL_REPLICATE_BORDER) {
2897117f1b4Smrg            ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
2907117f1b4Smrg         }
2917117f1b4Smrg         else {
2927117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
2937117f1b4Smrg            return;
2947117f1b4Smrg         }
2957117f1b4Smrg         break;
2967117f1b4Smrg      default:
2977117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
2987117f1b4Smrg         return;
2997117f1b4Smrg   }
3007117f1b4Smrg
3017117f1b4Smrg   ctx->NewState |= _NEW_PIXEL;
3027117f1b4Smrg}
3037117f1b4Smrg
3047117f1b4Smrg
3054a49301eSmrgstatic void GLAPIENTRY
3067117f1b4Smrg_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
3077117f1b4Smrg{
3087117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3097117f1b4Smrg   GLuint c;
3107117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
3117117f1b4Smrg
3127117f1b4Smrg   switch (target) {
3137117f1b4Smrg      case GL_CONVOLUTION_1D:
3147117f1b4Smrg         c = 0;
3157117f1b4Smrg         break;
3167117f1b4Smrg      case GL_CONVOLUTION_2D:
3177117f1b4Smrg         c = 1;
3187117f1b4Smrg         break;
3197117f1b4Smrg      case GL_SEPARABLE_2D:
3207117f1b4Smrg         c = 2;
3217117f1b4Smrg         break;
3227117f1b4Smrg      default:
3237117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
3247117f1b4Smrg         return;
3257117f1b4Smrg   }
3267117f1b4Smrg
3277117f1b4Smrg   switch (pname) {
3287117f1b4Smrg      case GL_CONVOLUTION_BORDER_COLOR:
3297117f1b4Smrg         COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
3307117f1b4Smrg         break;
3317117f1b4Smrg      case GL_CONVOLUTION_BORDER_MODE:
3327117f1b4Smrg         if (params[0] == (GLfloat) GL_REDUCE ||
3337117f1b4Smrg             params[0] == (GLfloat) GL_CONSTANT_BORDER ||
3347117f1b4Smrg             params[0] == (GLfloat) GL_REPLICATE_BORDER) {
3357117f1b4Smrg            ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
3367117f1b4Smrg         }
3377117f1b4Smrg         else {
3387117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
3397117f1b4Smrg            return;
3407117f1b4Smrg         }
3417117f1b4Smrg         break;
3427117f1b4Smrg      case GL_CONVOLUTION_FILTER_SCALE:
3437117f1b4Smrg         COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
3447117f1b4Smrg         break;
3457117f1b4Smrg      case GL_CONVOLUTION_FILTER_BIAS:
3467117f1b4Smrg         COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
3477117f1b4Smrg         break;
3487117f1b4Smrg      default:
3497117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
3507117f1b4Smrg         return;
3517117f1b4Smrg   }
3527117f1b4Smrg
3537117f1b4Smrg   ctx->NewState |= _NEW_PIXEL;
3547117f1b4Smrg}
3557117f1b4Smrg
3567117f1b4Smrg
3574a49301eSmrgstatic void GLAPIENTRY
3587117f1b4Smrg_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
3597117f1b4Smrg{
3607117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3617117f1b4Smrg   GLuint c;
3627117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
3637117f1b4Smrg
3647117f1b4Smrg   switch (target) {
3657117f1b4Smrg      case GL_CONVOLUTION_1D:
3667117f1b4Smrg         c = 0;
3677117f1b4Smrg         break;
3687117f1b4Smrg      case GL_CONVOLUTION_2D:
3697117f1b4Smrg         c = 1;
3707117f1b4Smrg         break;
3717117f1b4Smrg      case GL_SEPARABLE_2D:
3727117f1b4Smrg         c = 2;
3737117f1b4Smrg         break;
3747117f1b4Smrg      default:
3757117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
3767117f1b4Smrg         return;
3777117f1b4Smrg   }
3787117f1b4Smrg
3797117f1b4Smrg   switch (pname) {
3807117f1b4Smrg      case GL_CONVOLUTION_BORDER_MODE:
3817117f1b4Smrg         if (param == (GLint) GL_REDUCE ||
3827117f1b4Smrg             param == (GLint) GL_CONSTANT_BORDER ||
3837117f1b4Smrg             param == (GLint) GL_REPLICATE_BORDER) {
3847117f1b4Smrg            ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
3857117f1b4Smrg         }
3867117f1b4Smrg         else {
3877117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
3887117f1b4Smrg            return;
3897117f1b4Smrg         }
3907117f1b4Smrg         break;
3917117f1b4Smrg      default:
3927117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
3937117f1b4Smrg         return;
3947117f1b4Smrg   }
3957117f1b4Smrg
3967117f1b4Smrg   ctx->NewState |= _NEW_PIXEL;
3977117f1b4Smrg}
3987117f1b4Smrg
3997117f1b4Smrg
4004a49301eSmrgstatic void GLAPIENTRY
4017117f1b4Smrg_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
4027117f1b4Smrg{
4037117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4047117f1b4Smrg   GLuint c;
4057117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
4067117f1b4Smrg
4077117f1b4Smrg   switch (target) {
4087117f1b4Smrg      case GL_CONVOLUTION_1D:
4097117f1b4Smrg         c = 0;
4107117f1b4Smrg         break;
4117117f1b4Smrg      case GL_CONVOLUTION_2D:
4127117f1b4Smrg         c = 1;
4137117f1b4Smrg         break;
4147117f1b4Smrg      case GL_SEPARABLE_2D:
4157117f1b4Smrg         c = 2;
4167117f1b4Smrg         break;
4177117f1b4Smrg      default:
4187117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
4197117f1b4Smrg         return;
4207117f1b4Smrg   }
4217117f1b4Smrg
4227117f1b4Smrg   switch (pname) {
4237117f1b4Smrg      case GL_CONVOLUTION_BORDER_COLOR:
4247117f1b4Smrg	 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
4257117f1b4Smrg	 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
4267117f1b4Smrg	 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
4277117f1b4Smrg	 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
4287117f1b4Smrg         break;
4297117f1b4Smrg      case GL_CONVOLUTION_BORDER_MODE:
4307117f1b4Smrg         if (params[0] == (GLint) GL_REDUCE ||
4317117f1b4Smrg             params[0] == (GLint) GL_CONSTANT_BORDER ||
4327117f1b4Smrg             params[0] == (GLint) GL_REPLICATE_BORDER) {
4337117f1b4Smrg            ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
4347117f1b4Smrg         }
4357117f1b4Smrg         else {
4367117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
4377117f1b4Smrg            return;
4387117f1b4Smrg         }
4397117f1b4Smrg         break;
4407117f1b4Smrg      case GL_CONVOLUTION_FILTER_SCALE:
4417117f1b4Smrg	 /* COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); */
4427117f1b4Smrg	 /* need cast to prevent compiler warnings */
4437117f1b4Smrg	 ctx->Pixel.ConvolutionFilterScale[c][0] = (GLfloat) params[0];
4447117f1b4Smrg	 ctx->Pixel.ConvolutionFilterScale[c][1] = (GLfloat) params[1];
4457117f1b4Smrg	 ctx->Pixel.ConvolutionFilterScale[c][2] = (GLfloat) params[2];
4467117f1b4Smrg	 ctx->Pixel.ConvolutionFilterScale[c][3] = (GLfloat) params[3];
4477117f1b4Smrg         break;
4487117f1b4Smrg      case GL_CONVOLUTION_FILTER_BIAS:
4497117f1b4Smrg	 /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */
4507117f1b4Smrg	 /* need cast to prevent compiler warnings */
4517117f1b4Smrg	 ctx->Pixel.ConvolutionFilterBias[c][0] = (GLfloat) params[0];
4527117f1b4Smrg	 ctx->Pixel.ConvolutionFilterBias[c][1] = (GLfloat) params[1];
4537117f1b4Smrg	 ctx->Pixel.ConvolutionFilterBias[c][2] = (GLfloat) params[2];
4547117f1b4Smrg	 ctx->Pixel.ConvolutionFilterBias[c][3] = (GLfloat) params[3];
4557117f1b4Smrg         break;
4567117f1b4Smrg      default:
4577117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
4587117f1b4Smrg         return;
4597117f1b4Smrg   }
4607117f1b4Smrg
4617117f1b4Smrg   ctx->NewState |= _NEW_PIXEL;
4627117f1b4Smrg}
4637117f1b4Smrg
4647117f1b4Smrg
4654a49301eSmrgstatic void GLAPIENTRY
4667117f1b4Smrg_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
4677117f1b4Smrg{
4687117f1b4Smrg   GLint baseFormat;
4697117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4707117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
4717117f1b4Smrg
4727117f1b4Smrg   if (target != GL_CONVOLUTION_1D) {
4737117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
4747117f1b4Smrg      return;
4757117f1b4Smrg   }
4767117f1b4Smrg
4777117f1b4Smrg   baseFormat = base_filter_format(internalFormat);
4787117f1b4Smrg   if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
4797117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
4807117f1b4Smrg      return;
4817117f1b4Smrg   }
4827117f1b4Smrg
4837117f1b4Smrg   if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
4847117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
4857117f1b4Smrg      return;
4867117f1b4Smrg   }
4877117f1b4Smrg
4884a49301eSmrg   if (!ctx->ReadBuffer->_ColorReadBuffer) {
4894a49301eSmrg      return;      /* no readbuffer - OK */
4904a49301eSmrg   }
4914a49301eSmrg
4927117f1b4Smrg   ctx->Driver.CopyConvolutionFilter1D( ctx, target,
4937117f1b4Smrg					internalFormat, x, y, width);
4947117f1b4Smrg}
4957117f1b4Smrg
4967117f1b4Smrg
4974a49301eSmrgstatic void GLAPIENTRY
4987117f1b4Smrg_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
4997117f1b4Smrg{
5007117f1b4Smrg   GLint baseFormat;
5017117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
5027117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
5037117f1b4Smrg
5047117f1b4Smrg   if (target != GL_CONVOLUTION_2D) {
5057117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
5067117f1b4Smrg      return;
5077117f1b4Smrg   }
5087117f1b4Smrg
5097117f1b4Smrg   baseFormat = base_filter_format(internalFormat);
5107117f1b4Smrg   if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
5117117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
5127117f1b4Smrg      return;
5137117f1b4Smrg   }
5147117f1b4Smrg
5157117f1b4Smrg   if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
5167117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
5177117f1b4Smrg      return;
5187117f1b4Smrg   }
5197117f1b4Smrg   if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
5207117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
5217117f1b4Smrg      return;
5227117f1b4Smrg   }
5237117f1b4Smrg
5244a49301eSmrg   if (!ctx->ReadBuffer->_ColorReadBuffer) {
5254a49301eSmrg      return;      /* no readbuffer - OK */
5264a49301eSmrg   }
5274a49301eSmrg
5287117f1b4Smrg   ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y,
5297117f1b4Smrg					width, height );
5307117f1b4Smrg}
5317117f1b4Smrg
5327117f1b4Smrg
5334a49301eSmrgstatic void GLAPIENTRY
5347117f1b4Smrg_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type,
5357117f1b4Smrg                           GLvoid *image)
5367117f1b4Smrg{
5377117f1b4Smrg   struct gl_convolution_attrib *filter;
5387117f1b4Smrg   GLuint row;
5397117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
5407117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
5417117f1b4Smrg
5427117f1b4Smrg   if (ctx->NewState) {
5437117f1b4Smrg      _mesa_update_state(ctx);
5447117f1b4Smrg   }
5457117f1b4Smrg
5467117f1b4Smrg   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
5477117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
5487117f1b4Smrg      return;
5497117f1b4Smrg   }
5507117f1b4Smrg
5517117f1b4Smrg   if (format == GL_COLOR_INDEX ||
5527117f1b4Smrg       format == GL_STENCIL_INDEX ||
5537117f1b4Smrg       format == GL_DEPTH_COMPONENT ||
5547117f1b4Smrg       format == GL_INTENSITY ||
5557117f1b4Smrg       type == GL_BITMAP) {
5567117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
5577117f1b4Smrg      return;
5587117f1b4Smrg   }
5597117f1b4Smrg
5607117f1b4Smrg   switch (target) {
5617117f1b4Smrg      case GL_CONVOLUTION_1D:
5627117f1b4Smrg         filter = &(ctx->Convolution1D);
5637117f1b4Smrg         break;
5647117f1b4Smrg      case GL_CONVOLUTION_2D:
5657117f1b4Smrg         filter = &(ctx->Convolution2D);
5667117f1b4Smrg         break;
5677117f1b4Smrg      default:
5687117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
5697117f1b4Smrg         return;
5707117f1b4Smrg   }
5717117f1b4Smrg
5724a49301eSmrg   image = _mesa_map_validate_pbo_dest(ctx, 2, &ctx->Pack,
5734a49301eSmrg                                       filter->Width, filter->Height, 1,
5744a49301eSmrg                                       format, type, image,
5754a49301eSmrg                                       "glGetConvolutionFilter");
5764a49301eSmrg   if (!image)
5774a49301eSmrg      return;
5787117f1b4Smrg
5797117f1b4Smrg   for (row = 0; row < filter->Height; row++) {
5807117f1b4Smrg      GLvoid *dst = _mesa_image_address2d(&ctx->Pack, image, filter->Width,
5817117f1b4Smrg                                          filter->Height, format, type,
5827117f1b4Smrg                                          row, 0);
5837117f1b4Smrg      GLfloat (*src)[4] = (GLfloat (*)[4]) (filter->Filter + row * filter->Width * 4);
5847117f1b4Smrg      _mesa_pack_rgba_span_float(ctx, filter->Width, src,
5857117f1b4Smrg                                 format, type, dst, &ctx->Pack, 0x0);
5867117f1b4Smrg   }
5877117f1b4Smrg
5884a49301eSmrg   _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
5897117f1b4Smrg}
5907117f1b4Smrg
5917117f1b4Smrg
5924a49301eSmrgstatic void GLAPIENTRY
5937117f1b4Smrg_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
5947117f1b4Smrg{
5957117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
5967117f1b4Smrg   const struct gl_convolution_attrib *conv;
5977117f1b4Smrg   GLuint c;
5987117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
5997117f1b4Smrg
6007117f1b4Smrg   switch (target) {
6017117f1b4Smrg      case GL_CONVOLUTION_1D:
6027117f1b4Smrg         c = 0;
6037117f1b4Smrg         conv = &ctx->Convolution1D;
6047117f1b4Smrg         break;
6057117f1b4Smrg      case GL_CONVOLUTION_2D:
6067117f1b4Smrg         c = 1;
6077117f1b4Smrg         conv = &ctx->Convolution2D;
6087117f1b4Smrg         break;
6097117f1b4Smrg      case GL_SEPARABLE_2D:
6107117f1b4Smrg         c = 2;
6117117f1b4Smrg         conv = &ctx->Separable2D;
6127117f1b4Smrg         break;
6137117f1b4Smrg      default:
6147117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
6157117f1b4Smrg         return;
6167117f1b4Smrg   }
6177117f1b4Smrg
6187117f1b4Smrg   switch (pname) {
6197117f1b4Smrg      case GL_CONVOLUTION_BORDER_COLOR:
6207117f1b4Smrg         COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
6217117f1b4Smrg         break;
6227117f1b4Smrg      case GL_CONVOLUTION_BORDER_MODE:
6237117f1b4Smrg         *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
6247117f1b4Smrg         break;
6257117f1b4Smrg      case GL_CONVOLUTION_FILTER_SCALE:
6267117f1b4Smrg         COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
6277117f1b4Smrg         break;
6287117f1b4Smrg      case GL_CONVOLUTION_FILTER_BIAS:
6297117f1b4Smrg         COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
6307117f1b4Smrg         break;
6317117f1b4Smrg      case GL_CONVOLUTION_FORMAT:
6327117f1b4Smrg         *params = (GLfloat) conv->Format;
6337117f1b4Smrg         break;
6347117f1b4Smrg      case GL_CONVOLUTION_WIDTH:
6357117f1b4Smrg         *params = (GLfloat) conv->Width;
6367117f1b4Smrg         break;
6377117f1b4Smrg      case GL_CONVOLUTION_HEIGHT:
6387117f1b4Smrg         *params = (GLfloat) conv->Height;
6397117f1b4Smrg         break;
6407117f1b4Smrg      case GL_MAX_CONVOLUTION_WIDTH:
6417117f1b4Smrg         *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
6427117f1b4Smrg         break;
6437117f1b4Smrg      case GL_MAX_CONVOLUTION_HEIGHT:
6447117f1b4Smrg         *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
6457117f1b4Smrg         break;
6467117f1b4Smrg      default:
6477117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
6487117f1b4Smrg         return;
6497117f1b4Smrg   }
6507117f1b4Smrg}
6517117f1b4Smrg
6527117f1b4Smrg
6534a49301eSmrgstatic void GLAPIENTRY
6547117f1b4Smrg_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
6557117f1b4Smrg{
6567117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
6577117f1b4Smrg   const struct gl_convolution_attrib *conv;
6587117f1b4Smrg   GLuint c;
6597117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
6607117f1b4Smrg
6617117f1b4Smrg   switch (target) {
6627117f1b4Smrg      case GL_CONVOLUTION_1D:
6637117f1b4Smrg         c = 0;
6647117f1b4Smrg         conv = &ctx->Convolution1D;
6657117f1b4Smrg         break;
6667117f1b4Smrg      case GL_CONVOLUTION_2D:
6677117f1b4Smrg         c = 1;
6687117f1b4Smrg         conv = &ctx->Convolution2D;
6697117f1b4Smrg         break;
6707117f1b4Smrg      case GL_SEPARABLE_2D:
6717117f1b4Smrg         c = 2;
6727117f1b4Smrg         conv = &ctx->Separable2D;
6737117f1b4Smrg         break;
6747117f1b4Smrg      default:
6757117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
6767117f1b4Smrg         return;
6777117f1b4Smrg   }
6787117f1b4Smrg
6797117f1b4Smrg   switch (pname) {
6807117f1b4Smrg      case GL_CONVOLUTION_BORDER_COLOR:
6817117f1b4Smrg         params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
6827117f1b4Smrg         params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
6837117f1b4Smrg         params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
6847117f1b4Smrg         params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
6857117f1b4Smrg         break;
6867117f1b4Smrg      case GL_CONVOLUTION_BORDER_MODE:
6877117f1b4Smrg         *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
6887117f1b4Smrg         break;
6897117f1b4Smrg      case GL_CONVOLUTION_FILTER_SCALE:
6907117f1b4Smrg         params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
6917117f1b4Smrg         params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
6927117f1b4Smrg         params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
6937117f1b4Smrg         params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
6947117f1b4Smrg         break;
6957117f1b4Smrg      case GL_CONVOLUTION_FILTER_BIAS:
6967117f1b4Smrg         params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
6977117f1b4Smrg         params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
6987117f1b4Smrg         params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
6997117f1b4Smrg         params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
7007117f1b4Smrg         break;
7017117f1b4Smrg      case GL_CONVOLUTION_FORMAT:
7027117f1b4Smrg         *params = (GLint) conv->Format;
7037117f1b4Smrg         break;
7047117f1b4Smrg      case GL_CONVOLUTION_WIDTH:
7057117f1b4Smrg         *params = (GLint) conv->Width;
7067117f1b4Smrg         break;
7077117f1b4Smrg      case GL_CONVOLUTION_HEIGHT:
7087117f1b4Smrg         *params = (GLint) conv->Height;
7097117f1b4Smrg         break;
7107117f1b4Smrg      case GL_MAX_CONVOLUTION_WIDTH:
7117117f1b4Smrg         *params = (GLint) ctx->Const.MaxConvolutionWidth;
7127117f1b4Smrg         break;
7137117f1b4Smrg      case GL_MAX_CONVOLUTION_HEIGHT:
7147117f1b4Smrg         *params = (GLint) ctx->Const.MaxConvolutionHeight;
7157117f1b4Smrg         break;
7167117f1b4Smrg      default:
7177117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
7187117f1b4Smrg         return;
7197117f1b4Smrg   }
7207117f1b4Smrg}
7217117f1b4Smrg
7227117f1b4Smrg
7234a49301eSmrgstatic void GLAPIENTRY
7247117f1b4Smrg_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type,
7257117f1b4Smrg                         GLvoid *row, GLvoid *column, GLvoid *span)
7267117f1b4Smrg{
7277117f1b4Smrg   const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
7287117f1b4Smrg   struct gl_convolution_attrib *filter;
7297117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
7307117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
7317117f1b4Smrg
7327117f1b4Smrg   if (ctx->NewState) {
7337117f1b4Smrg      _mesa_update_state(ctx);
7347117f1b4Smrg   }
7357117f1b4Smrg
7367117f1b4Smrg   if (target != GL_SEPARABLE_2D) {
7377117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
7387117f1b4Smrg      return;
7397117f1b4Smrg   }
7407117f1b4Smrg
7417117f1b4Smrg   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
7427117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
7437117f1b4Smrg                  "glGetConvolutionFilter(format or type)");
7447117f1b4Smrg      return;
7457117f1b4Smrg   }
7467117f1b4Smrg
7477117f1b4Smrg   if (format == GL_COLOR_INDEX ||
7487117f1b4Smrg       format == GL_STENCIL_INDEX ||
7497117f1b4Smrg       format == GL_DEPTH_COMPONENT ||
7507117f1b4Smrg       format == GL_INTENSITY ||
7517117f1b4Smrg       type == GL_BITMAP) {
7527117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
7537117f1b4Smrg      return;
7547117f1b4Smrg   }
7557117f1b4Smrg
7567117f1b4Smrg   filter = &ctx->Separable2D;
7577117f1b4Smrg
7584a49301eSmrg   /* Get row filter */
7594a49301eSmrg   row = _mesa_map_validate_pbo_dest(ctx, 1, &ctx->Pack,
7604a49301eSmrg                                     filter->Width, 1, 1,
7614a49301eSmrg                                     format, type, row,
7624a49301eSmrg                                     "glGetConvolutionFilter");
7637117f1b4Smrg   if (row) {
7647117f1b4Smrg      GLvoid *dst = _mesa_image_address1d(&ctx->Pack, row, filter->Width,
7657117f1b4Smrg                                          format, type, 0);
7667117f1b4Smrg      _mesa_pack_rgba_span_float(ctx, filter->Width,
7677117f1b4Smrg                                 (GLfloat (*)[4]) filter->Filter,
7687117f1b4Smrg                                 format, type, dst, &ctx->Pack, 0x0);
7694a49301eSmrg      _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
7707117f1b4Smrg   }
7717117f1b4Smrg
7724a49301eSmrg   /* get column filter */
7734a49301eSmrg   column = _mesa_map_validate_pbo_dest(ctx, 1, &ctx->Pack,
7744a49301eSmrg                                        filter->Height, 1, 1,
7754a49301eSmrg                                        format, type, column,
7764a49301eSmrg                                        "glGetConvolutionFilter");
7777117f1b4Smrg   if (column) {
7787117f1b4Smrg      GLvoid *dst = _mesa_image_address1d(&ctx->Pack, column, filter->Height,
7797117f1b4Smrg                                          format, type, 0);
7807117f1b4Smrg      GLfloat (*src)[4] = (GLfloat (*)[4]) (filter->Filter + colStart);
7817117f1b4Smrg      _mesa_pack_rgba_span_float(ctx, filter->Height, src,
7827117f1b4Smrg                                 format, type, dst, &ctx->Pack, 0x0);
7834a49301eSmrg      _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
7847117f1b4Smrg   }
7857117f1b4Smrg
7867117f1b4Smrg   (void) span;  /* unused at this time */
7877117f1b4Smrg}
7887117f1b4Smrg
7897117f1b4Smrg
7904a49301eSmrgstatic void GLAPIENTRY
7917117f1b4Smrg_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
7927117f1b4Smrg{
7937117f1b4Smrg   const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
7947117f1b4Smrg   GLint baseFormat;
7957117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
7967117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
7977117f1b4Smrg
7987117f1b4Smrg   if (target != GL_SEPARABLE_2D) {
7997117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
8007117f1b4Smrg      return;
8017117f1b4Smrg   }
8027117f1b4Smrg
8037117f1b4Smrg   baseFormat = base_filter_format(internalFormat);
8047117f1b4Smrg   if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
8057117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
8067117f1b4Smrg      return;
8077117f1b4Smrg   }
8087117f1b4Smrg
8097117f1b4Smrg   if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
8107117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
8117117f1b4Smrg      return;
8127117f1b4Smrg   }
8137117f1b4Smrg   if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
8147117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
8157117f1b4Smrg      return;
8167117f1b4Smrg   }
8177117f1b4Smrg
8187117f1b4Smrg   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
8197117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
8207117f1b4Smrg      return;
8217117f1b4Smrg   }
8227117f1b4Smrg
8237117f1b4Smrg   if (format == GL_COLOR_INDEX ||
8247117f1b4Smrg       format == GL_STENCIL_INDEX ||
8257117f1b4Smrg       format == GL_DEPTH_COMPONENT ||
8267117f1b4Smrg       format == GL_INTENSITY ||
8277117f1b4Smrg       type == GL_BITMAP) {
8287117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
8297117f1b4Smrg      return;
8307117f1b4Smrg   }
8317117f1b4Smrg
8327117f1b4Smrg   ctx->Separable2D.Format = format;
8337117f1b4Smrg   ctx->Separable2D.InternalFormat = internalFormat;
8347117f1b4Smrg   ctx->Separable2D.Width = width;
8357117f1b4Smrg   ctx->Separable2D.Height = height;
8367117f1b4Smrg
8377117f1b4Smrg   /* unpack row filter */
8384a49301eSmrg   row = _mesa_map_validate_pbo_source(ctx, 1, &ctx->Unpack,
8394a49301eSmrg                                       width, 1, 1,
8404a49301eSmrg                                       format, type, row,
8414a49301eSmrg                                       "glSeparableFilter2D");
8427117f1b4Smrg   if (row) {
8437117f1b4Smrg      _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
8447117f1b4Smrg                                    ctx->Separable2D.Filter,
8457117f1b4Smrg                                    format, type, row, &ctx->Unpack,
8464a49301eSmrg                                    0x0);  /* transferOps */
8477117f1b4Smrg      _mesa_scale_and_bias_rgba(width,
8487117f1b4Smrg                             (GLfloat (*)[4]) ctx->Separable2D.Filter,
8497117f1b4Smrg                             ctx->Pixel.ConvolutionFilterScale[2][0],
8507117f1b4Smrg                             ctx->Pixel.ConvolutionFilterScale[2][1],
8517117f1b4Smrg                             ctx->Pixel.ConvolutionFilterScale[2][2],
8527117f1b4Smrg                             ctx->Pixel.ConvolutionFilterScale[2][3],
8537117f1b4Smrg                             ctx->Pixel.ConvolutionFilterBias[2][0],
8547117f1b4Smrg                             ctx->Pixel.ConvolutionFilterBias[2][1],
8557117f1b4Smrg                             ctx->Pixel.ConvolutionFilterBias[2][2],
8567117f1b4Smrg                             ctx->Pixel.ConvolutionFilterBias[2][3]);
8574a49301eSmrg      _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
8587117f1b4Smrg   }
8597117f1b4Smrg
8607117f1b4Smrg   /* unpack column filter */
8614a49301eSmrg   column = _mesa_map_validate_pbo_source(ctx, 1, &ctx->Unpack,
8624a49301eSmrg                                          height, 1, 1,
8634a49301eSmrg                                          format, type, column,
8644a49301eSmrg                                          "glSeparableFilter2D");
8657117f1b4Smrg   if (column) {
8667117f1b4Smrg      _mesa_unpack_color_span_float(ctx, height, GL_RGBA,
8677117f1b4Smrg                                    &ctx->Separable2D.Filter[colStart],
8687117f1b4Smrg                                    format, type, column, &ctx->Unpack,
8697117f1b4Smrg                                    0); /* transferOps */
8707117f1b4Smrg
8717117f1b4Smrg      _mesa_scale_and_bias_rgba(height,
8727117f1b4Smrg                       (GLfloat (*)[4]) (ctx->Separable2D.Filter + colStart),
8737117f1b4Smrg                       ctx->Pixel.ConvolutionFilterScale[2][0],
8747117f1b4Smrg                       ctx->Pixel.ConvolutionFilterScale[2][1],
8757117f1b4Smrg                       ctx->Pixel.ConvolutionFilterScale[2][2],
8767117f1b4Smrg                       ctx->Pixel.ConvolutionFilterScale[2][3],
8777117f1b4Smrg                       ctx->Pixel.ConvolutionFilterBias[2][0],
8787117f1b4Smrg                       ctx->Pixel.ConvolutionFilterBias[2][1],
8797117f1b4Smrg                       ctx->Pixel.ConvolutionFilterBias[2][2],
8807117f1b4Smrg                       ctx->Pixel.ConvolutionFilterBias[2][3]);
8814a49301eSmrg      _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
8827117f1b4Smrg   }
8837117f1b4Smrg
8844a49301eSmrg   if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
8857117f1b4Smrg      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
8867117f1b4Smrg                              ctx->Unpack.BufferObj);
8877117f1b4Smrg   }
8887117f1b4Smrg
8897117f1b4Smrg   ctx->NewState |= _NEW_PIXEL;
8907117f1b4Smrg}
8917117f1b4Smrg
8927117f1b4Smrg
8937117f1b4Smrg/**********************************************************************/
8947117f1b4Smrg/***                   image convolution functions                  ***/
8957117f1b4Smrg/**********************************************************************/
8967117f1b4Smrg
8977117f1b4Smrgstatic void
8987117f1b4Smrgconvolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
8997117f1b4Smrg                   GLint filterWidth, const GLfloat filter[][4],
9007117f1b4Smrg                   GLfloat dest[][4])
9017117f1b4Smrg{
9027117f1b4Smrg   GLint dstWidth;
9037117f1b4Smrg   GLint i, n;
9047117f1b4Smrg
9057117f1b4Smrg   if (filterWidth >= 1)
9067117f1b4Smrg      dstWidth = srcWidth - (filterWidth - 1);
9077117f1b4Smrg   else
9087117f1b4Smrg      dstWidth = srcWidth;
9097117f1b4Smrg
9107117f1b4Smrg   if (dstWidth <= 0)
9117117f1b4Smrg      return;  /* null result */
9127117f1b4Smrg
9137117f1b4Smrg   for (i = 0; i < dstWidth; i++) {
9147117f1b4Smrg      GLfloat sumR = 0.0;
9157117f1b4Smrg      GLfloat sumG = 0.0;
9167117f1b4Smrg      GLfloat sumB = 0.0;
9177117f1b4Smrg      GLfloat sumA = 0.0;
9187117f1b4Smrg      for (n = 0; n < filterWidth; n++) {
9197117f1b4Smrg         sumR += src[i + n][RCOMP] * filter[n][RCOMP];
9207117f1b4Smrg         sumG += src[i + n][GCOMP] * filter[n][GCOMP];
9217117f1b4Smrg         sumB += src[i + n][BCOMP] * filter[n][BCOMP];
9227117f1b4Smrg         sumA += src[i + n][ACOMP] * filter[n][ACOMP];
9237117f1b4Smrg      }
9247117f1b4Smrg      dest[i][RCOMP] = sumR;
9257117f1b4Smrg      dest[i][GCOMP] = sumG;
9267117f1b4Smrg      dest[i][BCOMP] = sumB;
9277117f1b4Smrg      dest[i][ACOMP] = sumA;
9287117f1b4Smrg   }
9297117f1b4Smrg}
9307117f1b4Smrg
9317117f1b4Smrg
9327117f1b4Smrgstatic void
9337117f1b4Smrgconvolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
9347117f1b4Smrg                     GLint filterWidth, const GLfloat filter[][4],
9357117f1b4Smrg                     GLfloat dest[][4],
9367117f1b4Smrg                     const GLfloat borderColor[4])
9377117f1b4Smrg{
9387117f1b4Smrg   const GLint halfFilterWidth = filterWidth / 2;
9397117f1b4Smrg   GLint i, n;
9407117f1b4Smrg
9417117f1b4Smrg   for (i = 0; i < srcWidth; i++) {
9427117f1b4Smrg      GLfloat sumR = 0.0;
9437117f1b4Smrg      GLfloat sumG = 0.0;
9447117f1b4Smrg      GLfloat sumB = 0.0;
9457117f1b4Smrg      GLfloat sumA = 0.0;
9467117f1b4Smrg      for (n = 0; n < filterWidth; n++) {
9477117f1b4Smrg         if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
9487117f1b4Smrg            sumR += borderColor[RCOMP] * filter[n][RCOMP];
9497117f1b4Smrg            sumG += borderColor[GCOMP] * filter[n][GCOMP];
9507117f1b4Smrg            sumB += borderColor[BCOMP] * filter[n][BCOMP];
9517117f1b4Smrg            sumA += borderColor[ACOMP] * filter[n][ACOMP];
9527117f1b4Smrg         }
9537117f1b4Smrg         else {
9547117f1b4Smrg            sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
9557117f1b4Smrg            sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
9567117f1b4Smrg            sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
9577117f1b4Smrg            sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
9587117f1b4Smrg         }
9597117f1b4Smrg      }
9607117f1b4Smrg      dest[i][RCOMP] = sumR;
9617117f1b4Smrg      dest[i][GCOMP] = sumG;
9627117f1b4Smrg      dest[i][BCOMP] = sumB;
9637117f1b4Smrg      dest[i][ACOMP] = sumA;
9647117f1b4Smrg   }
9657117f1b4Smrg}
9667117f1b4Smrg
9677117f1b4Smrg
9687117f1b4Smrgstatic void
9697117f1b4Smrgconvolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
9707117f1b4Smrg                      GLint filterWidth, const GLfloat filter[][4],
9717117f1b4Smrg                      GLfloat dest[][4])
9727117f1b4Smrg{
9737117f1b4Smrg   const GLint halfFilterWidth = filterWidth / 2;
9747117f1b4Smrg   GLint i, n;
9757117f1b4Smrg
9767117f1b4Smrg   for (i = 0; i < srcWidth; i++) {
9777117f1b4Smrg      GLfloat sumR = 0.0;
9787117f1b4Smrg      GLfloat sumG = 0.0;
9797117f1b4Smrg      GLfloat sumB = 0.0;
9807117f1b4Smrg      GLfloat sumA = 0.0;
9817117f1b4Smrg      for (n = 0; n < filterWidth; n++) {
9827117f1b4Smrg         if (i + n < halfFilterWidth) {
9837117f1b4Smrg            sumR += src[0][RCOMP] * filter[n][RCOMP];
9847117f1b4Smrg            sumG += src[0][GCOMP] * filter[n][GCOMP];
9857117f1b4Smrg            sumB += src[0][BCOMP] * filter[n][BCOMP];
9867117f1b4Smrg            sumA += src[0][ACOMP] * filter[n][ACOMP];
9877117f1b4Smrg         }
9887117f1b4Smrg         else if (i + n - halfFilterWidth >= srcWidth) {
9897117f1b4Smrg            sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
9907117f1b4Smrg            sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
9917117f1b4Smrg            sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
9927117f1b4Smrg            sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
9937117f1b4Smrg         }
9947117f1b4Smrg         else {
9957117f1b4Smrg            sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
9967117f1b4Smrg            sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
9977117f1b4Smrg            sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
9987117f1b4Smrg            sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
9997117f1b4Smrg         }
10007117f1b4Smrg      }
10017117f1b4Smrg      dest[i][RCOMP] = sumR;
10027117f1b4Smrg      dest[i][GCOMP] = sumG;
10037117f1b4Smrg      dest[i][BCOMP] = sumB;
10047117f1b4Smrg      dest[i][ACOMP] = sumA;
10057117f1b4Smrg   }
10067117f1b4Smrg}
10077117f1b4Smrg
10087117f1b4Smrg
10097117f1b4Smrgstatic void
10107117f1b4Smrgconvolve_2d_reduce(GLint srcWidth, GLint srcHeight,
10117117f1b4Smrg                   const GLfloat src[][4],
10127117f1b4Smrg                   GLint filterWidth, GLint filterHeight,
10137117f1b4Smrg                   const GLfloat filter[][4],
10147117f1b4Smrg                   GLfloat dest[][4])
10157117f1b4Smrg{
10167117f1b4Smrg   GLint dstWidth, dstHeight;
10177117f1b4Smrg   GLint i, j, n, m;
10187117f1b4Smrg
10197117f1b4Smrg   if (filterWidth >= 1)
10207117f1b4Smrg      dstWidth = srcWidth - (filterWidth - 1);
10217117f1b4Smrg   else
10227117f1b4Smrg      dstWidth = srcWidth;
10237117f1b4Smrg
10247117f1b4Smrg   if (filterHeight >= 1)
10257117f1b4Smrg      dstHeight = srcHeight - (filterHeight - 1);
10267117f1b4Smrg   else
10277117f1b4Smrg      dstHeight = srcHeight;
10287117f1b4Smrg
10297117f1b4Smrg   if (dstWidth <= 0 || dstHeight <= 0)
10307117f1b4Smrg      return;
10317117f1b4Smrg
10327117f1b4Smrg   for (j = 0; j < dstHeight; j++) {
10337117f1b4Smrg      for (i = 0; i < dstWidth; i++) {
10347117f1b4Smrg         GLfloat sumR = 0.0;
10357117f1b4Smrg         GLfloat sumG = 0.0;
10367117f1b4Smrg         GLfloat sumB = 0.0;
10377117f1b4Smrg         GLfloat sumA = 0.0;
10387117f1b4Smrg         for (m = 0; m < filterHeight; m++) {
10397117f1b4Smrg            for (n = 0; n < filterWidth; n++) {
10407117f1b4Smrg               const GLint k = (j + m) * srcWidth + i + n;
10417117f1b4Smrg               const GLint f = m * filterWidth + n;
10427117f1b4Smrg               sumR += src[k][RCOMP] * filter[f][RCOMP];
10437117f1b4Smrg               sumG += src[k][GCOMP] * filter[f][GCOMP];
10447117f1b4Smrg               sumB += src[k][BCOMP] * filter[f][BCOMP];
10457117f1b4Smrg               sumA += src[k][ACOMP] * filter[f][ACOMP];
10467117f1b4Smrg            }
10477117f1b4Smrg         }
10487117f1b4Smrg         dest[j * dstWidth + i][RCOMP] = sumR;
10497117f1b4Smrg         dest[j * dstWidth + i][GCOMP] = sumG;
10507117f1b4Smrg         dest[j * dstWidth + i][BCOMP] = sumB;
10517117f1b4Smrg         dest[j * dstWidth + i][ACOMP] = sumA;
10527117f1b4Smrg      }
10537117f1b4Smrg   }
10547117f1b4Smrg}
10557117f1b4Smrg
10567117f1b4Smrg
10577117f1b4Smrgstatic void
10587117f1b4Smrgconvolve_2d_constant(GLint srcWidth, GLint srcHeight,
10597117f1b4Smrg                     const GLfloat src[][4],
10607117f1b4Smrg                     GLint filterWidth, GLint filterHeight,
10617117f1b4Smrg                     const GLfloat filter[][4],
10627117f1b4Smrg                     GLfloat dest[][4],
10637117f1b4Smrg                     const GLfloat borderColor[4])
10647117f1b4Smrg{
10657117f1b4Smrg   const GLint halfFilterWidth = filterWidth / 2;
10667117f1b4Smrg   const GLint halfFilterHeight = filterHeight / 2;
10677117f1b4Smrg   GLint i, j, n, m;
10687117f1b4Smrg
10697117f1b4Smrg   for (j = 0; j < srcHeight; j++) {
10707117f1b4Smrg      for (i = 0; i < srcWidth; i++) {
10717117f1b4Smrg         GLfloat sumR = 0.0;
10727117f1b4Smrg         GLfloat sumG = 0.0;
10737117f1b4Smrg         GLfloat sumB = 0.0;
10747117f1b4Smrg         GLfloat sumA = 0.0;
10757117f1b4Smrg         for (m = 0; m < filterHeight; m++) {
10767117f1b4Smrg            for (n = 0; n < filterWidth; n++) {
10777117f1b4Smrg               const GLint f = m * filterWidth + n;
10787117f1b4Smrg               const GLint is = i + n - halfFilterWidth;
10797117f1b4Smrg               const GLint js = j + m - halfFilterHeight;
10807117f1b4Smrg               if (is < 0 || is >= srcWidth ||
10817117f1b4Smrg                   js < 0 || js >= srcHeight) {
10827117f1b4Smrg                  sumR += borderColor[RCOMP] * filter[f][RCOMP];
10837117f1b4Smrg                  sumG += borderColor[GCOMP] * filter[f][GCOMP];
10847117f1b4Smrg                  sumB += borderColor[BCOMP] * filter[f][BCOMP];
10857117f1b4Smrg                  sumA += borderColor[ACOMP] * filter[f][ACOMP];
10867117f1b4Smrg               }
10877117f1b4Smrg               else {
10887117f1b4Smrg                  const GLint k = js * srcWidth + is;
10897117f1b4Smrg                  sumR += src[k][RCOMP] * filter[f][RCOMP];
10907117f1b4Smrg                  sumG += src[k][GCOMP] * filter[f][GCOMP];
10917117f1b4Smrg                  sumB += src[k][BCOMP] * filter[f][BCOMP];
10927117f1b4Smrg                  sumA += src[k][ACOMP] * filter[f][ACOMP];
10937117f1b4Smrg               }
10947117f1b4Smrg            }
10957117f1b4Smrg         }
10967117f1b4Smrg         dest[j * srcWidth + i][RCOMP] = sumR;
10977117f1b4Smrg         dest[j * srcWidth + i][GCOMP] = sumG;
10987117f1b4Smrg         dest[j * srcWidth + i][BCOMP] = sumB;
10997117f1b4Smrg         dest[j * srcWidth + i][ACOMP] = sumA;
11007117f1b4Smrg      }
11017117f1b4Smrg   }
11027117f1b4Smrg}
11037117f1b4Smrg
11047117f1b4Smrg
11057117f1b4Smrgstatic void
11067117f1b4Smrgconvolve_2d_replicate(GLint srcWidth, GLint srcHeight,
11077117f1b4Smrg                      const GLfloat src[][4],
11087117f1b4Smrg                      GLint filterWidth, GLint filterHeight,
11097117f1b4Smrg                      const GLfloat filter[][4],
11107117f1b4Smrg                      GLfloat dest[][4])
11117117f1b4Smrg{
11127117f1b4Smrg   const GLint halfFilterWidth = filterWidth / 2;
11137117f1b4Smrg   const GLint halfFilterHeight = filterHeight / 2;
11147117f1b4Smrg   GLint i, j, n, m;
11157117f1b4Smrg
11167117f1b4Smrg   for (j = 0; j < srcHeight; j++) {
11177117f1b4Smrg      for (i = 0; i < srcWidth; i++) {
11187117f1b4Smrg         GLfloat sumR = 0.0;
11197117f1b4Smrg         GLfloat sumG = 0.0;
11207117f1b4Smrg         GLfloat sumB = 0.0;
11217117f1b4Smrg         GLfloat sumA = 0.0;
11227117f1b4Smrg         for (m = 0; m < filterHeight; m++) {
11237117f1b4Smrg            for (n = 0; n < filterWidth; n++) {
11247117f1b4Smrg               const GLint f = m * filterWidth + n;
11257117f1b4Smrg               GLint is = i + n - halfFilterWidth;
11267117f1b4Smrg               GLint js = j + m - halfFilterHeight;
11277117f1b4Smrg               GLint k;
11287117f1b4Smrg               if (is < 0)
11297117f1b4Smrg                  is = 0;
11307117f1b4Smrg               else if (is >= srcWidth)
11317117f1b4Smrg                  is = srcWidth - 1;
11327117f1b4Smrg               if (js < 0)
11337117f1b4Smrg                  js = 0;
11347117f1b4Smrg               else if (js >= srcHeight)
11357117f1b4Smrg                  js = srcHeight - 1;
11367117f1b4Smrg               k = js * srcWidth + is;
11377117f1b4Smrg               sumR += src[k][RCOMP] * filter[f][RCOMP];
11387117f1b4Smrg               sumG += src[k][GCOMP] * filter[f][GCOMP];
11397117f1b4Smrg               sumB += src[k][BCOMP] * filter[f][BCOMP];
11407117f1b4Smrg               sumA += src[k][ACOMP] * filter[f][ACOMP];
11417117f1b4Smrg            }
11427117f1b4Smrg         }
11437117f1b4Smrg         dest[j * srcWidth + i][RCOMP] = sumR;
11447117f1b4Smrg         dest[j * srcWidth + i][GCOMP] = sumG;
11457117f1b4Smrg         dest[j * srcWidth + i][BCOMP] = sumB;
11467117f1b4Smrg         dest[j * srcWidth + i][ACOMP] = sumA;
11477117f1b4Smrg      }
11487117f1b4Smrg   }
11497117f1b4Smrg}
11507117f1b4Smrg
11517117f1b4Smrg
11527117f1b4Smrgstatic void
11537117f1b4Smrgconvolve_sep_reduce(GLint srcWidth, GLint srcHeight,
11547117f1b4Smrg                    const GLfloat src[][4],
11557117f1b4Smrg                    GLint filterWidth, GLint filterHeight,
11567117f1b4Smrg                    const GLfloat rowFilt[][4],
11577117f1b4Smrg                    const GLfloat colFilt[][4],
11587117f1b4Smrg                    GLfloat dest[][4])
11597117f1b4Smrg{
11607117f1b4Smrg   GLint dstWidth, dstHeight;
11617117f1b4Smrg   GLint i, j, n, m;
11627117f1b4Smrg
11637117f1b4Smrg   if (filterWidth >= 1)
11647117f1b4Smrg      dstWidth = srcWidth - (filterWidth - 1);
11657117f1b4Smrg   else
11667117f1b4Smrg      dstWidth = srcWidth;
11677117f1b4Smrg
11687117f1b4Smrg   if (filterHeight >= 1)
11697117f1b4Smrg      dstHeight = srcHeight - (filterHeight - 1);
11707117f1b4Smrg   else
11717117f1b4Smrg      dstHeight = srcHeight;
11727117f1b4Smrg
11737117f1b4Smrg   if (dstWidth <= 0 || dstHeight <= 0)
11747117f1b4Smrg      return;
11757117f1b4Smrg
11767117f1b4Smrg   for (j = 0; j < dstHeight; j++) {
11777117f1b4Smrg      for (i = 0; i < dstWidth; i++) {
11787117f1b4Smrg         GLfloat sumR = 0.0;
11797117f1b4Smrg         GLfloat sumG = 0.0;
11807117f1b4Smrg         GLfloat sumB = 0.0;
11817117f1b4Smrg         GLfloat sumA = 0.0;
11827117f1b4Smrg         for (m = 0; m < filterHeight; m++) {
11837117f1b4Smrg            for (n = 0; n < filterWidth; n++) {
11847117f1b4Smrg               GLint k = (j + m) * srcWidth + i + n;
11857117f1b4Smrg               sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
11867117f1b4Smrg               sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
11877117f1b4Smrg               sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
11887117f1b4Smrg               sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
11897117f1b4Smrg            }
11907117f1b4Smrg         }
11917117f1b4Smrg         dest[j * dstWidth + i][RCOMP] = sumR;
11927117f1b4Smrg         dest[j * dstWidth + i][GCOMP] = sumG;
11937117f1b4Smrg         dest[j * dstWidth + i][BCOMP] = sumB;
11947117f1b4Smrg         dest[j * dstWidth + i][ACOMP] = sumA;
11957117f1b4Smrg      }
11967117f1b4Smrg   }
11977117f1b4Smrg}
11987117f1b4Smrg
11997117f1b4Smrg
12007117f1b4Smrgstatic void
12017117f1b4Smrgconvolve_sep_constant(GLint srcWidth, GLint srcHeight,
12027117f1b4Smrg                      const GLfloat src[][4],
12037117f1b4Smrg                      GLint filterWidth, GLint filterHeight,
12047117f1b4Smrg                      const GLfloat rowFilt[][4],
12057117f1b4Smrg                      const GLfloat colFilt[][4],
12067117f1b4Smrg                      GLfloat dest[][4],
12077117f1b4Smrg                      const GLfloat borderColor[4])
12087117f1b4Smrg{
12097117f1b4Smrg   const GLint halfFilterWidth = filterWidth / 2;
12107117f1b4Smrg   const GLint halfFilterHeight = filterHeight / 2;
12117117f1b4Smrg   GLint i, j, n, m;
12127117f1b4Smrg
12137117f1b4Smrg   for (j = 0; j < srcHeight; j++) {
12147117f1b4Smrg      for (i = 0; i < srcWidth; i++) {
12157117f1b4Smrg         GLfloat sumR = 0.0;
12167117f1b4Smrg         GLfloat sumG = 0.0;
12177117f1b4Smrg         GLfloat sumB = 0.0;
12187117f1b4Smrg         GLfloat sumA = 0.0;
12197117f1b4Smrg         for (m = 0; m < filterHeight; m++) {
12207117f1b4Smrg            for (n = 0; n < filterWidth; n++) {
12217117f1b4Smrg               const GLint is = i + n - halfFilterWidth;
12227117f1b4Smrg               const GLint js = j + m - halfFilterHeight;
12237117f1b4Smrg               if (is < 0 || is >= srcWidth ||
12247117f1b4Smrg                   js < 0 || js >= srcHeight) {
12257117f1b4Smrg                  sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
12267117f1b4Smrg                  sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
12277117f1b4Smrg                  sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
12287117f1b4Smrg                  sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
12297117f1b4Smrg               }
12307117f1b4Smrg               else {
12317117f1b4Smrg                  GLint k = js * srcWidth + is;
12327117f1b4Smrg                  sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
12337117f1b4Smrg                  sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
12347117f1b4Smrg                  sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
12357117f1b4Smrg                  sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
12367117f1b4Smrg               }
12377117f1b4Smrg
12387117f1b4Smrg            }
12397117f1b4Smrg         }
12407117f1b4Smrg         dest[j * srcWidth + i][RCOMP] = sumR;
12417117f1b4Smrg         dest[j * srcWidth + i][GCOMP] = sumG;
12427117f1b4Smrg         dest[j * srcWidth + i][BCOMP] = sumB;
12437117f1b4Smrg         dest[j * srcWidth + i][ACOMP] = sumA;
12447117f1b4Smrg      }
12457117f1b4Smrg   }
12467117f1b4Smrg}
12477117f1b4Smrg
12487117f1b4Smrg
12497117f1b4Smrgstatic void
12507117f1b4Smrgconvolve_sep_replicate(GLint srcWidth, GLint srcHeight,
12517117f1b4Smrg                       const GLfloat src[][4],
12527117f1b4Smrg                       GLint filterWidth, GLint filterHeight,
12537117f1b4Smrg                       const GLfloat rowFilt[][4],
12547117f1b4Smrg                       const GLfloat colFilt[][4],
12557117f1b4Smrg                       GLfloat dest[][4])
12567117f1b4Smrg{
12577117f1b4Smrg   const GLint halfFilterWidth = filterWidth / 2;
12587117f1b4Smrg   const GLint halfFilterHeight = filterHeight / 2;
12597117f1b4Smrg   GLint i, j, n, m;
12607117f1b4Smrg
12617117f1b4Smrg   for (j = 0; j < srcHeight; j++) {
12627117f1b4Smrg      for (i = 0; i < srcWidth; i++) {
12637117f1b4Smrg         GLfloat sumR = 0.0;
12647117f1b4Smrg         GLfloat sumG = 0.0;
12657117f1b4Smrg         GLfloat sumB = 0.0;
12667117f1b4Smrg         GLfloat sumA = 0.0;
12677117f1b4Smrg         for (m = 0; m < filterHeight; m++) {
12687117f1b4Smrg            for (n = 0; n < filterWidth; n++) {
12697117f1b4Smrg               GLint is = i + n - halfFilterWidth;
12707117f1b4Smrg               GLint js = j + m - halfFilterHeight;
12717117f1b4Smrg               GLint k;
12727117f1b4Smrg               if (is < 0)
12737117f1b4Smrg                  is = 0;
12747117f1b4Smrg               else if (is >= srcWidth)
12757117f1b4Smrg                  is = srcWidth - 1;
12767117f1b4Smrg               if (js < 0)
12777117f1b4Smrg                  js = 0;
12787117f1b4Smrg               else if (js >= srcHeight)
12797117f1b4Smrg                  js = srcHeight - 1;
12807117f1b4Smrg               k = js * srcWidth + is;
12817117f1b4Smrg               sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
12827117f1b4Smrg               sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
12837117f1b4Smrg               sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
12847117f1b4Smrg               sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
12857117f1b4Smrg            }
12867117f1b4Smrg         }
12877117f1b4Smrg         dest[j * srcWidth + i][RCOMP] = sumR;
12887117f1b4Smrg         dest[j * srcWidth + i][GCOMP] = sumG;
12897117f1b4Smrg         dest[j * srcWidth + i][BCOMP] = sumB;
12907117f1b4Smrg         dest[j * srcWidth + i][ACOMP] = sumA;
12917117f1b4Smrg      }
12927117f1b4Smrg   }
12937117f1b4Smrg}
12947117f1b4Smrg
12957117f1b4Smrg
12967117f1b4Smrg
12977117f1b4Smrgvoid
12987117f1b4Smrg_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
12997117f1b4Smrg                        const GLfloat *srcImage, GLfloat *dstImage)
13007117f1b4Smrg{
13017117f1b4Smrg   switch (ctx->Pixel.ConvolutionBorderMode[0]) {
13027117f1b4Smrg      case GL_REDUCE:
13037117f1b4Smrg         convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
13047117f1b4Smrg                            ctx->Convolution1D.Width,
13057117f1b4Smrg                            (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
13067117f1b4Smrg                            (GLfloat (*)[4]) dstImage);
13077117f1b4Smrg         *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
13087117f1b4Smrg         break;
13097117f1b4Smrg      case GL_CONSTANT_BORDER:
13107117f1b4Smrg         convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
13117117f1b4Smrg                              ctx->Convolution1D.Width,
13127117f1b4Smrg                              (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
13137117f1b4Smrg                              (GLfloat (*)[4]) dstImage,
13147117f1b4Smrg                              ctx->Pixel.ConvolutionBorderColor[0]);
13157117f1b4Smrg         break;
13167117f1b4Smrg      case GL_REPLICATE_BORDER:
13177117f1b4Smrg         convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
13187117f1b4Smrg                              ctx->Convolution1D.Width,
13197117f1b4Smrg                              (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
13207117f1b4Smrg                              (GLfloat (*)[4]) dstImage);
13217117f1b4Smrg         break;
13227117f1b4Smrg      default:
13237117f1b4Smrg         ;
13247117f1b4Smrg   }
13257117f1b4Smrg}
13267117f1b4Smrg
13277117f1b4Smrg
13287117f1b4Smrgvoid
13297117f1b4Smrg_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
13307117f1b4Smrg                        const GLfloat *srcImage, GLfloat *dstImage)
13317117f1b4Smrg{
13327117f1b4Smrg   switch (ctx->Pixel.ConvolutionBorderMode[1]) {
13337117f1b4Smrg      case GL_REDUCE:
13347117f1b4Smrg         convolve_2d_reduce(*width, *height,
13357117f1b4Smrg                            (const GLfloat (*)[4]) srcImage,
13367117f1b4Smrg                            ctx->Convolution2D.Width,
13377117f1b4Smrg                            ctx->Convolution2D.Height,
13387117f1b4Smrg                            (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
13397117f1b4Smrg                            (GLfloat (*)[4]) dstImage);
13407117f1b4Smrg         *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
13417117f1b4Smrg         *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
13427117f1b4Smrg         break;
13437117f1b4Smrg      case GL_CONSTANT_BORDER:
13447117f1b4Smrg         convolve_2d_constant(*width, *height,
13457117f1b4Smrg                              (const GLfloat (*)[4]) srcImage,
13467117f1b4Smrg                              ctx->Convolution2D.Width,
13477117f1b4Smrg                              ctx->Convolution2D.Height,
13487117f1b4Smrg                              (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
13497117f1b4Smrg                              (GLfloat (*)[4]) dstImage,
13507117f1b4Smrg                              ctx->Pixel.ConvolutionBorderColor[1]);
13517117f1b4Smrg         break;
13527117f1b4Smrg      case GL_REPLICATE_BORDER:
13537117f1b4Smrg         convolve_2d_replicate(*width, *height,
13547117f1b4Smrg                               (const GLfloat (*)[4]) srcImage,
13557117f1b4Smrg                               ctx->Convolution2D.Width,
13567117f1b4Smrg                               ctx->Convolution2D.Height,
13577117f1b4Smrg                               (const GLfloat (*)[4])ctx->Convolution2D.Filter,
13587117f1b4Smrg                               (GLfloat (*)[4]) dstImage);
13597117f1b4Smrg         break;
13607117f1b4Smrg      default:
13617117f1b4Smrg         ;
13627117f1b4Smrg      }
13637117f1b4Smrg}
13647117f1b4Smrg
13657117f1b4Smrg
13667117f1b4Smrgvoid
13677117f1b4Smrg_mesa_convolve_sep_image(const GLcontext *ctx,
13687117f1b4Smrg                         GLsizei *width, GLsizei *height,
13697117f1b4Smrg                         const GLfloat *srcImage, GLfloat *dstImage)
13707117f1b4Smrg{
13717117f1b4Smrg   const GLfloat *rowFilter = ctx->Separable2D.Filter;
13727117f1b4Smrg   const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
13737117f1b4Smrg
13747117f1b4Smrg   switch (ctx->Pixel.ConvolutionBorderMode[2]) {
13757117f1b4Smrg      case GL_REDUCE:
13767117f1b4Smrg         convolve_sep_reduce(*width, *height,
13777117f1b4Smrg                             (const GLfloat (*)[4]) srcImage,
13787117f1b4Smrg                             ctx->Separable2D.Width,
13797117f1b4Smrg                             ctx->Separable2D.Height,
13807117f1b4Smrg                             (const GLfloat (*)[4]) rowFilter,
13817117f1b4Smrg                             (const GLfloat (*)[4]) colFilter,
13827117f1b4Smrg                             (GLfloat (*)[4]) dstImage);
13837117f1b4Smrg         *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
13847117f1b4Smrg         *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
13857117f1b4Smrg         break;
13867117f1b4Smrg      case GL_CONSTANT_BORDER:
13877117f1b4Smrg         convolve_sep_constant(*width, *height,
13887117f1b4Smrg                               (const GLfloat (*)[4]) srcImage,
13897117f1b4Smrg                               ctx->Separable2D.Width,
13907117f1b4Smrg                               ctx->Separable2D.Height,
13917117f1b4Smrg                               (const GLfloat (*)[4]) rowFilter,
13927117f1b4Smrg                               (const GLfloat (*)[4]) colFilter,
13937117f1b4Smrg                               (GLfloat (*)[4]) dstImage,
13947117f1b4Smrg                               ctx->Pixel.ConvolutionBorderColor[2]);
13957117f1b4Smrg         break;
13967117f1b4Smrg      case GL_REPLICATE_BORDER:
13977117f1b4Smrg         convolve_sep_replicate(*width, *height,
13987117f1b4Smrg                                (const GLfloat (*)[4]) srcImage,
13997117f1b4Smrg                                ctx->Separable2D.Width,
14007117f1b4Smrg                                ctx->Separable2D.Height,
14017117f1b4Smrg                                (const GLfloat (*)[4]) rowFilter,
14027117f1b4Smrg                                (const GLfloat (*)[4]) colFilter,
14037117f1b4Smrg                                (GLfloat (*)[4]) dstImage);
14047117f1b4Smrg         break;
14057117f1b4Smrg      default:
14067117f1b4Smrg         ;
14077117f1b4Smrg   }
14087117f1b4Smrg}
14097117f1b4Smrg
14107117f1b4Smrg
14117117f1b4Smrg
14127117f1b4Smrg/*
14137117f1b4Smrg * This function computes an image's size after convolution.
14147117f1b4Smrg * If the convolution border mode is GL_REDUCE, the post-convolution
14157117f1b4Smrg * image will be smaller than the original.
14167117f1b4Smrg */
14177117f1b4Smrgvoid
14187117f1b4Smrg_mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions,
14197117f1b4Smrg                                   GLsizei *width, GLsizei *height)
14207117f1b4Smrg{
14217117f1b4Smrg   if (ctx->Pixel.Convolution1DEnabled
14227117f1b4Smrg       && dimensions == 1
14237117f1b4Smrg       && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) {
14247117f1b4Smrg      *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
14257117f1b4Smrg   }
14267117f1b4Smrg   else if (ctx->Pixel.Convolution2DEnabled
14277117f1b4Smrg            && dimensions > 1
14287117f1b4Smrg            && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) {
14297117f1b4Smrg      *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
14307117f1b4Smrg      *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
14317117f1b4Smrg   }
14327117f1b4Smrg   else if (ctx->Pixel.Separable2DEnabled
14337117f1b4Smrg            && dimensions > 1
14347117f1b4Smrg            && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) {
14357117f1b4Smrg      *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
14367117f1b4Smrg      *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
14377117f1b4Smrg   }
14387117f1b4Smrg}
14394a49301eSmrg
14404a49301eSmrg
14414a49301eSmrgvoid
14424a49301eSmrg_mesa_init_convolve_dispatch(struct _glapi_table *disp)
14434a49301eSmrg{
14444a49301eSmrg   SET_ConvolutionFilter1D(disp, _mesa_ConvolutionFilter1D);
14454a49301eSmrg   SET_ConvolutionFilter2D(disp, _mesa_ConvolutionFilter2D);
14464a49301eSmrg   SET_ConvolutionParameterf(disp, _mesa_ConvolutionParameterf);
14474a49301eSmrg   SET_ConvolutionParameterfv(disp, _mesa_ConvolutionParameterfv);
14484a49301eSmrg   SET_ConvolutionParameteri(disp, _mesa_ConvolutionParameteri);
14494a49301eSmrg   SET_ConvolutionParameteriv(disp, _mesa_ConvolutionParameteriv);
14504a49301eSmrg   SET_CopyConvolutionFilter1D(disp, _mesa_CopyConvolutionFilter1D);
14514a49301eSmrg   SET_CopyConvolutionFilter2D(disp, _mesa_CopyConvolutionFilter2D);
14524a49301eSmrg   SET_GetConvolutionFilter(disp, _mesa_GetConvolutionFilter);
14534a49301eSmrg   SET_GetConvolutionParameterfv(disp, _mesa_GetConvolutionParameterfv);
14544a49301eSmrg   SET_GetConvolutionParameteriv(disp, _mesa_GetConvolutionParameteriv);
14554a49301eSmrg   SET_SeparableFilter2D(disp, _mesa_SeparableFilter2D);
14564a49301eSmrg   SET_GetSeparableFilter(disp, _mesa_GetSeparableFilter);
14574a49301eSmrg}
14584a49301eSmrg
14594a49301eSmrg
14604a49301eSmrg#endif /* FEATURE_convolve */
1461