convolve.c revision cdc920a0
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5.2 4 * 5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26/* 27 * Image convolution functions. 28 * 29 * Notes: filter kernel elements are indexed by <n> and <m> as in 30 * the GL spec. 31 */ 32 33 34#include "glheader.h" 35#include "bufferobj.h" 36#include "colormac.h" 37#include "convolve.h" 38#include "context.h" 39#include "image.h" 40#include "mtypes.h" 41#include "state.h" 42#include "main/dispatch.h" 43 44 45#if FEATURE_convolve 46 47 48/* 49 * Given an internalFormat token passed to glConvolutionFilter 50 * or glSeparableFilter, return the corresponding base format. 51 * Return -1 if invalid token. 52 */ 53static GLint 54base_filter_format( GLenum format ) 55{ 56 switch (format) { 57 case GL_ALPHA: 58 case GL_ALPHA4: 59 case GL_ALPHA8: 60 case GL_ALPHA12: 61 case GL_ALPHA16: 62 return GL_ALPHA; 63 case GL_LUMINANCE: 64 case GL_LUMINANCE4: 65 case GL_LUMINANCE8: 66 case GL_LUMINANCE12: 67 case GL_LUMINANCE16: 68 return GL_LUMINANCE; 69 case GL_LUMINANCE_ALPHA: 70 case GL_LUMINANCE4_ALPHA4: 71 case GL_LUMINANCE6_ALPHA2: 72 case GL_LUMINANCE8_ALPHA8: 73 case GL_LUMINANCE12_ALPHA4: 74 case GL_LUMINANCE12_ALPHA12: 75 case GL_LUMINANCE16_ALPHA16: 76 return GL_LUMINANCE_ALPHA; 77 case GL_INTENSITY: 78 case GL_INTENSITY4: 79 case GL_INTENSITY8: 80 case GL_INTENSITY12: 81 case GL_INTENSITY16: 82 return GL_INTENSITY; 83 case GL_RGB: 84 case GL_R3_G3_B2: 85 case GL_RGB4: 86 case GL_RGB5: 87 case GL_RGB8: 88 case GL_RGB10: 89 case GL_RGB12: 90 case GL_RGB16: 91 return GL_RGB; 92 case 4: 93 case GL_RGBA: 94 case GL_RGBA2: 95 case GL_RGBA4: 96 case GL_RGB5_A1: 97 case GL_RGBA8: 98 case GL_RGB10_A2: 99 case GL_RGBA12: 100 case GL_RGBA16: 101 return GL_RGBA; 102 default: 103 return -1; /* error */ 104 } 105} 106 107 108void GLAPIENTRY 109_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image) 110{ 111 GLint baseFormat; 112 GET_CURRENT_CONTEXT(ctx); 113 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 114 115 if (target != GL_CONVOLUTION_1D) { 116 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)"); 117 return; 118 } 119 120 baseFormat = base_filter_format(internalFormat); 121 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) { 122 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)"); 123 return; 124 } 125 126 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) { 127 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)"); 128 return; 129 } 130 131 if (!_mesa_is_legal_format_and_type(ctx, format, type)) { 132 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter1D(format or type)"); 133 return; 134 } 135 136 if (format == GL_COLOR_INDEX || 137 format == GL_STENCIL_INDEX || 138 format == GL_DEPTH_COMPONENT || 139 format == GL_INTENSITY || 140 type == GL_BITMAP) { 141 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)"); 142 return; 143 } 144 145 ctx->Convolution1D.Format = format; 146 ctx->Convolution1D.InternalFormat = internalFormat; 147 ctx->Convolution1D.Width = width; 148 ctx->Convolution1D.Height = 1; 149 150 image = _mesa_map_validate_pbo_source(ctx, 151 1, &ctx->Unpack, width, 1, 1, 152 format, type, image, 153 "glConvolutionFilter1D"); 154 if (!image) 155 return; 156 157 _mesa_unpack_color_span_float(ctx, width, GL_RGBA, 158 ctx->Convolution1D.Filter, 159 format, type, image, &ctx->Unpack, 160 0); /* transferOps */ 161 162 _mesa_unmap_pbo_source(ctx, &ctx->Unpack); 163 164 _mesa_scale_and_bias_rgba(width, 165 (GLfloat (*)[4]) ctx->Convolution1D.Filter, 166 ctx->Pixel.ConvolutionFilterScale[0][0], 167 ctx->Pixel.ConvolutionFilterScale[0][1], 168 ctx->Pixel.ConvolutionFilterScale[0][2], 169 ctx->Pixel.ConvolutionFilterScale[0][3], 170 ctx->Pixel.ConvolutionFilterBias[0][0], 171 ctx->Pixel.ConvolutionFilterBias[0][1], 172 ctx->Pixel.ConvolutionFilterBias[0][2], 173 ctx->Pixel.ConvolutionFilterBias[0][3]); 174 175 ctx->NewState |= _NEW_PIXEL; 176} 177 178 179void GLAPIENTRY 180_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image) 181{ 182 GLint baseFormat; 183 GLint i; 184 GET_CURRENT_CONTEXT(ctx); 185 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 186 187 if (target != GL_CONVOLUTION_2D) { 188 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)"); 189 return; 190 } 191 192 baseFormat = base_filter_format(internalFormat); 193 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) { 194 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)"); 195 return; 196 } 197 198 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) { 199 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)"); 200 return; 201 } 202 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) { 203 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)"); 204 return; 205 } 206 207 if (!_mesa_is_legal_format_and_type(ctx, format, type)) { 208 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)"); 209 return; 210 } 211 if (format == GL_COLOR_INDEX || 212 format == GL_STENCIL_INDEX || 213 format == GL_DEPTH_COMPONENT || 214 format == GL_INTENSITY || 215 type == GL_BITMAP) { 216 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)"); 217 return; 218 } 219 220 /* this should have been caught earlier */ 221 assert(_mesa_components_in_format(format)); 222 223 ctx->Convolution2D.Format = format; 224 ctx->Convolution2D.InternalFormat = internalFormat; 225 ctx->Convolution2D.Width = width; 226 ctx->Convolution2D.Height = height; 227 228 image = _mesa_map_validate_pbo_source(ctx, 229 2, &ctx->Unpack, width, height, 1, 230 format, type, image, 231 "glConvolutionFilter2D"); 232 if (!image) 233 return; 234 235 /* Unpack filter image. We always store filters in RGBA format. */ 236 for (i = 0; i < height; i++) { 237 const GLvoid *src = _mesa_image_address2d(&ctx->Unpack, image, width, 238 height, format, type, i, 0); 239 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4; 240 _mesa_unpack_color_span_float(ctx, width, GL_RGBA, dst, 241 format, type, src, &ctx->Unpack, 242 0); /* transferOps */ 243 } 244 245 _mesa_unmap_pbo_source(ctx, &ctx->Unpack); 246 247 _mesa_scale_and_bias_rgba(width * height, 248 (GLfloat (*)[4]) ctx->Convolution2D.Filter, 249 ctx->Pixel.ConvolutionFilterScale[1][0], 250 ctx->Pixel.ConvolutionFilterScale[1][1], 251 ctx->Pixel.ConvolutionFilterScale[1][2], 252 ctx->Pixel.ConvolutionFilterScale[1][3], 253 ctx->Pixel.ConvolutionFilterBias[1][0], 254 ctx->Pixel.ConvolutionFilterBias[1][1], 255 ctx->Pixel.ConvolutionFilterBias[1][2], 256 ctx->Pixel.ConvolutionFilterBias[1][3]); 257 258 ctx->NewState |= _NEW_PIXEL; 259} 260 261 262static void GLAPIENTRY 263_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param) 264{ 265 GET_CURRENT_CONTEXT(ctx); 266 GLuint c; 267 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 268 269 switch (target) { 270 case GL_CONVOLUTION_1D: 271 c = 0; 272 break; 273 case GL_CONVOLUTION_2D: 274 c = 1; 275 break; 276 case GL_SEPARABLE_2D: 277 c = 2; 278 break; 279 default: 280 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)"); 281 return; 282 } 283 284 switch (pname) { 285 case GL_CONVOLUTION_BORDER_MODE: 286 if (param == (GLfloat) GL_REDUCE || 287 param == (GLfloat) GL_CONSTANT_BORDER || 288 param == (GLfloat) GL_REPLICATE_BORDER) { 289 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param; 290 } 291 else { 292 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)"); 293 return; 294 } 295 break; 296 default: 297 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)"); 298 return; 299 } 300 301 ctx->NewState |= _NEW_PIXEL; 302} 303 304 305static void GLAPIENTRY 306_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params) 307{ 308 GET_CURRENT_CONTEXT(ctx); 309 GLuint c; 310 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 311 312 switch (target) { 313 case GL_CONVOLUTION_1D: 314 c = 0; 315 break; 316 case GL_CONVOLUTION_2D: 317 c = 1; 318 break; 319 case GL_SEPARABLE_2D: 320 c = 2; 321 break; 322 default: 323 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)"); 324 return; 325 } 326 327 switch (pname) { 328 case GL_CONVOLUTION_BORDER_COLOR: 329 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params); 330 break; 331 case GL_CONVOLUTION_BORDER_MODE: 332 if (params[0] == (GLfloat) GL_REDUCE || 333 params[0] == (GLfloat) GL_CONSTANT_BORDER || 334 params[0] == (GLfloat) GL_REPLICATE_BORDER) { 335 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0]; 336 } 337 else { 338 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)"); 339 return; 340 } 341 break; 342 case GL_CONVOLUTION_FILTER_SCALE: 343 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); 344 break; 345 case GL_CONVOLUTION_FILTER_BIAS: 346 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); 347 break; 348 default: 349 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)"); 350 return; 351 } 352 353 ctx->NewState |= _NEW_PIXEL; 354} 355 356 357static void GLAPIENTRY 358_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param) 359{ 360 GET_CURRENT_CONTEXT(ctx); 361 GLuint c; 362 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 363 364 switch (target) { 365 case GL_CONVOLUTION_1D: 366 c = 0; 367 break; 368 case GL_CONVOLUTION_2D: 369 c = 1; 370 break; 371 case GL_SEPARABLE_2D: 372 c = 2; 373 break; 374 default: 375 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)"); 376 return; 377 } 378 379 switch (pname) { 380 case GL_CONVOLUTION_BORDER_MODE: 381 if (param == (GLint) GL_REDUCE || 382 param == (GLint) GL_CONSTANT_BORDER || 383 param == (GLint) GL_REPLICATE_BORDER) { 384 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param; 385 } 386 else { 387 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)"); 388 return; 389 } 390 break; 391 default: 392 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)"); 393 return; 394 } 395 396 ctx->NewState |= _NEW_PIXEL; 397} 398 399 400static void GLAPIENTRY 401_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params) 402{ 403 GET_CURRENT_CONTEXT(ctx); 404 GLuint c; 405 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 406 407 switch (target) { 408 case GL_CONVOLUTION_1D: 409 c = 0; 410 break; 411 case GL_CONVOLUTION_2D: 412 c = 1; 413 break; 414 case GL_SEPARABLE_2D: 415 c = 2; 416 break; 417 default: 418 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)"); 419 return; 420 } 421 422 switch (pname) { 423 case GL_CONVOLUTION_BORDER_COLOR: 424 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]); 425 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]); 426 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]); 427 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]); 428 break; 429 case GL_CONVOLUTION_BORDER_MODE: 430 if (params[0] == (GLint) GL_REDUCE || 431 params[0] == (GLint) GL_CONSTANT_BORDER || 432 params[0] == (GLint) GL_REPLICATE_BORDER) { 433 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0]; 434 } 435 else { 436 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)"); 437 return; 438 } 439 break; 440 case GL_CONVOLUTION_FILTER_SCALE: 441 /* COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); */ 442 /* need cast to prevent compiler warnings */ 443 ctx->Pixel.ConvolutionFilterScale[c][0] = (GLfloat) params[0]; 444 ctx->Pixel.ConvolutionFilterScale[c][1] = (GLfloat) params[1]; 445 ctx->Pixel.ConvolutionFilterScale[c][2] = (GLfloat) params[2]; 446 ctx->Pixel.ConvolutionFilterScale[c][3] = (GLfloat) params[3]; 447 break; 448 case GL_CONVOLUTION_FILTER_BIAS: 449 /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */ 450 /* need cast to prevent compiler warnings */ 451 ctx->Pixel.ConvolutionFilterBias[c][0] = (GLfloat) params[0]; 452 ctx->Pixel.ConvolutionFilterBias[c][1] = (GLfloat) params[1]; 453 ctx->Pixel.ConvolutionFilterBias[c][2] = (GLfloat) params[2]; 454 ctx->Pixel.ConvolutionFilterBias[c][3] = (GLfloat) params[3]; 455 break; 456 default: 457 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)"); 458 return; 459 } 460 461 ctx->NewState |= _NEW_PIXEL; 462} 463 464 465static void GLAPIENTRY 466_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width) 467{ 468 GLint baseFormat; 469 GET_CURRENT_CONTEXT(ctx); 470 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 471 472 if (target != GL_CONVOLUTION_1D) { 473 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)"); 474 return; 475 } 476 477 baseFormat = base_filter_format(internalFormat); 478 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) { 479 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)"); 480 return; 481 } 482 483 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) { 484 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)"); 485 return; 486 } 487 488 if (!ctx->ReadBuffer->_ColorReadBuffer) { 489 return; /* no readbuffer - OK */ 490 } 491 492 ctx->Driver.CopyConvolutionFilter1D( ctx, target, 493 internalFormat, x, y, width); 494} 495 496 497static void GLAPIENTRY 498_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height) 499{ 500 GLint baseFormat; 501 GET_CURRENT_CONTEXT(ctx); 502 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 503 504 if (target != GL_CONVOLUTION_2D) { 505 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)"); 506 return; 507 } 508 509 baseFormat = base_filter_format(internalFormat); 510 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) { 511 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)"); 512 return; 513 } 514 515 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) { 516 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)"); 517 return; 518 } 519 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) { 520 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)"); 521 return; 522 } 523 524 if (!ctx->ReadBuffer->_ColorReadBuffer) { 525 return; /* no readbuffer - OK */ 526 } 527 528 ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y, 529 width, height ); 530} 531 532 533static void GLAPIENTRY 534_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, 535 GLvoid *image) 536{ 537 struct gl_convolution_attrib *filter; 538 GLuint row; 539 GET_CURRENT_CONTEXT(ctx); 540 ASSERT_OUTSIDE_BEGIN_END(ctx); 541 542 if (ctx->NewState) { 543 _mesa_update_state(ctx); 544 } 545 546 if (!_mesa_is_legal_format_and_type(ctx, format, type)) { 547 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)"); 548 return; 549 } 550 551 if (format == GL_COLOR_INDEX || 552 format == GL_STENCIL_INDEX || 553 format == GL_DEPTH_COMPONENT || 554 format == GL_INTENSITY || 555 type == GL_BITMAP) { 556 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)"); 557 return; 558 } 559 560 switch (target) { 561 case GL_CONVOLUTION_1D: 562 filter = &(ctx->Convolution1D); 563 break; 564 case GL_CONVOLUTION_2D: 565 filter = &(ctx->Convolution2D); 566 break; 567 default: 568 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)"); 569 return; 570 } 571 572 image = _mesa_map_validate_pbo_dest(ctx, 2, &ctx->Pack, 573 filter->Width, filter->Height, 1, 574 format, type, image, 575 "glGetConvolutionFilter"); 576 if (!image) 577 return; 578 579 for (row = 0; row < filter->Height; row++) { 580 GLvoid *dst = _mesa_image_address2d(&ctx->Pack, image, filter->Width, 581 filter->Height, format, type, 582 row, 0); 583 GLfloat (*src)[4] = (GLfloat (*)[4]) (filter->Filter + row * filter->Width * 4); 584 _mesa_pack_rgba_span_float(ctx, filter->Width, src, 585 format, type, dst, &ctx->Pack, 0x0); 586 } 587 588 _mesa_unmap_pbo_dest(ctx, &ctx->Pack); 589} 590 591 592static void GLAPIENTRY 593_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params) 594{ 595 GET_CURRENT_CONTEXT(ctx); 596 const struct gl_convolution_attrib *conv; 597 GLuint c; 598 ASSERT_OUTSIDE_BEGIN_END(ctx); 599 600 switch (target) { 601 case GL_CONVOLUTION_1D: 602 c = 0; 603 conv = &ctx->Convolution1D; 604 break; 605 case GL_CONVOLUTION_2D: 606 c = 1; 607 conv = &ctx->Convolution2D; 608 break; 609 case GL_SEPARABLE_2D: 610 c = 2; 611 conv = &ctx->Separable2D; 612 break; 613 default: 614 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)"); 615 return; 616 } 617 618 switch (pname) { 619 case GL_CONVOLUTION_BORDER_COLOR: 620 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]); 621 break; 622 case GL_CONVOLUTION_BORDER_MODE: 623 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c]; 624 break; 625 case GL_CONVOLUTION_FILTER_SCALE: 626 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]); 627 break; 628 case GL_CONVOLUTION_FILTER_BIAS: 629 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]); 630 break; 631 case GL_CONVOLUTION_FORMAT: 632 *params = (GLfloat) conv->Format; 633 break; 634 case GL_CONVOLUTION_WIDTH: 635 *params = (GLfloat) conv->Width; 636 break; 637 case GL_CONVOLUTION_HEIGHT: 638 *params = (GLfloat) conv->Height; 639 break; 640 case GL_MAX_CONVOLUTION_WIDTH: 641 *params = (GLfloat) ctx->Const.MaxConvolutionWidth; 642 break; 643 case GL_MAX_CONVOLUTION_HEIGHT: 644 *params = (GLfloat) ctx->Const.MaxConvolutionHeight; 645 break; 646 default: 647 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)"); 648 return; 649 } 650} 651 652 653static void GLAPIENTRY 654_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params) 655{ 656 GET_CURRENT_CONTEXT(ctx); 657 const struct gl_convolution_attrib *conv; 658 GLuint c; 659 ASSERT_OUTSIDE_BEGIN_END(ctx); 660 661 switch (target) { 662 case GL_CONVOLUTION_1D: 663 c = 0; 664 conv = &ctx->Convolution1D; 665 break; 666 case GL_CONVOLUTION_2D: 667 c = 1; 668 conv = &ctx->Convolution2D; 669 break; 670 case GL_SEPARABLE_2D: 671 c = 2; 672 conv = &ctx->Separable2D; 673 break; 674 default: 675 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)"); 676 return; 677 } 678 679 switch (pname) { 680 case GL_CONVOLUTION_BORDER_COLOR: 681 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]); 682 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]); 683 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]); 684 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]); 685 break; 686 case GL_CONVOLUTION_BORDER_MODE: 687 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c]; 688 break; 689 case GL_CONVOLUTION_FILTER_SCALE: 690 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0]; 691 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1]; 692 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2]; 693 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3]; 694 break; 695 case GL_CONVOLUTION_FILTER_BIAS: 696 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0]; 697 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1]; 698 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2]; 699 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3]; 700 break; 701 case GL_CONVOLUTION_FORMAT: 702 *params = (GLint) conv->Format; 703 break; 704 case GL_CONVOLUTION_WIDTH: 705 *params = (GLint) conv->Width; 706 break; 707 case GL_CONVOLUTION_HEIGHT: 708 *params = (GLint) conv->Height; 709 break; 710 case GL_MAX_CONVOLUTION_WIDTH: 711 *params = (GLint) ctx->Const.MaxConvolutionWidth; 712 break; 713 case GL_MAX_CONVOLUTION_HEIGHT: 714 *params = (GLint) ctx->Const.MaxConvolutionHeight; 715 break; 716 default: 717 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)"); 718 return; 719 } 720} 721 722 723static void GLAPIENTRY 724_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, 725 GLvoid *row, GLvoid *column, GLvoid *span) 726{ 727 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4; 728 struct gl_convolution_attrib *filter; 729 GET_CURRENT_CONTEXT(ctx); 730 ASSERT_OUTSIDE_BEGIN_END(ctx); 731 732 if (ctx->NewState) { 733 _mesa_update_state(ctx); 734 } 735 736 if (target != GL_SEPARABLE_2D) { 737 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)"); 738 return; 739 } 740 741 if (!_mesa_is_legal_format_and_type(ctx, format, type)) { 742 _mesa_error(ctx, GL_INVALID_OPERATION, 743 "glGetConvolutionFilter(format or type)"); 744 return; 745 } 746 747 if (format == GL_COLOR_INDEX || 748 format == GL_STENCIL_INDEX || 749 format == GL_DEPTH_COMPONENT || 750 format == GL_INTENSITY || 751 type == GL_BITMAP) { 752 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)"); 753 return; 754 } 755 756 filter = &ctx->Separable2D; 757 758 /* Get row filter */ 759 row = _mesa_map_validate_pbo_dest(ctx, 1, &ctx->Pack, 760 filter->Width, 1, 1, 761 format, type, row, 762 "glGetConvolutionFilter"); 763 if (row) { 764 GLvoid *dst = _mesa_image_address1d(&ctx->Pack, row, filter->Width, 765 format, type, 0); 766 _mesa_pack_rgba_span_float(ctx, filter->Width, 767 (GLfloat (*)[4]) filter->Filter, 768 format, type, dst, &ctx->Pack, 0x0); 769 _mesa_unmap_pbo_dest(ctx, &ctx->Pack); 770 } 771 772 /* get column filter */ 773 column = _mesa_map_validate_pbo_dest(ctx, 1, &ctx->Pack, 774 filter->Height, 1, 1, 775 format, type, column, 776 "glGetConvolutionFilter"); 777 if (column) { 778 GLvoid *dst = _mesa_image_address1d(&ctx->Pack, column, filter->Height, 779 format, type, 0); 780 GLfloat (*src)[4] = (GLfloat (*)[4]) (filter->Filter + colStart); 781 _mesa_pack_rgba_span_float(ctx, filter->Height, src, 782 format, type, dst, &ctx->Pack, 0x0); 783 _mesa_unmap_pbo_dest(ctx, &ctx->Pack); 784 } 785 786 (void) span; /* unused at this time */ 787} 788 789 790static void GLAPIENTRY 791_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column) 792{ 793 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4; 794 GLint baseFormat; 795 GET_CURRENT_CONTEXT(ctx); 796 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 797 798 if (target != GL_SEPARABLE_2D) { 799 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)"); 800 return; 801 } 802 803 baseFormat = base_filter_format(internalFormat); 804 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) { 805 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)"); 806 return; 807 } 808 809 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) { 810 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)"); 811 return; 812 } 813 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) { 814 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)"); 815 return; 816 } 817 818 if (!_mesa_is_legal_format_and_type(ctx, format, type)) { 819 _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)"); 820 return; 821 } 822 823 if (format == GL_COLOR_INDEX || 824 format == GL_STENCIL_INDEX || 825 format == GL_DEPTH_COMPONENT || 826 format == GL_INTENSITY || 827 type == GL_BITMAP) { 828 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)"); 829 return; 830 } 831 832 ctx->Separable2D.Format = format; 833 ctx->Separable2D.InternalFormat = internalFormat; 834 ctx->Separable2D.Width = width; 835 ctx->Separable2D.Height = height; 836 837 /* unpack row filter */ 838 row = _mesa_map_validate_pbo_source(ctx, 1, &ctx->Unpack, 839 width, 1, 1, 840 format, type, row, 841 "glSeparableFilter2D"); 842 if (row) { 843 _mesa_unpack_color_span_float(ctx, width, GL_RGBA, 844 ctx->Separable2D.Filter, 845 format, type, row, &ctx->Unpack, 846 0x0); /* transferOps */ 847 _mesa_scale_and_bias_rgba(width, 848 (GLfloat (*)[4]) ctx->Separable2D.Filter, 849 ctx->Pixel.ConvolutionFilterScale[2][0], 850 ctx->Pixel.ConvolutionFilterScale[2][1], 851 ctx->Pixel.ConvolutionFilterScale[2][2], 852 ctx->Pixel.ConvolutionFilterScale[2][3], 853 ctx->Pixel.ConvolutionFilterBias[2][0], 854 ctx->Pixel.ConvolutionFilterBias[2][1], 855 ctx->Pixel.ConvolutionFilterBias[2][2], 856 ctx->Pixel.ConvolutionFilterBias[2][3]); 857 _mesa_unmap_pbo_source(ctx, &ctx->Unpack); 858 } 859 860 /* unpack column filter */ 861 column = _mesa_map_validate_pbo_source(ctx, 1, &ctx->Unpack, 862 height, 1, 1, 863 format, type, column, 864 "glSeparableFilter2D"); 865 if (column) { 866 _mesa_unpack_color_span_float(ctx, height, GL_RGBA, 867 &ctx->Separable2D.Filter[colStart], 868 format, type, column, &ctx->Unpack, 869 0); /* transferOps */ 870 871 _mesa_scale_and_bias_rgba(height, 872 (GLfloat (*)[4]) (ctx->Separable2D.Filter + colStart), 873 ctx->Pixel.ConvolutionFilterScale[2][0], 874 ctx->Pixel.ConvolutionFilterScale[2][1], 875 ctx->Pixel.ConvolutionFilterScale[2][2], 876 ctx->Pixel.ConvolutionFilterScale[2][3], 877 ctx->Pixel.ConvolutionFilterBias[2][0], 878 ctx->Pixel.ConvolutionFilterBias[2][1], 879 ctx->Pixel.ConvolutionFilterBias[2][2], 880 ctx->Pixel.ConvolutionFilterBias[2][3]); 881 _mesa_unmap_pbo_source(ctx, &ctx->Unpack); 882 } 883 884 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { 885 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 886 ctx->Unpack.BufferObj); 887 } 888 889 ctx->NewState |= _NEW_PIXEL; 890} 891 892 893/**********************************************************************/ 894/*** image convolution functions ***/ 895/**********************************************************************/ 896 897static void 898convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4], 899 GLint filterWidth, const GLfloat filter[][4], 900 GLfloat dest[][4]) 901{ 902 GLint dstWidth; 903 GLint i, n; 904 905 if (filterWidth >= 1) 906 dstWidth = srcWidth - (filterWidth - 1); 907 else 908 dstWidth = srcWidth; 909 910 if (dstWidth <= 0) 911 return; /* null result */ 912 913 for (i = 0; i < dstWidth; i++) { 914 GLfloat sumR = 0.0; 915 GLfloat sumG = 0.0; 916 GLfloat sumB = 0.0; 917 GLfloat sumA = 0.0; 918 for (n = 0; n < filterWidth; n++) { 919 sumR += src[i + n][RCOMP] * filter[n][RCOMP]; 920 sumG += src[i + n][GCOMP] * filter[n][GCOMP]; 921 sumB += src[i + n][BCOMP] * filter[n][BCOMP]; 922 sumA += src[i + n][ACOMP] * filter[n][ACOMP]; 923 } 924 dest[i][RCOMP] = sumR; 925 dest[i][GCOMP] = sumG; 926 dest[i][BCOMP] = sumB; 927 dest[i][ACOMP] = sumA; 928 } 929} 930 931 932static void 933convolve_1d_constant(GLint srcWidth, const GLfloat src[][4], 934 GLint filterWidth, const GLfloat filter[][4], 935 GLfloat dest[][4], 936 const GLfloat borderColor[4]) 937{ 938 const GLint halfFilterWidth = filterWidth / 2; 939 GLint i, n; 940 941 for (i = 0; i < srcWidth; i++) { 942 GLfloat sumR = 0.0; 943 GLfloat sumG = 0.0; 944 GLfloat sumB = 0.0; 945 GLfloat sumA = 0.0; 946 for (n = 0; n < filterWidth; n++) { 947 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) { 948 sumR += borderColor[RCOMP] * filter[n][RCOMP]; 949 sumG += borderColor[GCOMP] * filter[n][GCOMP]; 950 sumB += borderColor[BCOMP] * filter[n][BCOMP]; 951 sumA += borderColor[ACOMP] * filter[n][ACOMP]; 952 } 953 else { 954 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP]; 955 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP]; 956 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP]; 957 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP]; 958 } 959 } 960 dest[i][RCOMP] = sumR; 961 dest[i][GCOMP] = sumG; 962 dest[i][BCOMP] = sumB; 963 dest[i][ACOMP] = sumA; 964 } 965} 966 967 968static void 969convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4], 970 GLint filterWidth, const GLfloat filter[][4], 971 GLfloat dest[][4]) 972{ 973 const GLint halfFilterWidth = filterWidth / 2; 974 GLint i, n; 975 976 for (i = 0; i < srcWidth; i++) { 977 GLfloat sumR = 0.0; 978 GLfloat sumG = 0.0; 979 GLfloat sumB = 0.0; 980 GLfloat sumA = 0.0; 981 for (n = 0; n < filterWidth; n++) { 982 if (i + n < halfFilterWidth) { 983 sumR += src[0][RCOMP] * filter[n][RCOMP]; 984 sumG += src[0][GCOMP] * filter[n][GCOMP]; 985 sumB += src[0][BCOMP] * filter[n][BCOMP]; 986 sumA += src[0][ACOMP] * filter[n][ACOMP]; 987 } 988 else if (i + n - halfFilterWidth >= srcWidth) { 989 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP]; 990 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP]; 991 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP]; 992 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP]; 993 } 994 else { 995 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP]; 996 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP]; 997 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP]; 998 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP]; 999 } 1000 } 1001 dest[i][RCOMP] = sumR; 1002 dest[i][GCOMP] = sumG; 1003 dest[i][BCOMP] = sumB; 1004 dest[i][ACOMP] = sumA; 1005 } 1006} 1007 1008 1009static void 1010convolve_2d_reduce(GLint srcWidth, GLint srcHeight, 1011 const GLfloat src[][4], 1012 GLint filterWidth, GLint filterHeight, 1013 const GLfloat filter[][4], 1014 GLfloat dest[][4]) 1015{ 1016 GLint dstWidth, dstHeight; 1017 GLint i, j, n, m; 1018 1019 if (filterWidth >= 1) 1020 dstWidth = srcWidth - (filterWidth - 1); 1021 else 1022 dstWidth = srcWidth; 1023 1024 if (filterHeight >= 1) 1025 dstHeight = srcHeight - (filterHeight - 1); 1026 else 1027 dstHeight = srcHeight; 1028 1029 if (dstWidth <= 0 || dstHeight <= 0) 1030 return; 1031 1032 for (j = 0; j < dstHeight; j++) { 1033 for (i = 0; i < dstWidth; i++) { 1034 GLfloat sumR = 0.0; 1035 GLfloat sumG = 0.0; 1036 GLfloat sumB = 0.0; 1037 GLfloat sumA = 0.0; 1038 for (m = 0; m < filterHeight; m++) { 1039 for (n = 0; n < filterWidth; n++) { 1040 const GLint k = (j + m) * srcWidth + i + n; 1041 const GLint f = m * filterWidth + n; 1042 sumR += src[k][RCOMP] * filter[f][RCOMP]; 1043 sumG += src[k][GCOMP] * filter[f][GCOMP]; 1044 sumB += src[k][BCOMP] * filter[f][BCOMP]; 1045 sumA += src[k][ACOMP] * filter[f][ACOMP]; 1046 } 1047 } 1048 dest[j * dstWidth + i][RCOMP] = sumR; 1049 dest[j * dstWidth + i][GCOMP] = sumG; 1050 dest[j * dstWidth + i][BCOMP] = sumB; 1051 dest[j * dstWidth + i][ACOMP] = sumA; 1052 } 1053 } 1054} 1055 1056 1057static void 1058convolve_2d_constant(GLint srcWidth, GLint srcHeight, 1059 const GLfloat src[][4], 1060 GLint filterWidth, GLint filterHeight, 1061 const GLfloat filter[][4], 1062 GLfloat dest[][4], 1063 const GLfloat borderColor[4]) 1064{ 1065 const GLint halfFilterWidth = filterWidth / 2; 1066 const GLint halfFilterHeight = filterHeight / 2; 1067 GLint i, j, n, m; 1068 1069 for (j = 0; j < srcHeight; j++) { 1070 for (i = 0; i < srcWidth; i++) { 1071 GLfloat sumR = 0.0; 1072 GLfloat sumG = 0.0; 1073 GLfloat sumB = 0.0; 1074 GLfloat sumA = 0.0; 1075 for (m = 0; m < filterHeight; m++) { 1076 for (n = 0; n < filterWidth; n++) { 1077 const GLint f = m * filterWidth + n; 1078 const GLint is = i + n - halfFilterWidth; 1079 const GLint js = j + m - halfFilterHeight; 1080 if (is < 0 || is >= srcWidth || 1081 js < 0 || js >= srcHeight) { 1082 sumR += borderColor[RCOMP] * filter[f][RCOMP]; 1083 sumG += borderColor[GCOMP] * filter[f][GCOMP]; 1084 sumB += borderColor[BCOMP] * filter[f][BCOMP]; 1085 sumA += borderColor[ACOMP] * filter[f][ACOMP]; 1086 } 1087 else { 1088 const GLint k = js * srcWidth + is; 1089 sumR += src[k][RCOMP] * filter[f][RCOMP]; 1090 sumG += src[k][GCOMP] * filter[f][GCOMP]; 1091 sumB += src[k][BCOMP] * filter[f][BCOMP]; 1092 sumA += src[k][ACOMP] * filter[f][ACOMP]; 1093 } 1094 } 1095 } 1096 dest[j * srcWidth + i][RCOMP] = sumR; 1097 dest[j * srcWidth + i][GCOMP] = sumG; 1098 dest[j * srcWidth + i][BCOMP] = sumB; 1099 dest[j * srcWidth + i][ACOMP] = sumA; 1100 } 1101 } 1102} 1103 1104 1105static void 1106convolve_2d_replicate(GLint srcWidth, GLint srcHeight, 1107 const GLfloat src[][4], 1108 GLint filterWidth, GLint filterHeight, 1109 const GLfloat filter[][4], 1110 GLfloat dest[][4]) 1111{ 1112 const GLint halfFilterWidth = filterWidth / 2; 1113 const GLint halfFilterHeight = filterHeight / 2; 1114 GLint i, j, n, m; 1115 1116 for (j = 0; j < srcHeight; j++) { 1117 for (i = 0; i < srcWidth; i++) { 1118 GLfloat sumR = 0.0; 1119 GLfloat sumG = 0.0; 1120 GLfloat sumB = 0.0; 1121 GLfloat sumA = 0.0; 1122 for (m = 0; m < filterHeight; m++) { 1123 for (n = 0; n < filterWidth; n++) { 1124 const GLint f = m * filterWidth + n; 1125 GLint is = i + n - halfFilterWidth; 1126 GLint js = j + m - halfFilterHeight; 1127 GLint k; 1128 if (is < 0) 1129 is = 0; 1130 else if (is >= srcWidth) 1131 is = srcWidth - 1; 1132 if (js < 0) 1133 js = 0; 1134 else if (js >= srcHeight) 1135 js = srcHeight - 1; 1136 k = js * srcWidth + is; 1137 sumR += src[k][RCOMP] * filter[f][RCOMP]; 1138 sumG += src[k][GCOMP] * filter[f][GCOMP]; 1139 sumB += src[k][BCOMP] * filter[f][BCOMP]; 1140 sumA += src[k][ACOMP] * filter[f][ACOMP]; 1141 } 1142 } 1143 dest[j * srcWidth + i][RCOMP] = sumR; 1144 dest[j * srcWidth + i][GCOMP] = sumG; 1145 dest[j * srcWidth + i][BCOMP] = sumB; 1146 dest[j * srcWidth + i][ACOMP] = sumA; 1147 } 1148 } 1149} 1150 1151 1152static void 1153convolve_sep_reduce(GLint srcWidth, GLint srcHeight, 1154 const GLfloat src[][4], 1155 GLint filterWidth, GLint filterHeight, 1156 const GLfloat rowFilt[][4], 1157 const GLfloat colFilt[][4], 1158 GLfloat dest[][4]) 1159{ 1160 GLint dstWidth, dstHeight; 1161 GLint i, j, n, m; 1162 1163 if (filterWidth >= 1) 1164 dstWidth = srcWidth - (filterWidth - 1); 1165 else 1166 dstWidth = srcWidth; 1167 1168 if (filterHeight >= 1) 1169 dstHeight = srcHeight - (filterHeight - 1); 1170 else 1171 dstHeight = srcHeight; 1172 1173 if (dstWidth <= 0 || dstHeight <= 0) 1174 return; 1175 1176 for (j = 0; j < dstHeight; j++) { 1177 for (i = 0; i < dstWidth; i++) { 1178 GLfloat sumR = 0.0; 1179 GLfloat sumG = 0.0; 1180 GLfloat sumB = 0.0; 1181 GLfloat sumA = 0.0; 1182 for (m = 0; m < filterHeight; m++) { 1183 for (n = 0; n < filterWidth; n++) { 1184 GLint k = (j + m) * srcWidth + i + n; 1185 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP]; 1186 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP]; 1187 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP]; 1188 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP]; 1189 } 1190 } 1191 dest[j * dstWidth + i][RCOMP] = sumR; 1192 dest[j * dstWidth + i][GCOMP] = sumG; 1193 dest[j * dstWidth + i][BCOMP] = sumB; 1194 dest[j * dstWidth + i][ACOMP] = sumA; 1195 } 1196 } 1197} 1198 1199 1200static void 1201convolve_sep_constant(GLint srcWidth, GLint srcHeight, 1202 const GLfloat src[][4], 1203 GLint filterWidth, GLint filterHeight, 1204 const GLfloat rowFilt[][4], 1205 const GLfloat colFilt[][4], 1206 GLfloat dest[][4], 1207 const GLfloat borderColor[4]) 1208{ 1209 const GLint halfFilterWidth = filterWidth / 2; 1210 const GLint halfFilterHeight = filterHeight / 2; 1211 GLint i, j, n, m; 1212 1213 for (j = 0; j < srcHeight; j++) { 1214 for (i = 0; i < srcWidth; i++) { 1215 GLfloat sumR = 0.0; 1216 GLfloat sumG = 0.0; 1217 GLfloat sumB = 0.0; 1218 GLfloat sumA = 0.0; 1219 for (m = 0; m < filterHeight; m++) { 1220 for (n = 0; n < filterWidth; n++) { 1221 const GLint is = i + n - halfFilterWidth; 1222 const GLint js = j + m - halfFilterHeight; 1223 if (is < 0 || is >= srcWidth || 1224 js < 0 || js >= srcHeight) { 1225 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP]; 1226 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP]; 1227 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP]; 1228 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP]; 1229 } 1230 else { 1231 GLint k = js * srcWidth + is; 1232 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP]; 1233 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP]; 1234 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP]; 1235 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP]; 1236 } 1237 1238 } 1239 } 1240 dest[j * srcWidth + i][RCOMP] = sumR; 1241 dest[j * srcWidth + i][GCOMP] = sumG; 1242 dest[j * srcWidth + i][BCOMP] = sumB; 1243 dest[j * srcWidth + i][ACOMP] = sumA; 1244 } 1245 } 1246} 1247 1248 1249static void 1250convolve_sep_replicate(GLint srcWidth, GLint srcHeight, 1251 const GLfloat src[][4], 1252 GLint filterWidth, GLint filterHeight, 1253 const GLfloat rowFilt[][4], 1254 const GLfloat colFilt[][4], 1255 GLfloat dest[][4]) 1256{ 1257 const GLint halfFilterWidth = filterWidth / 2; 1258 const GLint halfFilterHeight = filterHeight / 2; 1259 GLint i, j, n, m; 1260 1261 for (j = 0; j < srcHeight; j++) { 1262 for (i = 0; i < srcWidth; i++) { 1263 GLfloat sumR = 0.0; 1264 GLfloat sumG = 0.0; 1265 GLfloat sumB = 0.0; 1266 GLfloat sumA = 0.0; 1267 for (m = 0; m < filterHeight; m++) { 1268 for (n = 0; n < filterWidth; n++) { 1269 GLint is = i + n - halfFilterWidth; 1270 GLint js = j + m - halfFilterHeight; 1271 GLint k; 1272 if (is < 0) 1273 is = 0; 1274 else if (is >= srcWidth) 1275 is = srcWidth - 1; 1276 if (js < 0) 1277 js = 0; 1278 else if (js >= srcHeight) 1279 js = srcHeight - 1; 1280 k = js * srcWidth + is; 1281 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP]; 1282 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP]; 1283 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP]; 1284 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP]; 1285 } 1286 } 1287 dest[j * srcWidth + i][RCOMP] = sumR; 1288 dest[j * srcWidth + i][GCOMP] = sumG; 1289 dest[j * srcWidth + i][BCOMP] = sumB; 1290 dest[j * srcWidth + i][ACOMP] = sumA; 1291 } 1292 } 1293} 1294 1295 1296 1297void 1298_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width, 1299 const GLfloat *srcImage, GLfloat *dstImage) 1300{ 1301 switch (ctx->Pixel.ConvolutionBorderMode[0]) { 1302 case GL_REDUCE: 1303 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage, 1304 ctx->Convolution1D.Width, 1305 (const GLfloat (*)[4]) ctx->Convolution1D.Filter, 1306 (GLfloat (*)[4]) dstImage); 1307 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1); 1308 break; 1309 case GL_CONSTANT_BORDER: 1310 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage, 1311 ctx->Convolution1D.Width, 1312 (const GLfloat (*)[4]) ctx->Convolution1D.Filter, 1313 (GLfloat (*)[4]) dstImage, 1314 ctx->Pixel.ConvolutionBorderColor[0]); 1315 break; 1316 case GL_REPLICATE_BORDER: 1317 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage, 1318 ctx->Convolution1D.Width, 1319 (const GLfloat (*)[4]) ctx->Convolution1D.Filter, 1320 (GLfloat (*)[4]) dstImage); 1321 break; 1322 default: 1323 ; 1324 } 1325} 1326 1327 1328void 1329_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height, 1330 const GLfloat *srcImage, GLfloat *dstImage) 1331{ 1332 switch (ctx->Pixel.ConvolutionBorderMode[1]) { 1333 case GL_REDUCE: 1334 convolve_2d_reduce(*width, *height, 1335 (const GLfloat (*)[4]) srcImage, 1336 ctx->Convolution2D.Width, 1337 ctx->Convolution2D.Height, 1338 (const GLfloat (*)[4]) ctx->Convolution2D.Filter, 1339 (GLfloat (*)[4]) dstImage); 1340 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1); 1341 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1); 1342 break; 1343 case GL_CONSTANT_BORDER: 1344 convolve_2d_constant(*width, *height, 1345 (const GLfloat (*)[4]) srcImage, 1346 ctx->Convolution2D.Width, 1347 ctx->Convolution2D.Height, 1348 (const GLfloat (*)[4]) ctx->Convolution2D.Filter, 1349 (GLfloat (*)[4]) dstImage, 1350 ctx->Pixel.ConvolutionBorderColor[1]); 1351 break; 1352 case GL_REPLICATE_BORDER: 1353 convolve_2d_replicate(*width, *height, 1354 (const GLfloat (*)[4]) srcImage, 1355 ctx->Convolution2D.Width, 1356 ctx->Convolution2D.Height, 1357 (const GLfloat (*)[4])ctx->Convolution2D.Filter, 1358 (GLfloat (*)[4]) dstImage); 1359 break; 1360 default: 1361 ; 1362 } 1363} 1364 1365 1366void 1367_mesa_convolve_sep_image(const GLcontext *ctx, 1368 GLsizei *width, GLsizei *height, 1369 const GLfloat *srcImage, GLfloat *dstImage) 1370{ 1371 const GLfloat *rowFilter = ctx->Separable2D.Filter; 1372 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH; 1373 1374 switch (ctx->Pixel.ConvolutionBorderMode[2]) { 1375 case GL_REDUCE: 1376 convolve_sep_reduce(*width, *height, 1377 (const GLfloat (*)[4]) srcImage, 1378 ctx->Separable2D.Width, 1379 ctx->Separable2D.Height, 1380 (const GLfloat (*)[4]) rowFilter, 1381 (const GLfloat (*)[4]) colFilter, 1382 (GLfloat (*)[4]) dstImage); 1383 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1); 1384 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1); 1385 break; 1386 case GL_CONSTANT_BORDER: 1387 convolve_sep_constant(*width, *height, 1388 (const GLfloat (*)[4]) srcImage, 1389 ctx->Separable2D.Width, 1390 ctx->Separable2D.Height, 1391 (const GLfloat (*)[4]) rowFilter, 1392 (const GLfloat (*)[4]) colFilter, 1393 (GLfloat (*)[4]) dstImage, 1394 ctx->Pixel.ConvolutionBorderColor[2]); 1395 break; 1396 case GL_REPLICATE_BORDER: 1397 convolve_sep_replicate(*width, *height, 1398 (const GLfloat (*)[4]) srcImage, 1399 ctx->Separable2D.Width, 1400 ctx->Separable2D.Height, 1401 (const GLfloat (*)[4]) rowFilter, 1402 (const GLfloat (*)[4]) colFilter, 1403 (GLfloat (*)[4]) dstImage); 1404 break; 1405 default: 1406 ; 1407 } 1408} 1409 1410 1411 1412/* 1413 * This function computes an image's size after convolution. 1414 * If the convolution border mode is GL_REDUCE, the post-convolution 1415 * image will be smaller than the original. 1416 */ 1417void 1418_mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions, 1419 GLsizei *width, GLsizei *height) 1420{ 1421 if (ctx->Pixel.Convolution1DEnabled 1422 && dimensions == 1 1423 && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) { 1424 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1); 1425 } 1426 else if (ctx->Pixel.Convolution2DEnabled 1427 && dimensions > 1 1428 && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) { 1429 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1); 1430 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1); 1431 } 1432 else if (ctx->Pixel.Separable2DEnabled 1433 && dimensions > 1 1434 && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) { 1435 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1); 1436 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1); 1437 } 1438} 1439 1440 1441void 1442_mesa_init_convolve_dispatch(struct _glapi_table *disp) 1443{ 1444 SET_ConvolutionFilter1D(disp, _mesa_ConvolutionFilter1D); 1445 SET_ConvolutionFilter2D(disp, _mesa_ConvolutionFilter2D); 1446 SET_ConvolutionParameterf(disp, _mesa_ConvolutionParameterf); 1447 SET_ConvolutionParameterfv(disp, _mesa_ConvolutionParameterfv); 1448 SET_ConvolutionParameteri(disp, _mesa_ConvolutionParameteri); 1449 SET_ConvolutionParameteriv(disp, _mesa_ConvolutionParameteriv); 1450 SET_CopyConvolutionFilter1D(disp, _mesa_CopyConvolutionFilter1D); 1451 SET_CopyConvolutionFilter2D(disp, _mesa_CopyConvolutionFilter2D); 1452 SET_GetConvolutionFilter(disp, _mesa_GetConvolutionFilter); 1453 SET_GetConvolutionParameterfv(disp, _mesa_GetConvolutionParameterfv); 1454 SET_GetConvolutionParameteriv(disp, _mesa_GetConvolutionParameteriv); 1455 SET_SeparableFilter2D(disp, _mesa_SeparableFilter2D); 1456 SET_GetSeparableFilter(disp, _mesa_GetSeparableFilter); 1457} 1458 1459 1460#endif /* FEATURE_convolve */ 1461