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