2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
27 * Image convolution functions.
29 * Notes: filter kernel elements are indexed by <n> and <m> as in
35 #include "bufferobj.h"
46 * Given an internalFormat token passed to glConvolutionFilter
47 * or glSeparableFilter, return the corresponding base format.
48 * Return -1 if invalid token.
51 base_filter_format( GLenum format
)
66 case GL_LUMINANCE_ALPHA
:
67 case GL_LUMINANCE4_ALPHA4
:
68 case GL_LUMINANCE6_ALPHA2
:
69 case GL_LUMINANCE8_ALPHA8
:
70 case GL_LUMINANCE12_ALPHA4
:
71 case GL_LUMINANCE12_ALPHA12
:
72 case GL_LUMINANCE16_ALPHA16
:
73 return GL_LUMINANCE_ALPHA
;
100 return -1; /* error */
106 _mesa_ConvolutionFilter1D(GLenum target
, GLenum internalFormat
, GLsizei width
, GLenum format
, GLenum type
, const GLvoid
*image
)
109 GET_CURRENT_CONTEXT(ctx
);
110 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
112 if (target
!= GL_CONVOLUTION_1D
) {
113 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter1D(target)");
117 baseFormat
= base_filter_format(internalFormat
);
118 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
119 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter1D(internalFormat)");
123 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
124 _mesa_error(ctx
, GL_INVALID_VALUE
, "glConvolutionFilter1D(width)");
128 if (!_mesa_is_legal_format_and_type(ctx
, format
, type
)) {
129 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glConvolutionFilter1D(format or type)");
133 if (format
== GL_COLOR_INDEX
||
134 format
== GL_STENCIL_INDEX
||
135 format
== GL_DEPTH_COMPONENT
||
136 format
== GL_INTENSITY
||
138 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter1D(format or type)");
142 ctx
->Convolution1D
.Format
= format
;
143 ctx
->Convolution1D
.InternalFormat
= internalFormat
;
144 ctx
->Convolution1D
.Width
= width
;
145 ctx
->Convolution1D
.Height
= 1;
147 if (ctx
->Unpack
.BufferObj
->Name
) {
148 /* unpack filter from PBO */
150 if (!_mesa_validate_pbo_access(1, &ctx
->Unpack
, width
, 1, 1,
151 format
, type
, image
)) {
152 _mesa_error(ctx
, GL_INVALID_OPERATION
,
153 "glConvolutionFilter1D(invalid PBO access)");
156 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
158 ctx
->Unpack
.BufferObj
);
160 /* buffer is already mapped - that's an error */
161 _mesa_error(ctx
, GL_INVALID_OPERATION
,
162 "glConvolutionFilter1D(PBO is mapped)");
165 image
= ADD_POINTERS(buf
, image
);
171 _mesa_unpack_color_span_float(ctx
, width
, GL_RGBA
,
172 ctx
->Convolution1D
.Filter
,
173 format
, type
, image
, &ctx
->Unpack
,
174 0); /* transferOps */
176 if (ctx
->Unpack
.BufferObj
->Name
) {
177 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
178 ctx
->Unpack
.BufferObj
);
181 _mesa_scale_and_bias_rgba(width
,
182 (GLfloat (*)[4]) ctx
->Convolution1D
.Filter
,
183 ctx
->Pixel
.ConvolutionFilterScale
[0][0],
184 ctx
->Pixel
.ConvolutionFilterScale
[0][1],
185 ctx
->Pixel
.ConvolutionFilterScale
[0][2],
186 ctx
->Pixel
.ConvolutionFilterScale
[0][3],
187 ctx
->Pixel
.ConvolutionFilterBias
[0][0],
188 ctx
->Pixel
.ConvolutionFilterBias
[0][1],
189 ctx
->Pixel
.ConvolutionFilterBias
[0][2],
190 ctx
->Pixel
.ConvolutionFilterBias
[0][3]);
192 ctx
->NewState
|= _NEW_PIXEL
;
197 _mesa_ConvolutionFilter2D(GLenum target
, GLenum internalFormat
, GLsizei width
, GLsizei height
, GLenum format
, GLenum type
, const GLvoid
*image
)
201 GET_CURRENT_CONTEXT(ctx
);
202 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
204 if (target
!= GL_CONVOLUTION_2D
) {
205 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter2D(target)");
209 baseFormat
= base_filter_format(internalFormat
);
210 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
211 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter2D(internalFormat)");
215 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
216 _mesa_error(ctx
, GL_INVALID_VALUE
, "glConvolutionFilter2D(width)");
219 if (height
< 0 || height
> MAX_CONVOLUTION_HEIGHT
) {
220 _mesa_error(ctx
, GL_INVALID_VALUE
, "glConvolutionFilter2D(height)");
224 if (!_mesa_is_legal_format_and_type(ctx
, format
, type
)) {
225 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glConvolutionFilter2D(format or type)");
228 if (format
== GL_COLOR_INDEX
||
229 format
== GL_STENCIL_INDEX
||
230 format
== GL_DEPTH_COMPONENT
||
231 format
== GL_INTENSITY
||
233 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter2D(format or type)");
237 /* this should have been caught earlier */
238 assert(_mesa_components_in_format(format
));
240 ctx
->Convolution2D
.Format
= format
;
241 ctx
->Convolution2D
.InternalFormat
= internalFormat
;
242 ctx
->Convolution2D
.Width
= width
;
243 ctx
->Convolution2D
.Height
= height
;
245 if (ctx
->Unpack
.BufferObj
->Name
) {
246 /* unpack filter from PBO */
248 if (!_mesa_validate_pbo_access(2, &ctx
->Unpack
, width
, height
, 1,
249 format
, type
, image
)) {
250 _mesa_error(ctx
, GL_INVALID_OPERATION
,
251 "glConvolutionFilter2D(invalid PBO access)");
254 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
256 ctx
->Unpack
.BufferObj
);
258 /* buffer is already mapped - that's an error */
259 _mesa_error(ctx
, GL_INVALID_OPERATION
,
260 "glConvolutionFilter2D(PBO is mapped)");
263 image
= ADD_POINTERS(buf
, image
);
269 /* Unpack filter image. We always store filters in RGBA format. */
270 for (i
= 0; i
< height
; i
++) {
271 const GLvoid
*src
= _mesa_image_address2d(&ctx
->Unpack
, image
, width
,
272 height
, format
, type
, i
, 0);
273 GLfloat
*dst
= ctx
->Convolution2D
.Filter
+ i
* width
* 4;
274 _mesa_unpack_color_span_float(ctx
, width
, GL_RGBA
, dst
,
275 format
, type
, src
, &ctx
->Unpack
,
276 0); /* transferOps */
279 if (ctx
->Unpack
.BufferObj
->Name
) {
280 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
281 ctx
->Unpack
.BufferObj
);
284 _mesa_scale_and_bias_rgba(width
* height
,
285 (GLfloat (*)[4]) ctx
->Convolution2D
.Filter
,
286 ctx
->Pixel
.ConvolutionFilterScale
[1][0],
287 ctx
->Pixel
.ConvolutionFilterScale
[1][1],
288 ctx
->Pixel
.ConvolutionFilterScale
[1][2],
289 ctx
->Pixel
.ConvolutionFilterScale
[1][3],
290 ctx
->Pixel
.ConvolutionFilterBias
[1][0],
291 ctx
->Pixel
.ConvolutionFilterBias
[1][1],
292 ctx
->Pixel
.ConvolutionFilterBias
[1][2],
293 ctx
->Pixel
.ConvolutionFilterBias
[1][3]);
295 ctx
->NewState
|= _NEW_PIXEL
;
300 _mesa_ConvolutionParameterf(GLenum target
, GLenum pname
, GLfloat param
)
302 GET_CURRENT_CONTEXT(ctx
);
304 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
307 case GL_CONVOLUTION_1D
:
310 case GL_CONVOLUTION_2D
:
313 case GL_SEPARABLE_2D
:
317 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterf(target)");
322 case GL_CONVOLUTION_BORDER_MODE
:
323 if (param
== (GLfloat
) GL_REDUCE
||
324 param
== (GLfloat
) GL_CONSTANT_BORDER
||
325 param
== (GLfloat
) GL_REPLICATE_BORDER
) {
326 ctx
->Pixel
.ConvolutionBorderMode
[c
] = (GLenum
) param
;
329 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterf(params)");
334 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterf(pname)");
338 ctx
->NewState
|= _NEW_PIXEL
;
343 _mesa_ConvolutionParameterfv(GLenum target
, GLenum pname
, const GLfloat
*params
)
345 GET_CURRENT_CONTEXT(ctx
);
347 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
350 case GL_CONVOLUTION_1D
:
353 case GL_CONVOLUTION_2D
:
356 case GL_SEPARABLE_2D
:
360 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterfv(target)");
365 case GL_CONVOLUTION_BORDER_COLOR
:
366 COPY_4V(ctx
->Pixel
.ConvolutionBorderColor
[c
], params
);
368 case GL_CONVOLUTION_BORDER_MODE
:
369 if (params
[0] == (GLfloat
) GL_REDUCE
||
370 params
[0] == (GLfloat
) GL_CONSTANT_BORDER
||
371 params
[0] == (GLfloat
) GL_REPLICATE_BORDER
) {
372 ctx
->Pixel
.ConvolutionBorderMode
[c
] = (GLenum
) params
[0];
375 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterfv(params)");
379 case GL_CONVOLUTION_FILTER_SCALE
:
380 COPY_4V(ctx
->Pixel
.ConvolutionFilterScale
[c
], params
);
382 case GL_CONVOLUTION_FILTER_BIAS
:
383 COPY_4V(ctx
->Pixel
.ConvolutionFilterBias
[c
], params
);
386 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterfv(pname)");
390 ctx
->NewState
|= _NEW_PIXEL
;
395 _mesa_ConvolutionParameteri(GLenum target
, GLenum pname
, GLint param
)
397 GET_CURRENT_CONTEXT(ctx
);
399 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
402 case GL_CONVOLUTION_1D
:
405 case GL_CONVOLUTION_2D
:
408 case GL_SEPARABLE_2D
:
412 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteri(target)");
417 case GL_CONVOLUTION_BORDER_MODE
:
418 if (param
== (GLint
) GL_REDUCE
||
419 param
== (GLint
) GL_CONSTANT_BORDER
||
420 param
== (GLint
) GL_REPLICATE_BORDER
) {
421 ctx
->Pixel
.ConvolutionBorderMode
[c
] = (GLenum
) param
;
424 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteri(params)");
429 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteri(pname)");
433 ctx
->NewState
|= _NEW_PIXEL
;
438 _mesa_ConvolutionParameteriv(GLenum target
, GLenum pname
, const GLint
*params
)
440 GET_CURRENT_CONTEXT(ctx
);
442 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
445 case GL_CONVOLUTION_1D
:
448 case GL_CONVOLUTION_2D
:
451 case GL_SEPARABLE_2D
:
455 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteriv(target)");
460 case GL_CONVOLUTION_BORDER_COLOR
:
461 ctx
->Pixel
.ConvolutionBorderColor
[c
][0] = INT_TO_FLOAT(params
[0]);
462 ctx
->Pixel
.ConvolutionBorderColor
[c
][1] = INT_TO_FLOAT(params
[1]);
463 ctx
->Pixel
.ConvolutionBorderColor
[c
][2] = INT_TO_FLOAT(params
[2]);
464 ctx
->Pixel
.ConvolutionBorderColor
[c
][3] = INT_TO_FLOAT(params
[3]);
466 case GL_CONVOLUTION_BORDER_MODE
:
467 if (params
[0] == (GLint
) GL_REDUCE
||
468 params
[0] == (GLint
) GL_CONSTANT_BORDER
||
469 params
[0] == (GLint
) GL_REPLICATE_BORDER
) {
470 ctx
->Pixel
.ConvolutionBorderMode
[c
] = (GLenum
) params
[0];
473 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteriv(params)");
477 case GL_CONVOLUTION_FILTER_SCALE
:
478 /* COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); */
479 /* need cast to prevent compiler warnings */
480 ctx
->Pixel
.ConvolutionFilterScale
[c
][0] = (GLfloat
) params
[0];
481 ctx
->Pixel
.ConvolutionFilterScale
[c
][1] = (GLfloat
) params
[1];
482 ctx
->Pixel
.ConvolutionFilterScale
[c
][2] = (GLfloat
) params
[2];
483 ctx
->Pixel
.ConvolutionFilterScale
[c
][3] = (GLfloat
) params
[3];
485 case GL_CONVOLUTION_FILTER_BIAS
:
486 /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */
487 /* need cast to prevent compiler warnings */
488 ctx
->Pixel
.ConvolutionFilterBias
[c
][0] = (GLfloat
) params
[0];
489 ctx
->Pixel
.ConvolutionFilterBias
[c
][1] = (GLfloat
) params
[1];
490 ctx
->Pixel
.ConvolutionFilterBias
[c
][2] = (GLfloat
) params
[2];
491 ctx
->Pixel
.ConvolutionFilterBias
[c
][3] = (GLfloat
) params
[3];
494 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteriv(pname)");
498 ctx
->NewState
|= _NEW_PIXEL
;
503 _mesa_CopyConvolutionFilter1D(GLenum target
, GLenum internalFormat
, GLint x
, GLint y
, GLsizei width
)
506 GET_CURRENT_CONTEXT(ctx
);
507 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
509 if (target
!= GL_CONVOLUTION_1D
) {
510 _mesa_error(ctx
, GL_INVALID_ENUM
, "glCopyConvolutionFilter1D(target)");
514 baseFormat
= base_filter_format(internalFormat
);
515 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
516 _mesa_error(ctx
, GL_INVALID_ENUM
, "glCopyConvolutionFilter1D(internalFormat)");
520 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
521 _mesa_error(ctx
, GL_INVALID_VALUE
, "glCopyConvolutionFilter1D(width)");
525 ctx
->Driver
.CopyConvolutionFilter1D( ctx
, target
,
526 internalFormat
, x
, y
, width
);
531 _mesa_CopyConvolutionFilter2D(GLenum target
, GLenum internalFormat
, GLint x
, GLint y
, GLsizei width
, GLsizei height
)
534 GET_CURRENT_CONTEXT(ctx
);
535 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
537 if (target
!= GL_CONVOLUTION_2D
) {
538 _mesa_error(ctx
, GL_INVALID_ENUM
, "glCopyConvolutionFilter2D(target)");
542 baseFormat
= base_filter_format(internalFormat
);
543 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
544 _mesa_error(ctx
, GL_INVALID_ENUM
, "glCopyConvolutionFilter2D(internalFormat)");
548 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
549 _mesa_error(ctx
, GL_INVALID_VALUE
, "glCopyConvolutionFilter2D(width)");
552 if (height
< 0 || height
> MAX_CONVOLUTION_HEIGHT
) {
553 _mesa_error(ctx
, GL_INVALID_VALUE
, "glCopyConvolutionFilter2D(height)");
557 ctx
->Driver
.CopyConvolutionFilter2D( ctx
, target
, internalFormat
, x
, y
,
563 _mesa_GetConvolutionFilter(GLenum target
, GLenum format
, GLenum type
, GLvoid
*image
)
565 const struct gl_convolution_attrib
*filter
;
567 GET_CURRENT_CONTEXT(ctx
);
568 ASSERT_OUTSIDE_BEGIN_END(ctx
);
571 _mesa_update_state(ctx
);
574 if (!_mesa_is_legal_format_and_type(ctx
, format
, type
)) {
575 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetConvolutionFilter(format or type)");
579 if (format
== GL_COLOR_INDEX
||
580 format
== GL_STENCIL_INDEX
||
581 format
== GL_DEPTH_COMPONENT
||
582 format
== GL_INTENSITY
||
584 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionFilter(format or type)");
589 case GL_CONVOLUTION_1D
:
590 filter
= &(ctx
->Convolution1D
);
592 case GL_CONVOLUTION_2D
:
593 filter
= &(ctx
->Convolution2D
);
596 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionFilter(target)");
600 if (ctx
->Pack
.BufferObj
->Name
) {
601 /* Pack the filter into a PBO */
603 if (!_mesa_validate_pbo_access(2, &ctx
->Pack
,
604 filter
->Width
, filter
->Height
,
605 1, format
, type
, image
)) {
606 _mesa_error(ctx
, GL_INVALID_OPERATION
,
607 "glGetConvolutionFilter(invalid PBO access)");
610 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_PACK_BUFFER_EXT
,
612 ctx
->Pack
.BufferObj
);
614 /* buffer is already mapped - that's an error */
615 _mesa_error(ctx
, GL_INVALID_OPERATION
,
616 "glGetConvolutionFilter(PBO is mapped)");
619 image
= ADD_POINTERS(image
, buf
);
622 for (row
= 0; row
< filter
->Height
; row
++) {
623 GLvoid
*dst
= _mesa_image_address2d(&ctx
->Pack
, image
, filter
->Width
,
624 filter
->Height
, format
, type
,
626 const GLfloat
*src
= filter
->Filter
+ row
* filter
->Width
* 4;
627 _mesa_pack_rgba_span_float(ctx
, filter
->Width
,
628 (const GLfloat (*)[4]) src
,
629 format
, type
, dst
, &ctx
->Pack
, 0);
632 if (ctx
->Pack
.BufferObj
->Name
) {
633 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_PACK_BUFFER_EXT
,
634 ctx
->Pack
.BufferObj
);
640 _mesa_GetConvolutionParameterfv(GLenum target
, GLenum pname
, GLfloat
*params
)
642 GET_CURRENT_CONTEXT(ctx
);
643 const struct gl_convolution_attrib
*conv
;
645 ASSERT_OUTSIDE_BEGIN_END(ctx
);
648 case GL_CONVOLUTION_1D
:
650 conv
= &ctx
->Convolution1D
;
652 case GL_CONVOLUTION_2D
:
654 conv
= &ctx
->Convolution2D
;
656 case GL_SEPARABLE_2D
:
658 conv
= &ctx
->Separable2D
;
661 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionParameterfv(target)");
666 case GL_CONVOLUTION_BORDER_COLOR
:
667 COPY_4V(params
, ctx
->Pixel
.ConvolutionBorderColor
[c
]);
669 case GL_CONVOLUTION_BORDER_MODE
:
670 *params
= (GLfloat
) ctx
->Pixel
.ConvolutionBorderMode
[c
];
672 case GL_CONVOLUTION_FILTER_SCALE
:
673 COPY_4V(params
, ctx
->Pixel
.ConvolutionFilterScale
[c
]);
675 case GL_CONVOLUTION_FILTER_BIAS
:
676 COPY_4V(params
, ctx
->Pixel
.ConvolutionFilterBias
[c
]);
678 case GL_CONVOLUTION_FORMAT
:
679 *params
= (GLfloat
) conv
->Format
;
681 case GL_CONVOLUTION_WIDTH
:
682 *params
= (GLfloat
) conv
->Width
;
684 case GL_CONVOLUTION_HEIGHT
:
685 *params
= (GLfloat
) conv
->Height
;
687 case GL_MAX_CONVOLUTION_WIDTH
:
688 *params
= (GLfloat
) ctx
->Const
.MaxConvolutionWidth
;
690 case GL_MAX_CONVOLUTION_HEIGHT
:
691 *params
= (GLfloat
) ctx
->Const
.MaxConvolutionHeight
;
694 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionParameterfv(pname)");
701 _mesa_GetConvolutionParameteriv(GLenum target
, GLenum pname
, GLint
*params
)
703 GET_CURRENT_CONTEXT(ctx
);
704 const struct gl_convolution_attrib
*conv
;
706 ASSERT_OUTSIDE_BEGIN_END(ctx
);
709 case GL_CONVOLUTION_1D
:
711 conv
= &ctx
->Convolution1D
;
713 case GL_CONVOLUTION_2D
:
715 conv
= &ctx
->Convolution2D
;
717 case GL_SEPARABLE_2D
:
719 conv
= &ctx
->Separable2D
;
722 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionParameteriv(target)");
727 case GL_CONVOLUTION_BORDER_COLOR
:
728 params
[0] = FLOAT_TO_INT(ctx
->Pixel
.ConvolutionBorderColor
[c
][0]);
729 params
[1] = FLOAT_TO_INT(ctx
->Pixel
.ConvolutionBorderColor
[c
][1]);
730 params
[2] = FLOAT_TO_INT(ctx
->Pixel
.ConvolutionBorderColor
[c
][2]);
731 params
[3] = FLOAT_TO_INT(ctx
->Pixel
.ConvolutionBorderColor
[c
][3]);
733 case GL_CONVOLUTION_BORDER_MODE
:
734 *params
= (GLint
) ctx
->Pixel
.ConvolutionBorderMode
[c
];
736 case GL_CONVOLUTION_FILTER_SCALE
:
737 params
[0] = (GLint
) ctx
->Pixel
.ConvolutionFilterScale
[c
][0];
738 params
[1] = (GLint
) ctx
->Pixel
.ConvolutionFilterScale
[c
][1];
739 params
[2] = (GLint
) ctx
->Pixel
.ConvolutionFilterScale
[c
][2];
740 params
[3] = (GLint
) ctx
->Pixel
.ConvolutionFilterScale
[c
][3];
742 case GL_CONVOLUTION_FILTER_BIAS
:
743 params
[0] = (GLint
) ctx
->Pixel
.ConvolutionFilterBias
[c
][0];
744 params
[1] = (GLint
) ctx
->Pixel
.ConvolutionFilterBias
[c
][1];
745 params
[2] = (GLint
) ctx
->Pixel
.ConvolutionFilterBias
[c
][2];
746 params
[3] = (GLint
) ctx
->Pixel
.ConvolutionFilterBias
[c
][3];
748 case GL_CONVOLUTION_FORMAT
:
749 *params
= (GLint
) conv
->Format
;
751 case GL_CONVOLUTION_WIDTH
:
752 *params
= (GLint
) conv
->Width
;
754 case GL_CONVOLUTION_HEIGHT
:
755 *params
= (GLint
) conv
->Height
;
757 case GL_MAX_CONVOLUTION_WIDTH
:
758 *params
= (GLint
) ctx
->Const
.MaxConvolutionWidth
;
760 case GL_MAX_CONVOLUTION_HEIGHT
:
761 *params
= (GLint
) ctx
->Const
.MaxConvolutionHeight
;
764 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionParameteriv(pname)");
771 _mesa_GetSeparableFilter(GLenum target
, GLenum format
, GLenum type
, GLvoid
*row
, GLvoid
*column
, GLvoid
*span
)
773 const GLint colStart
= MAX_CONVOLUTION_WIDTH
* 4;
774 const struct gl_convolution_attrib
*filter
;
775 GET_CURRENT_CONTEXT(ctx
);
776 ASSERT_OUTSIDE_BEGIN_END(ctx
);
779 _mesa_update_state(ctx
);
782 if (target
!= GL_SEPARABLE_2D
) {
783 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetSeparableFilter(target)");
787 if (!_mesa_is_legal_format_and_type(ctx
, format
, type
)) {
788 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetConvolutionFilter(format or type)");
792 if (format
== GL_COLOR_INDEX
||
793 format
== GL_STENCIL_INDEX
||
794 format
== GL_DEPTH_COMPONENT
||
795 format
== GL_INTENSITY
||
797 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionFilter(format or type)");
801 filter
= &ctx
->Separable2D
;
803 if (ctx
->Pack
.BufferObj
->Name
) {
804 /* Pack filter into PBO */
806 if (!_mesa_validate_pbo_access(1, &ctx
->Pack
, filter
->Width
, 1, 1,
807 format
, type
, row
)) {
808 _mesa_error(ctx
, GL_INVALID_OPERATION
,
809 "glGetSeparableFilter(invalid PBO access, width)");
812 if (!_mesa_validate_pbo_access(1, &ctx
->Pack
, filter
->Height
, 1, 1,
813 format
, type
, column
)) {
814 _mesa_error(ctx
, GL_INVALID_OPERATION
,
815 "glGetSeparableFilter(invalid PBO access, height)");
818 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_PACK_BUFFER_EXT
,
820 ctx
->Pack
.BufferObj
);
822 /* buffer is already mapped - that's an error */
823 _mesa_error(ctx
, GL_INVALID_OPERATION
,
824 "glGetSeparableFilter(PBO is mapped)");
827 row
= ADD_POINTERS(buf
, row
);
828 column
= ADD_POINTERS(buf
, column
);
833 GLvoid
*dst
= _mesa_image_address1d(&ctx
->Pack
, row
, filter
->Width
,
835 _mesa_pack_rgba_span_float(ctx
, filter
->Width
,
836 (const GLfloat (*)[4]) filter
->Filter
,
837 format
, type
, dst
, &ctx
->Pack
, 0);
842 GLvoid
*dst
= _mesa_image_address1d(&ctx
->Pack
, column
, filter
->Height
,
844 const GLfloat
*src
= filter
->Filter
+ colStart
;
845 _mesa_pack_rgba_span_float(ctx
, filter
->Height
,
846 (const GLfloat (*)[4]) src
,
847 format
, type
, dst
, &ctx
->Pack
, 0);
850 (void) span
; /* unused at this time */
852 if (ctx
->Pack
.BufferObj
->Name
) {
853 /* Pack filter into PBO */
854 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
855 ctx
->Unpack
.BufferObj
);
861 _mesa_SeparableFilter2D(GLenum target
, GLenum internalFormat
, GLsizei width
, GLsizei height
, GLenum format
, GLenum type
, const GLvoid
*row
, const GLvoid
*column
)
863 const GLint colStart
= MAX_CONVOLUTION_WIDTH
* 4;
865 GET_CURRENT_CONTEXT(ctx
);
866 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
868 if (target
!= GL_SEPARABLE_2D
) {
869 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSeparableFilter2D(target)");
873 baseFormat
= base_filter_format(internalFormat
);
874 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
875 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSeparableFilter2D(internalFormat)");
879 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
880 _mesa_error(ctx
, GL_INVALID_VALUE
, "glSeparableFilter2D(width)");
883 if (height
< 0 || height
> MAX_CONVOLUTION_HEIGHT
) {
884 _mesa_error(ctx
, GL_INVALID_VALUE
, "glSeparableFilter2D(height)");
888 if (!_mesa_is_legal_format_and_type(ctx
, format
, type
)) {
889 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSeparableFilter2D(format or type)");
893 if (format
== GL_COLOR_INDEX
||
894 format
== GL_STENCIL_INDEX
||
895 format
== GL_DEPTH_COMPONENT
||
896 format
== GL_INTENSITY
||
898 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSeparableFilter2D(format or type)");
902 ctx
->Separable2D
.Format
= format
;
903 ctx
->Separable2D
.InternalFormat
= internalFormat
;
904 ctx
->Separable2D
.Width
= width
;
905 ctx
->Separable2D
.Height
= height
;
907 if (ctx
->Unpack
.BufferObj
->Name
) {
908 /* unpack filter from PBO */
910 if (!_mesa_validate_pbo_access(1, &ctx
->Unpack
, width
, 1, 1,
911 format
, type
, row
)) {
912 _mesa_error(ctx
, GL_INVALID_OPERATION
,
913 "glSeparableFilter2D(invalid PBO access, width)");
916 if (!_mesa_validate_pbo_access(1, &ctx
->Unpack
, height
, 1, 1,
917 format
, type
, column
)) {
918 _mesa_error(ctx
, GL_INVALID_OPERATION
,
919 "glSeparableFilter2D(invalid PBO access, height)");
922 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
924 ctx
->Unpack
.BufferObj
);
926 /* buffer is already mapped - that's an error */
927 _mesa_error(ctx
, GL_INVALID_OPERATION
,
928 "glSeparableFilter2D(PBO is mapped)");
931 row
= ADD_POINTERS(buf
, row
);
932 column
= ADD_POINTERS(buf
, column
);
935 /* unpack row filter */
937 _mesa_unpack_color_span_float(ctx
, width
, GL_RGBA
,
938 ctx
->Separable2D
.Filter
,
939 format
, type
, row
, &ctx
->Unpack
,
940 0); /* transferOps */
942 _mesa_scale_and_bias_rgba(width
,
943 (GLfloat (*)[4]) ctx
->Separable2D
.Filter
,
944 ctx
->Pixel
.ConvolutionFilterScale
[2][0],
945 ctx
->Pixel
.ConvolutionFilterScale
[2][1],
946 ctx
->Pixel
.ConvolutionFilterScale
[2][2],
947 ctx
->Pixel
.ConvolutionFilterScale
[2][3],
948 ctx
->Pixel
.ConvolutionFilterBias
[2][0],
949 ctx
->Pixel
.ConvolutionFilterBias
[2][1],
950 ctx
->Pixel
.ConvolutionFilterBias
[2][2],
951 ctx
->Pixel
.ConvolutionFilterBias
[2][3]);
954 /* unpack column filter */
956 _mesa_unpack_color_span_float(ctx
, height
, GL_RGBA
,
957 &ctx
->Separable2D
.Filter
[colStart
],
958 format
, type
, column
, &ctx
->Unpack
,
959 0); /* transferOps */
961 _mesa_scale_and_bias_rgba(height
,
962 (GLfloat (*)[4]) (ctx
->Separable2D
.Filter
+ colStart
),
963 ctx
->Pixel
.ConvolutionFilterScale
[2][0],
964 ctx
->Pixel
.ConvolutionFilterScale
[2][1],
965 ctx
->Pixel
.ConvolutionFilterScale
[2][2],
966 ctx
->Pixel
.ConvolutionFilterScale
[2][3],
967 ctx
->Pixel
.ConvolutionFilterBias
[2][0],
968 ctx
->Pixel
.ConvolutionFilterBias
[2][1],
969 ctx
->Pixel
.ConvolutionFilterBias
[2][2],
970 ctx
->Pixel
.ConvolutionFilterBias
[2][3]);
973 if (ctx
->Unpack
.BufferObj
->Name
) {
974 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
975 ctx
->Unpack
.BufferObj
);
978 ctx
->NewState
|= _NEW_PIXEL
;
982 /**********************************************************************/
983 /*** image convolution functions ***/
984 /**********************************************************************/
987 convolve_1d_reduce(GLint srcWidth
, const GLfloat src
[][4],
988 GLint filterWidth
, const GLfloat filter
[][4],
994 if (filterWidth
>= 1)
995 dstWidth
= srcWidth
- (filterWidth
- 1);
1000 return; /* null result */
1002 for (i
= 0; i
< dstWidth
; i
++) {
1007 for (n
= 0; n
< filterWidth
; n
++) {
1008 sumR
+= src
[i
+ n
][RCOMP
] * filter
[n
][RCOMP
];
1009 sumG
+= src
[i
+ n
][GCOMP
] * filter
[n
][GCOMP
];
1010 sumB
+= src
[i
+ n
][BCOMP
] * filter
[n
][BCOMP
];
1011 sumA
+= src
[i
+ n
][ACOMP
] * filter
[n
][ACOMP
];
1013 dest
[i
][RCOMP
] = sumR
;
1014 dest
[i
][GCOMP
] = sumG
;
1015 dest
[i
][BCOMP
] = sumB
;
1016 dest
[i
][ACOMP
] = sumA
;
1022 convolve_1d_constant(GLint srcWidth
, const GLfloat src
[][4],
1023 GLint filterWidth
, const GLfloat filter
[][4],
1025 const GLfloat borderColor
[4])
1027 const GLint halfFilterWidth
= filterWidth
/ 2;
1030 for (i
= 0; i
< srcWidth
; i
++) {
1035 for (n
= 0; n
< filterWidth
; n
++) {
1036 if (i
+ n
< halfFilterWidth
|| i
+ n
- halfFilterWidth
>= srcWidth
) {
1037 sumR
+= borderColor
[RCOMP
] * filter
[n
][RCOMP
];
1038 sumG
+= borderColor
[GCOMP
] * filter
[n
][GCOMP
];
1039 sumB
+= borderColor
[BCOMP
] * filter
[n
][BCOMP
];
1040 sumA
+= borderColor
[ACOMP
] * filter
[n
][ACOMP
];
1043 sumR
+= src
[i
+ n
- halfFilterWidth
][RCOMP
] * filter
[n
][RCOMP
];
1044 sumG
+= src
[i
+ n
- halfFilterWidth
][GCOMP
] * filter
[n
][GCOMP
];
1045 sumB
+= src
[i
+ n
- halfFilterWidth
][BCOMP
] * filter
[n
][BCOMP
];
1046 sumA
+= src
[i
+ n
- halfFilterWidth
][ACOMP
] * filter
[n
][ACOMP
];
1049 dest
[i
][RCOMP
] = sumR
;
1050 dest
[i
][GCOMP
] = sumG
;
1051 dest
[i
][BCOMP
] = sumB
;
1052 dest
[i
][ACOMP
] = sumA
;
1058 convolve_1d_replicate(GLint srcWidth
, const GLfloat src
[][4],
1059 GLint filterWidth
, const GLfloat filter
[][4],
1062 const GLint halfFilterWidth
= filterWidth
/ 2;
1065 for (i
= 0; i
< srcWidth
; i
++) {
1070 for (n
= 0; n
< filterWidth
; n
++) {
1071 if (i
+ n
< halfFilterWidth
) {
1072 sumR
+= src
[0][RCOMP
] * filter
[n
][RCOMP
];
1073 sumG
+= src
[0][GCOMP
] * filter
[n
][GCOMP
];
1074 sumB
+= src
[0][BCOMP
] * filter
[n
][BCOMP
];
1075 sumA
+= src
[0][ACOMP
] * filter
[n
][ACOMP
];
1077 else if (i
+ n
- halfFilterWidth
>= srcWidth
) {
1078 sumR
+= src
[srcWidth
- 1][RCOMP
] * filter
[n
][RCOMP
];
1079 sumG
+= src
[srcWidth
- 1][GCOMP
] * filter
[n
][GCOMP
];
1080 sumB
+= src
[srcWidth
- 1][BCOMP
] * filter
[n
][BCOMP
];
1081 sumA
+= src
[srcWidth
- 1][ACOMP
] * filter
[n
][ACOMP
];
1084 sumR
+= src
[i
+ n
- halfFilterWidth
][RCOMP
] * filter
[n
][RCOMP
];
1085 sumG
+= src
[i
+ n
- halfFilterWidth
][GCOMP
] * filter
[n
][GCOMP
];
1086 sumB
+= src
[i
+ n
- halfFilterWidth
][BCOMP
] * filter
[n
][BCOMP
];
1087 sumA
+= src
[i
+ n
- halfFilterWidth
][ACOMP
] * filter
[n
][ACOMP
];
1090 dest
[i
][RCOMP
] = sumR
;
1091 dest
[i
][GCOMP
] = sumG
;
1092 dest
[i
][BCOMP
] = sumB
;
1093 dest
[i
][ACOMP
] = sumA
;
1099 convolve_2d_reduce(GLint srcWidth
, GLint srcHeight
,
1100 const GLfloat src
[][4],
1101 GLint filterWidth
, GLint filterHeight
,
1102 const GLfloat filter
[][4],
1105 GLint dstWidth
, dstHeight
;
1108 if (filterWidth
>= 1)
1109 dstWidth
= srcWidth
- (filterWidth
- 1);
1111 dstWidth
= srcWidth
;
1113 if (filterHeight
>= 1)
1114 dstHeight
= srcHeight
- (filterHeight
- 1);
1116 dstHeight
= srcHeight
;
1118 if (dstWidth
<= 0 || dstHeight
<= 0)
1121 for (j
= 0; j
< dstHeight
; j
++) {
1122 for (i
= 0; i
< dstWidth
; i
++) {
1127 for (m
= 0; m
< filterHeight
; m
++) {
1128 for (n
= 0; n
< filterWidth
; n
++) {
1129 const GLint k
= (j
+ m
) * srcWidth
+ i
+ n
;
1130 const GLint f
= m
* filterWidth
+ n
;
1131 sumR
+= src
[k
][RCOMP
] * filter
[f
][RCOMP
];
1132 sumG
+= src
[k
][GCOMP
] * filter
[f
][GCOMP
];
1133 sumB
+= src
[k
][BCOMP
] * filter
[f
][BCOMP
];
1134 sumA
+= src
[k
][ACOMP
] * filter
[f
][ACOMP
];
1137 dest
[j
* dstWidth
+ i
][RCOMP
] = sumR
;
1138 dest
[j
* dstWidth
+ i
][GCOMP
] = sumG
;
1139 dest
[j
* dstWidth
+ i
][BCOMP
] = sumB
;
1140 dest
[j
* dstWidth
+ i
][ACOMP
] = sumA
;
1147 convolve_2d_constant(GLint srcWidth
, GLint srcHeight
,
1148 const GLfloat src
[][4],
1149 GLint filterWidth
, GLint filterHeight
,
1150 const GLfloat filter
[][4],
1152 const GLfloat borderColor
[4])
1154 const GLint halfFilterWidth
= filterWidth
/ 2;
1155 const GLint halfFilterHeight
= filterHeight
/ 2;
1158 for (j
= 0; j
< srcHeight
; j
++) {
1159 for (i
= 0; i
< srcWidth
; i
++) {
1164 for (m
= 0; m
< filterHeight
; m
++) {
1165 for (n
= 0; n
< filterWidth
; n
++) {
1166 const GLint f
= m
* filterWidth
+ n
;
1167 const GLint is
= i
+ n
- halfFilterWidth
;
1168 const GLint js
= j
+ m
- halfFilterHeight
;
1169 if (is
< 0 || is
>= srcWidth
||
1170 js
< 0 || js
>= srcHeight
) {
1171 sumR
+= borderColor
[RCOMP
] * filter
[f
][RCOMP
];
1172 sumG
+= borderColor
[GCOMP
] * filter
[f
][GCOMP
];
1173 sumB
+= borderColor
[BCOMP
] * filter
[f
][BCOMP
];
1174 sumA
+= borderColor
[ACOMP
] * filter
[f
][ACOMP
];
1177 const GLint k
= js
* srcWidth
+ is
;
1178 sumR
+= src
[k
][RCOMP
] * filter
[f
][RCOMP
];
1179 sumG
+= src
[k
][GCOMP
] * filter
[f
][GCOMP
];
1180 sumB
+= src
[k
][BCOMP
] * filter
[f
][BCOMP
];
1181 sumA
+= src
[k
][ACOMP
] * filter
[f
][ACOMP
];
1185 dest
[j
* srcWidth
+ i
][RCOMP
] = sumR
;
1186 dest
[j
* srcWidth
+ i
][GCOMP
] = sumG
;
1187 dest
[j
* srcWidth
+ i
][BCOMP
] = sumB
;
1188 dest
[j
* srcWidth
+ i
][ACOMP
] = sumA
;
1195 convolve_2d_replicate(GLint srcWidth
, GLint srcHeight
,
1196 const GLfloat src
[][4],
1197 GLint filterWidth
, GLint filterHeight
,
1198 const GLfloat filter
[][4],
1201 const GLint halfFilterWidth
= filterWidth
/ 2;
1202 const GLint halfFilterHeight
= filterHeight
/ 2;
1205 for (j
= 0; j
< srcHeight
; j
++) {
1206 for (i
= 0; i
< srcWidth
; i
++) {
1211 for (m
= 0; m
< filterHeight
; m
++) {
1212 for (n
= 0; n
< filterWidth
; n
++) {
1213 const GLint f
= m
* filterWidth
+ n
;
1214 GLint is
= i
+ n
- halfFilterWidth
;
1215 GLint js
= j
+ m
- halfFilterHeight
;
1219 else if (is
>= srcWidth
)
1223 else if (js
>= srcHeight
)
1225 k
= js
* srcWidth
+ is
;
1226 sumR
+= src
[k
][RCOMP
] * filter
[f
][RCOMP
];
1227 sumG
+= src
[k
][GCOMP
] * filter
[f
][GCOMP
];
1228 sumB
+= src
[k
][BCOMP
] * filter
[f
][BCOMP
];
1229 sumA
+= src
[k
][ACOMP
] * filter
[f
][ACOMP
];
1232 dest
[j
* srcWidth
+ i
][RCOMP
] = sumR
;
1233 dest
[j
* srcWidth
+ i
][GCOMP
] = sumG
;
1234 dest
[j
* srcWidth
+ i
][BCOMP
] = sumB
;
1235 dest
[j
* srcWidth
+ i
][ACOMP
] = sumA
;
1242 convolve_sep_reduce(GLint srcWidth
, GLint srcHeight
,
1243 const GLfloat src
[][4],
1244 GLint filterWidth
, GLint filterHeight
,
1245 const GLfloat rowFilt
[][4],
1246 const GLfloat colFilt
[][4],
1249 GLint dstWidth
, dstHeight
;
1252 if (filterWidth
>= 1)
1253 dstWidth
= srcWidth
- (filterWidth
- 1);
1255 dstWidth
= srcWidth
;
1257 if (filterHeight
>= 1)
1258 dstHeight
= srcHeight
- (filterHeight
- 1);
1260 dstHeight
= srcHeight
;
1262 if (dstWidth
<= 0 || dstHeight
<= 0)
1265 for (j
= 0; j
< dstHeight
; j
++) {
1266 for (i
= 0; i
< dstWidth
; i
++) {
1271 for (m
= 0; m
< filterHeight
; m
++) {
1272 for (n
= 0; n
< filterWidth
; n
++) {
1273 GLint k
= (j
+ m
) * srcWidth
+ i
+ n
;
1274 sumR
+= src
[k
][RCOMP
] * rowFilt
[n
][RCOMP
] * colFilt
[m
][RCOMP
];
1275 sumG
+= src
[k
][GCOMP
] * rowFilt
[n
][GCOMP
] * colFilt
[m
][GCOMP
];
1276 sumB
+= src
[k
][BCOMP
] * rowFilt
[n
][BCOMP
] * colFilt
[m
][BCOMP
];
1277 sumA
+= src
[k
][ACOMP
] * rowFilt
[n
][ACOMP
] * colFilt
[m
][ACOMP
];
1280 dest
[j
* dstWidth
+ i
][RCOMP
] = sumR
;
1281 dest
[j
* dstWidth
+ i
][GCOMP
] = sumG
;
1282 dest
[j
* dstWidth
+ i
][BCOMP
] = sumB
;
1283 dest
[j
* dstWidth
+ i
][ACOMP
] = sumA
;
1290 convolve_sep_constant(GLint srcWidth
, GLint srcHeight
,
1291 const GLfloat src
[][4],
1292 GLint filterWidth
, GLint filterHeight
,
1293 const GLfloat rowFilt
[][4],
1294 const GLfloat colFilt
[][4],
1296 const GLfloat borderColor
[4])
1298 const GLint halfFilterWidth
= filterWidth
/ 2;
1299 const GLint halfFilterHeight
= filterHeight
/ 2;
1302 for (j
= 0; j
< srcHeight
; j
++) {
1303 for (i
= 0; i
< srcWidth
; i
++) {
1308 for (m
= 0; m
< filterHeight
; m
++) {
1309 for (n
= 0; n
< filterWidth
; n
++) {
1310 const GLint is
= i
+ n
- halfFilterWidth
;
1311 const GLint js
= j
+ m
- halfFilterHeight
;
1312 if (is
< 0 || is
>= srcWidth
||
1313 js
< 0 || js
>= srcHeight
) {
1314 sumR
+= borderColor
[RCOMP
] * rowFilt
[n
][RCOMP
] * colFilt
[m
][RCOMP
];
1315 sumG
+= borderColor
[GCOMP
] * rowFilt
[n
][GCOMP
] * colFilt
[m
][GCOMP
];
1316 sumB
+= borderColor
[BCOMP
] * rowFilt
[n
][BCOMP
] * colFilt
[m
][BCOMP
];
1317 sumA
+= borderColor
[ACOMP
] * rowFilt
[n
][ACOMP
] * colFilt
[m
][ACOMP
];
1320 GLint k
= js
* srcWidth
+ is
;
1321 sumR
+= src
[k
][RCOMP
] * rowFilt
[n
][RCOMP
] * colFilt
[m
][RCOMP
];
1322 sumG
+= src
[k
][GCOMP
] * rowFilt
[n
][GCOMP
] * colFilt
[m
][GCOMP
];
1323 sumB
+= src
[k
][BCOMP
] * rowFilt
[n
][BCOMP
] * colFilt
[m
][BCOMP
];
1324 sumA
+= src
[k
][ACOMP
] * rowFilt
[n
][ACOMP
] * colFilt
[m
][ACOMP
];
1329 dest
[j
* srcWidth
+ i
][RCOMP
] = sumR
;
1330 dest
[j
* srcWidth
+ i
][GCOMP
] = sumG
;
1331 dest
[j
* srcWidth
+ i
][BCOMP
] = sumB
;
1332 dest
[j
* srcWidth
+ i
][ACOMP
] = sumA
;
1339 convolve_sep_replicate(GLint srcWidth
, GLint srcHeight
,
1340 const GLfloat src
[][4],
1341 GLint filterWidth
, GLint filterHeight
,
1342 const GLfloat rowFilt
[][4],
1343 const GLfloat colFilt
[][4],
1346 const GLint halfFilterWidth
= filterWidth
/ 2;
1347 const GLint halfFilterHeight
= filterHeight
/ 2;
1350 for (j
= 0; j
< srcHeight
; j
++) {
1351 for (i
= 0; i
< srcWidth
; i
++) {
1356 for (m
= 0; m
< filterHeight
; m
++) {
1357 for (n
= 0; n
< filterWidth
; n
++) {
1358 GLint is
= i
+ n
- halfFilterWidth
;
1359 GLint js
= j
+ m
- halfFilterHeight
;
1363 else if (is
>= srcWidth
)
1367 else if (js
>= srcHeight
)
1369 k
= js
* srcWidth
+ is
;
1370 sumR
+= src
[k
][RCOMP
] * rowFilt
[n
][RCOMP
] * colFilt
[m
][RCOMP
];
1371 sumG
+= src
[k
][GCOMP
] * rowFilt
[n
][GCOMP
] * colFilt
[m
][GCOMP
];
1372 sumB
+= src
[k
][BCOMP
] * rowFilt
[n
][BCOMP
] * colFilt
[m
][BCOMP
];
1373 sumA
+= src
[k
][ACOMP
] * rowFilt
[n
][ACOMP
] * colFilt
[m
][ACOMP
];
1376 dest
[j
* srcWidth
+ i
][RCOMP
] = sumR
;
1377 dest
[j
* srcWidth
+ i
][GCOMP
] = sumG
;
1378 dest
[j
* srcWidth
+ i
][BCOMP
] = sumB
;
1379 dest
[j
* srcWidth
+ i
][ACOMP
] = sumA
;
1387 _mesa_convolve_1d_image(const GLcontext
*ctx
, GLsizei
*width
,
1388 const GLfloat
*srcImage
, GLfloat
*dstImage
)
1390 switch (ctx
->Pixel
.ConvolutionBorderMode
[0]) {
1392 convolve_1d_reduce(*width
, (const GLfloat (*)[4]) srcImage
,
1393 ctx
->Convolution1D
.Width
,
1394 (const GLfloat (*)[4]) ctx
->Convolution1D
.Filter
,
1395 (GLfloat (*)[4]) dstImage
);
1396 *width
= *width
- (MAX2(ctx
->Convolution1D
.Width
, 1) - 1);
1398 case GL_CONSTANT_BORDER
:
1399 convolve_1d_constant(*width
, (const GLfloat (*)[4]) srcImage
,
1400 ctx
->Convolution1D
.Width
,
1401 (const GLfloat (*)[4]) ctx
->Convolution1D
.Filter
,
1402 (GLfloat (*)[4]) dstImage
,
1403 ctx
->Pixel
.ConvolutionBorderColor
[0]);
1405 case GL_REPLICATE_BORDER
:
1406 convolve_1d_replicate(*width
, (const GLfloat (*)[4]) srcImage
,
1407 ctx
->Convolution1D
.Width
,
1408 (const GLfloat (*)[4]) ctx
->Convolution1D
.Filter
,
1409 (GLfloat (*)[4]) dstImage
);
1418 _mesa_convolve_2d_image(const GLcontext
*ctx
, GLsizei
*width
, GLsizei
*height
,
1419 const GLfloat
*srcImage
, GLfloat
*dstImage
)
1421 switch (ctx
->Pixel
.ConvolutionBorderMode
[1]) {
1423 convolve_2d_reduce(*width
, *height
,
1424 (const GLfloat (*)[4]) srcImage
,
1425 ctx
->Convolution2D
.Width
,
1426 ctx
->Convolution2D
.Height
,
1427 (const GLfloat (*)[4]) ctx
->Convolution2D
.Filter
,
1428 (GLfloat (*)[4]) dstImage
);
1429 *width
= *width
- (MAX2(ctx
->Convolution2D
.Width
, 1) - 1);
1430 *height
= *height
- (MAX2(ctx
->Convolution2D
.Height
, 1) - 1);
1432 case GL_CONSTANT_BORDER
:
1433 convolve_2d_constant(*width
, *height
,
1434 (const GLfloat (*)[4]) srcImage
,
1435 ctx
->Convolution2D
.Width
,
1436 ctx
->Convolution2D
.Height
,
1437 (const GLfloat (*)[4]) ctx
->Convolution2D
.Filter
,
1438 (GLfloat (*)[4]) dstImage
,
1439 ctx
->Pixel
.ConvolutionBorderColor
[1]);
1441 case GL_REPLICATE_BORDER
:
1442 convolve_2d_replicate(*width
, *height
,
1443 (const GLfloat (*)[4]) srcImage
,
1444 ctx
->Convolution2D
.Width
,
1445 ctx
->Convolution2D
.Height
,
1446 (const GLfloat (*)[4])ctx
->Convolution2D
.Filter
,
1447 (GLfloat (*)[4]) dstImage
);
1456 _mesa_convolve_sep_image(const GLcontext
*ctx
,
1457 GLsizei
*width
, GLsizei
*height
,
1458 const GLfloat
*srcImage
, GLfloat
*dstImage
)
1460 const GLfloat
*rowFilter
= ctx
->Separable2D
.Filter
;
1461 const GLfloat
*colFilter
= rowFilter
+ 4 * MAX_CONVOLUTION_WIDTH
;
1463 switch (ctx
->Pixel
.ConvolutionBorderMode
[2]) {
1465 convolve_sep_reduce(*width
, *height
,
1466 (const GLfloat (*)[4]) srcImage
,
1467 ctx
->Separable2D
.Width
,
1468 ctx
->Separable2D
.Height
,
1469 (const GLfloat (*)[4]) rowFilter
,
1470 (const GLfloat (*)[4]) colFilter
,
1471 (GLfloat (*)[4]) dstImage
);
1472 *width
= *width
- (MAX2(ctx
->Separable2D
.Width
, 1) - 1);
1473 *height
= *height
- (MAX2(ctx
->Separable2D
.Height
, 1) - 1);
1475 case GL_CONSTANT_BORDER
:
1476 convolve_sep_constant(*width
, *height
,
1477 (const GLfloat (*)[4]) srcImage
,
1478 ctx
->Separable2D
.Width
,
1479 ctx
->Separable2D
.Height
,
1480 (const GLfloat (*)[4]) rowFilter
,
1481 (const GLfloat (*)[4]) colFilter
,
1482 (GLfloat (*)[4]) dstImage
,
1483 ctx
->Pixel
.ConvolutionBorderColor
[2]);
1485 case GL_REPLICATE_BORDER
:
1486 convolve_sep_replicate(*width
, *height
,
1487 (const GLfloat (*)[4]) srcImage
,
1488 ctx
->Separable2D
.Width
,
1489 ctx
->Separable2D
.Height
,
1490 (const GLfloat (*)[4]) rowFilter
,
1491 (const GLfloat (*)[4]) colFilter
,
1492 (GLfloat (*)[4]) dstImage
);
1502 * This function computes an image's size after convolution.
1503 * If the convolution border mode is GL_REDUCE, the post-convolution
1504 * image will be smaller than the original.
1507 _mesa_adjust_image_for_convolution(const GLcontext
*ctx
, GLuint dimensions
,
1508 GLsizei
*width
, GLsizei
*height
)
1510 if (ctx
->Pixel
.Convolution1DEnabled
1512 && ctx
->Pixel
.ConvolutionBorderMode
[0] == GL_REDUCE
) {
1513 *width
= *width
- (MAX2(ctx
->Convolution1D
.Width
, 1) - 1);
1515 else if (ctx
->Pixel
.Convolution2DEnabled
1517 && ctx
->Pixel
.ConvolutionBorderMode
[1] == GL_REDUCE
) {
1518 *width
= *width
- (MAX2(ctx
->Convolution2D
.Width
, 1) - 1);
1519 *height
= *height
- (MAX2(ctx
->Convolution2D
.Height
, 1) - 1);
1521 else if (ctx
->Pixel
.Separable2DEnabled
1523 && ctx
->Pixel
.ConvolutionBorderMode
[2] == GL_REDUCE
) {
1524 *width
= *width
- (MAX2(ctx
->Separable2D
.Width
, 1) - 1);
1525 *height
= *height
- (MAX2(ctx
->Separable2D
.Height
, 1) - 1);