2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 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 image
= _mesa_map_validate_pbo_source(ctx
,
148 1, &ctx
->Unpack
, width
, 1, 1,
150 "glConvolutionFilter1D");
154 _mesa_unpack_color_span_float(ctx
, width
, GL_RGBA
,
155 ctx
->Convolution1D
.Filter
,
156 format
, type
, image
, &ctx
->Unpack
,
157 0); /* transferOps */
159 _mesa_unmap_pbo_source(ctx
, &ctx
->Unpack
);
161 _mesa_scale_and_bias_rgba(width
,
162 (GLfloat (*)[4]) ctx
->Convolution1D
.Filter
,
163 ctx
->Pixel
.ConvolutionFilterScale
[0][0],
164 ctx
->Pixel
.ConvolutionFilterScale
[0][1],
165 ctx
->Pixel
.ConvolutionFilterScale
[0][2],
166 ctx
->Pixel
.ConvolutionFilterScale
[0][3],
167 ctx
->Pixel
.ConvolutionFilterBias
[0][0],
168 ctx
->Pixel
.ConvolutionFilterBias
[0][1],
169 ctx
->Pixel
.ConvolutionFilterBias
[0][2],
170 ctx
->Pixel
.ConvolutionFilterBias
[0][3]);
172 ctx
->NewState
|= _NEW_PIXEL
;
177 _mesa_ConvolutionFilter2D(GLenum target
, GLenum internalFormat
, GLsizei width
, GLsizei height
, GLenum format
, GLenum type
, const GLvoid
*image
)
181 GET_CURRENT_CONTEXT(ctx
);
182 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
184 if (target
!= GL_CONVOLUTION_2D
) {
185 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter2D(target)");
189 baseFormat
= base_filter_format(internalFormat
);
190 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
191 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter2D(internalFormat)");
195 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
196 _mesa_error(ctx
, GL_INVALID_VALUE
, "glConvolutionFilter2D(width)");
199 if (height
< 0 || height
> MAX_CONVOLUTION_HEIGHT
) {
200 _mesa_error(ctx
, GL_INVALID_VALUE
, "glConvolutionFilter2D(height)");
204 if (!_mesa_is_legal_format_and_type(ctx
, format
, type
)) {
205 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glConvolutionFilter2D(format or type)");
208 if (format
== GL_COLOR_INDEX
||
209 format
== GL_STENCIL_INDEX
||
210 format
== GL_DEPTH_COMPONENT
||
211 format
== GL_INTENSITY
||
213 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter2D(format or type)");
217 /* this should have been caught earlier */
218 assert(_mesa_components_in_format(format
));
220 ctx
->Convolution2D
.Format
= format
;
221 ctx
->Convolution2D
.InternalFormat
= internalFormat
;
222 ctx
->Convolution2D
.Width
= width
;
223 ctx
->Convolution2D
.Height
= height
;
225 image
= _mesa_map_validate_pbo_source(ctx
,
226 2, &ctx
->Unpack
, width
, height
, 1,
228 "glConvolutionFilter2D");
232 /* Unpack filter image. We always store filters in RGBA format. */
233 for (i
= 0; i
< height
; i
++) {
234 const GLvoid
*src
= _mesa_image_address2d(&ctx
->Unpack
, image
, width
,
235 height
, format
, type
, i
, 0);
236 GLfloat
*dst
= ctx
->Convolution2D
.Filter
+ i
* width
* 4;
237 _mesa_unpack_color_span_float(ctx
, width
, GL_RGBA
, dst
,
238 format
, type
, src
, &ctx
->Unpack
,
239 0); /* transferOps */
242 _mesa_unmap_pbo_source(ctx
, &ctx
->Unpack
);
244 _mesa_scale_and_bias_rgba(width
* height
,
245 (GLfloat (*)[4]) ctx
->Convolution2D
.Filter
,
246 ctx
->Pixel
.ConvolutionFilterScale
[1][0],
247 ctx
->Pixel
.ConvolutionFilterScale
[1][1],
248 ctx
->Pixel
.ConvolutionFilterScale
[1][2],
249 ctx
->Pixel
.ConvolutionFilterScale
[1][3],
250 ctx
->Pixel
.ConvolutionFilterBias
[1][0],
251 ctx
->Pixel
.ConvolutionFilterBias
[1][1],
252 ctx
->Pixel
.ConvolutionFilterBias
[1][2],
253 ctx
->Pixel
.ConvolutionFilterBias
[1][3]);
255 ctx
->NewState
|= _NEW_PIXEL
;
260 _mesa_ConvolutionParameterf(GLenum target
, GLenum pname
, GLfloat param
)
262 GET_CURRENT_CONTEXT(ctx
);
264 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
267 case GL_CONVOLUTION_1D
:
270 case GL_CONVOLUTION_2D
:
273 case GL_SEPARABLE_2D
:
277 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterf(target)");
282 case GL_CONVOLUTION_BORDER_MODE
:
283 if (param
== (GLfloat
) GL_REDUCE
||
284 param
== (GLfloat
) GL_CONSTANT_BORDER
||
285 param
== (GLfloat
) GL_REPLICATE_BORDER
) {
286 ctx
->Pixel
.ConvolutionBorderMode
[c
] = (GLenum
) param
;
289 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterf(params)");
294 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterf(pname)");
298 ctx
->NewState
|= _NEW_PIXEL
;
303 _mesa_ConvolutionParameterfv(GLenum target
, GLenum pname
, const GLfloat
*params
)
305 GET_CURRENT_CONTEXT(ctx
);
307 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
310 case GL_CONVOLUTION_1D
:
313 case GL_CONVOLUTION_2D
:
316 case GL_SEPARABLE_2D
:
320 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterfv(target)");
325 case GL_CONVOLUTION_BORDER_COLOR
:
326 COPY_4V(ctx
->Pixel
.ConvolutionBorderColor
[c
], params
);
328 case GL_CONVOLUTION_BORDER_MODE
:
329 if (params
[0] == (GLfloat
) GL_REDUCE
||
330 params
[0] == (GLfloat
) GL_CONSTANT_BORDER
||
331 params
[0] == (GLfloat
) GL_REPLICATE_BORDER
) {
332 ctx
->Pixel
.ConvolutionBorderMode
[c
] = (GLenum
) params
[0];
335 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterfv(params)");
339 case GL_CONVOLUTION_FILTER_SCALE
:
340 COPY_4V(ctx
->Pixel
.ConvolutionFilterScale
[c
], params
);
342 case GL_CONVOLUTION_FILTER_BIAS
:
343 COPY_4V(ctx
->Pixel
.ConvolutionFilterBias
[c
], params
);
346 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterfv(pname)");
350 ctx
->NewState
|= _NEW_PIXEL
;
355 _mesa_ConvolutionParameteri(GLenum target
, GLenum pname
, GLint param
)
357 GET_CURRENT_CONTEXT(ctx
);
359 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
362 case GL_CONVOLUTION_1D
:
365 case GL_CONVOLUTION_2D
:
368 case GL_SEPARABLE_2D
:
372 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteri(target)");
377 case GL_CONVOLUTION_BORDER_MODE
:
378 if (param
== (GLint
) GL_REDUCE
||
379 param
== (GLint
) GL_CONSTANT_BORDER
||
380 param
== (GLint
) GL_REPLICATE_BORDER
) {
381 ctx
->Pixel
.ConvolutionBorderMode
[c
] = (GLenum
) param
;
384 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteri(params)");
389 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteri(pname)");
393 ctx
->NewState
|= _NEW_PIXEL
;
398 _mesa_ConvolutionParameteriv(GLenum target
, GLenum pname
, const GLint
*params
)
400 GET_CURRENT_CONTEXT(ctx
);
402 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
405 case GL_CONVOLUTION_1D
:
408 case GL_CONVOLUTION_2D
:
411 case GL_SEPARABLE_2D
:
415 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteriv(target)");
420 case GL_CONVOLUTION_BORDER_COLOR
:
421 ctx
->Pixel
.ConvolutionBorderColor
[c
][0] = INT_TO_FLOAT(params
[0]);
422 ctx
->Pixel
.ConvolutionBorderColor
[c
][1] = INT_TO_FLOAT(params
[1]);
423 ctx
->Pixel
.ConvolutionBorderColor
[c
][2] = INT_TO_FLOAT(params
[2]);
424 ctx
->Pixel
.ConvolutionBorderColor
[c
][3] = INT_TO_FLOAT(params
[3]);
426 case GL_CONVOLUTION_BORDER_MODE
:
427 if (params
[0] == (GLint
) GL_REDUCE
||
428 params
[0] == (GLint
) GL_CONSTANT_BORDER
||
429 params
[0] == (GLint
) GL_REPLICATE_BORDER
) {
430 ctx
->Pixel
.ConvolutionBorderMode
[c
] = (GLenum
) params
[0];
433 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteriv(params)");
437 case GL_CONVOLUTION_FILTER_SCALE
:
438 /* COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); */
439 /* need cast to prevent compiler warnings */
440 ctx
->Pixel
.ConvolutionFilterScale
[c
][0] = (GLfloat
) params
[0];
441 ctx
->Pixel
.ConvolutionFilterScale
[c
][1] = (GLfloat
) params
[1];
442 ctx
->Pixel
.ConvolutionFilterScale
[c
][2] = (GLfloat
) params
[2];
443 ctx
->Pixel
.ConvolutionFilterScale
[c
][3] = (GLfloat
) params
[3];
445 case GL_CONVOLUTION_FILTER_BIAS
:
446 /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */
447 /* need cast to prevent compiler warnings */
448 ctx
->Pixel
.ConvolutionFilterBias
[c
][0] = (GLfloat
) params
[0];
449 ctx
->Pixel
.ConvolutionFilterBias
[c
][1] = (GLfloat
) params
[1];
450 ctx
->Pixel
.ConvolutionFilterBias
[c
][2] = (GLfloat
) params
[2];
451 ctx
->Pixel
.ConvolutionFilterBias
[c
][3] = (GLfloat
) params
[3];
454 _mesa_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteriv(pname)");
458 ctx
->NewState
|= _NEW_PIXEL
;
463 _mesa_CopyConvolutionFilter1D(GLenum target
, GLenum internalFormat
, GLint x
, GLint y
, GLsizei width
)
466 GET_CURRENT_CONTEXT(ctx
);
467 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
469 if (target
!= GL_CONVOLUTION_1D
) {
470 _mesa_error(ctx
, GL_INVALID_ENUM
, "glCopyConvolutionFilter1D(target)");
474 baseFormat
= base_filter_format(internalFormat
);
475 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
476 _mesa_error(ctx
, GL_INVALID_ENUM
, "glCopyConvolutionFilter1D(internalFormat)");
480 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
481 _mesa_error(ctx
, GL_INVALID_VALUE
, "glCopyConvolutionFilter1D(width)");
485 ctx
->Driver
.CopyConvolutionFilter1D( ctx
, target
,
486 internalFormat
, x
, y
, width
);
491 _mesa_CopyConvolutionFilter2D(GLenum target
, GLenum internalFormat
, GLint x
, GLint y
, GLsizei width
, GLsizei height
)
494 GET_CURRENT_CONTEXT(ctx
);
495 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
497 if (target
!= GL_CONVOLUTION_2D
) {
498 _mesa_error(ctx
, GL_INVALID_ENUM
, "glCopyConvolutionFilter2D(target)");
502 baseFormat
= base_filter_format(internalFormat
);
503 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
504 _mesa_error(ctx
, GL_INVALID_ENUM
, "glCopyConvolutionFilter2D(internalFormat)");
508 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
509 _mesa_error(ctx
, GL_INVALID_VALUE
, "glCopyConvolutionFilter2D(width)");
512 if (height
< 0 || height
> MAX_CONVOLUTION_HEIGHT
) {
513 _mesa_error(ctx
, GL_INVALID_VALUE
, "glCopyConvolutionFilter2D(height)");
517 ctx
->Driver
.CopyConvolutionFilter2D( ctx
, target
, internalFormat
, x
, y
,
523 _mesa_GetConvolutionFilter(GLenum target
, GLenum format
, GLenum type
,
526 struct gl_convolution_attrib
*filter
;
528 GET_CURRENT_CONTEXT(ctx
);
529 ASSERT_OUTSIDE_BEGIN_END(ctx
);
532 _mesa_update_state(ctx
);
535 if (!_mesa_is_legal_format_and_type(ctx
, format
, type
)) {
536 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetConvolutionFilter(format or type)");
540 if (format
== GL_COLOR_INDEX
||
541 format
== GL_STENCIL_INDEX
||
542 format
== GL_DEPTH_COMPONENT
||
543 format
== GL_INTENSITY
||
545 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionFilter(format or type)");
550 case GL_CONVOLUTION_1D
:
551 filter
= &(ctx
->Convolution1D
);
553 case GL_CONVOLUTION_2D
:
554 filter
= &(ctx
->Convolution2D
);
557 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionFilter(target)");
561 image
= _mesa_map_validate_pbo_dest(ctx
, 2, &ctx
->Pack
,
562 filter
->Width
, filter
->Height
, 1,
564 "glGetConvolutionFilter");
568 for (row
= 0; row
< filter
->Height
; row
++) {
569 GLvoid
*dst
= _mesa_image_address2d(&ctx
->Pack
, image
, filter
->Width
,
570 filter
->Height
, format
, type
,
572 GLfloat (*src
)[4] = (GLfloat (*)[4]) (filter
->Filter
+ row
* filter
->Width
* 4);
573 _mesa_pack_rgba_span_float(ctx
, filter
->Width
, src
,
574 format
, type
, dst
, &ctx
->Pack
, 0x0);
577 _mesa_unmap_pbo_dest(ctx
, &ctx
->Pack
);
582 _mesa_GetConvolutionParameterfv(GLenum target
, GLenum pname
, GLfloat
*params
)
584 GET_CURRENT_CONTEXT(ctx
);
585 const struct gl_convolution_attrib
*conv
;
587 ASSERT_OUTSIDE_BEGIN_END(ctx
);
590 case GL_CONVOLUTION_1D
:
592 conv
= &ctx
->Convolution1D
;
594 case GL_CONVOLUTION_2D
:
596 conv
= &ctx
->Convolution2D
;
598 case GL_SEPARABLE_2D
:
600 conv
= &ctx
->Separable2D
;
603 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionParameterfv(target)");
608 case GL_CONVOLUTION_BORDER_COLOR
:
609 COPY_4V(params
, ctx
->Pixel
.ConvolutionBorderColor
[c
]);
611 case GL_CONVOLUTION_BORDER_MODE
:
612 *params
= (GLfloat
) ctx
->Pixel
.ConvolutionBorderMode
[c
];
614 case GL_CONVOLUTION_FILTER_SCALE
:
615 COPY_4V(params
, ctx
->Pixel
.ConvolutionFilterScale
[c
]);
617 case GL_CONVOLUTION_FILTER_BIAS
:
618 COPY_4V(params
, ctx
->Pixel
.ConvolutionFilterBias
[c
]);
620 case GL_CONVOLUTION_FORMAT
:
621 *params
= (GLfloat
) conv
->Format
;
623 case GL_CONVOLUTION_WIDTH
:
624 *params
= (GLfloat
) conv
->Width
;
626 case GL_CONVOLUTION_HEIGHT
:
627 *params
= (GLfloat
) conv
->Height
;
629 case GL_MAX_CONVOLUTION_WIDTH
:
630 *params
= (GLfloat
) ctx
->Const
.MaxConvolutionWidth
;
632 case GL_MAX_CONVOLUTION_HEIGHT
:
633 *params
= (GLfloat
) ctx
->Const
.MaxConvolutionHeight
;
636 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionParameterfv(pname)");
643 _mesa_GetConvolutionParameteriv(GLenum target
, GLenum pname
, GLint
*params
)
645 GET_CURRENT_CONTEXT(ctx
);
646 const struct gl_convolution_attrib
*conv
;
648 ASSERT_OUTSIDE_BEGIN_END(ctx
);
651 case GL_CONVOLUTION_1D
:
653 conv
= &ctx
->Convolution1D
;
655 case GL_CONVOLUTION_2D
:
657 conv
= &ctx
->Convolution2D
;
659 case GL_SEPARABLE_2D
:
661 conv
= &ctx
->Separable2D
;
664 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionParameteriv(target)");
669 case GL_CONVOLUTION_BORDER_COLOR
:
670 params
[0] = FLOAT_TO_INT(ctx
->Pixel
.ConvolutionBorderColor
[c
][0]);
671 params
[1] = FLOAT_TO_INT(ctx
->Pixel
.ConvolutionBorderColor
[c
][1]);
672 params
[2] = FLOAT_TO_INT(ctx
->Pixel
.ConvolutionBorderColor
[c
][2]);
673 params
[3] = FLOAT_TO_INT(ctx
->Pixel
.ConvolutionBorderColor
[c
][3]);
675 case GL_CONVOLUTION_BORDER_MODE
:
676 *params
= (GLint
) ctx
->Pixel
.ConvolutionBorderMode
[c
];
678 case GL_CONVOLUTION_FILTER_SCALE
:
679 params
[0] = (GLint
) ctx
->Pixel
.ConvolutionFilterScale
[c
][0];
680 params
[1] = (GLint
) ctx
->Pixel
.ConvolutionFilterScale
[c
][1];
681 params
[2] = (GLint
) ctx
->Pixel
.ConvolutionFilterScale
[c
][2];
682 params
[3] = (GLint
) ctx
->Pixel
.ConvolutionFilterScale
[c
][3];
684 case GL_CONVOLUTION_FILTER_BIAS
:
685 params
[0] = (GLint
) ctx
->Pixel
.ConvolutionFilterBias
[c
][0];
686 params
[1] = (GLint
) ctx
->Pixel
.ConvolutionFilterBias
[c
][1];
687 params
[2] = (GLint
) ctx
->Pixel
.ConvolutionFilterBias
[c
][2];
688 params
[3] = (GLint
) ctx
->Pixel
.ConvolutionFilterBias
[c
][3];
690 case GL_CONVOLUTION_FORMAT
:
691 *params
= (GLint
) conv
->Format
;
693 case GL_CONVOLUTION_WIDTH
:
694 *params
= (GLint
) conv
->Width
;
696 case GL_CONVOLUTION_HEIGHT
:
697 *params
= (GLint
) conv
->Height
;
699 case GL_MAX_CONVOLUTION_WIDTH
:
700 *params
= (GLint
) ctx
->Const
.MaxConvolutionWidth
;
702 case GL_MAX_CONVOLUTION_HEIGHT
:
703 *params
= (GLint
) ctx
->Const
.MaxConvolutionHeight
;
706 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionParameteriv(pname)");
713 _mesa_GetSeparableFilter(GLenum target
, GLenum format
, GLenum type
,
714 GLvoid
*row
, GLvoid
*column
, GLvoid
*span
)
716 const GLint colStart
= MAX_CONVOLUTION_WIDTH
* 4;
717 struct gl_convolution_attrib
*filter
;
718 GET_CURRENT_CONTEXT(ctx
);
719 ASSERT_OUTSIDE_BEGIN_END(ctx
);
722 _mesa_update_state(ctx
);
725 if (target
!= GL_SEPARABLE_2D
) {
726 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetSeparableFilter(target)");
730 if (!_mesa_is_legal_format_and_type(ctx
, format
, type
)) {
731 _mesa_error(ctx
, GL_INVALID_OPERATION
,
732 "glGetConvolutionFilter(format or type)");
736 if (format
== GL_COLOR_INDEX
||
737 format
== GL_STENCIL_INDEX
||
738 format
== GL_DEPTH_COMPONENT
||
739 format
== GL_INTENSITY
||
741 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionFilter(format or type)");
745 filter
= &ctx
->Separable2D
;
747 if (_mesa_is_bufferobj(ctx
->Pack
.BufferObj
)) {
748 /* Pack filter into PBO */
750 if (!_mesa_validate_pbo_access(1, &ctx
->Pack
, filter
->Width
, 1, 1,
751 format
, type
, row
)) {
752 _mesa_error(ctx
, GL_INVALID_OPERATION
,
753 "glGetSeparableFilter(invalid PBO access, width)");
756 if (!_mesa_validate_pbo_access(1, &ctx
->Pack
, filter
->Height
, 1, 1,
757 format
, type
, column
)) {
758 _mesa_error(ctx
, GL_INVALID_OPERATION
,
759 "glGetSeparableFilter(invalid PBO access, height)");
762 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_PACK_BUFFER_EXT
,
764 ctx
->Pack
.BufferObj
);
766 /* buffer is already mapped - that's an error */
767 _mesa_error(ctx
, GL_INVALID_OPERATION
,
768 "glGetSeparableFilter(PBO is mapped)");
771 row
= ADD_POINTERS(buf
, row
);
772 column
= ADD_POINTERS(buf
, column
);
777 GLvoid
*dst
= _mesa_image_address1d(&ctx
->Pack
, row
, filter
->Width
,
779 _mesa_pack_rgba_span_float(ctx
, filter
->Width
,
780 (GLfloat (*)[4]) filter
->Filter
,
781 format
, type
, dst
, &ctx
->Pack
, 0x0);
786 GLvoid
*dst
= _mesa_image_address1d(&ctx
->Pack
, column
, filter
->Height
,
788 GLfloat (*src
)[4] = (GLfloat (*)[4]) (filter
->Filter
+ colStart
);
789 _mesa_pack_rgba_span_float(ctx
, filter
->Height
, src
,
790 format
, type
, dst
, &ctx
->Pack
, 0x0);
793 (void) span
; /* unused at this time */
795 if (_mesa_is_bufferobj(ctx
->Pack
.BufferObj
)) {
796 /* Pack filter into PBO */
797 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
798 ctx
->Unpack
.BufferObj
);
804 _mesa_SeparableFilter2D(GLenum target
, GLenum internalFormat
, GLsizei width
, GLsizei height
, GLenum format
, GLenum type
, const GLvoid
*row
, const GLvoid
*column
)
806 const GLint colStart
= MAX_CONVOLUTION_WIDTH
* 4;
808 GET_CURRENT_CONTEXT(ctx
);
809 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
811 if (target
!= GL_SEPARABLE_2D
) {
812 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSeparableFilter2D(target)");
816 baseFormat
= base_filter_format(internalFormat
);
817 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
818 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSeparableFilter2D(internalFormat)");
822 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
823 _mesa_error(ctx
, GL_INVALID_VALUE
, "glSeparableFilter2D(width)");
826 if (height
< 0 || height
> MAX_CONVOLUTION_HEIGHT
) {
827 _mesa_error(ctx
, GL_INVALID_VALUE
, "glSeparableFilter2D(height)");
831 if (!_mesa_is_legal_format_and_type(ctx
, format
, type
)) {
832 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSeparableFilter2D(format or type)");
836 if (format
== GL_COLOR_INDEX
||
837 format
== GL_STENCIL_INDEX
||
838 format
== GL_DEPTH_COMPONENT
||
839 format
== GL_INTENSITY
||
841 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSeparableFilter2D(format or type)");
845 ctx
->Separable2D
.Format
= format
;
846 ctx
->Separable2D
.InternalFormat
= internalFormat
;
847 ctx
->Separable2D
.Width
= width
;
848 ctx
->Separable2D
.Height
= height
;
850 if (_mesa_is_bufferobj(ctx
->Unpack
.BufferObj
)) {
851 /* unpack filter from PBO */
853 if (!_mesa_validate_pbo_access(1, &ctx
->Unpack
, width
, 1, 1,
854 format
, type
, row
)) {
855 _mesa_error(ctx
, GL_INVALID_OPERATION
,
856 "glSeparableFilter2D(invalid PBO access, width)");
859 if (!_mesa_validate_pbo_access(1, &ctx
->Unpack
, height
, 1, 1,
860 format
, type
, column
)) {
861 _mesa_error(ctx
, GL_INVALID_OPERATION
,
862 "glSeparableFilter2D(invalid PBO access, height)");
865 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
867 ctx
->Unpack
.BufferObj
);
869 /* buffer is already mapped - that's an error */
870 _mesa_error(ctx
, GL_INVALID_OPERATION
,
871 "glSeparableFilter2D(PBO is mapped)");
874 row
= ADD_POINTERS(buf
, row
);
875 column
= ADD_POINTERS(buf
, column
);
878 /* unpack row filter */
880 _mesa_unpack_color_span_float(ctx
, width
, GL_RGBA
,
881 ctx
->Separable2D
.Filter
,
882 format
, type
, row
, &ctx
->Unpack
,
883 0); /* transferOps */
885 _mesa_scale_and_bias_rgba(width
,
886 (GLfloat (*)[4]) ctx
->Separable2D
.Filter
,
887 ctx
->Pixel
.ConvolutionFilterScale
[2][0],
888 ctx
->Pixel
.ConvolutionFilterScale
[2][1],
889 ctx
->Pixel
.ConvolutionFilterScale
[2][2],
890 ctx
->Pixel
.ConvolutionFilterScale
[2][3],
891 ctx
->Pixel
.ConvolutionFilterBias
[2][0],
892 ctx
->Pixel
.ConvolutionFilterBias
[2][1],
893 ctx
->Pixel
.ConvolutionFilterBias
[2][2],
894 ctx
->Pixel
.ConvolutionFilterBias
[2][3]);
897 /* unpack column filter */
899 _mesa_unpack_color_span_float(ctx
, height
, GL_RGBA
,
900 &ctx
->Separable2D
.Filter
[colStart
],
901 format
, type
, column
, &ctx
->Unpack
,
902 0); /* transferOps */
904 _mesa_scale_and_bias_rgba(height
,
905 (GLfloat (*)[4]) (ctx
->Separable2D
.Filter
+ colStart
),
906 ctx
->Pixel
.ConvolutionFilterScale
[2][0],
907 ctx
->Pixel
.ConvolutionFilterScale
[2][1],
908 ctx
->Pixel
.ConvolutionFilterScale
[2][2],
909 ctx
->Pixel
.ConvolutionFilterScale
[2][3],
910 ctx
->Pixel
.ConvolutionFilterBias
[2][0],
911 ctx
->Pixel
.ConvolutionFilterBias
[2][1],
912 ctx
->Pixel
.ConvolutionFilterBias
[2][2],
913 ctx
->Pixel
.ConvolutionFilterBias
[2][3]);
916 if (_mesa_is_bufferobj(ctx
->Unpack
.BufferObj
)) {
917 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
918 ctx
->Unpack
.BufferObj
);
921 ctx
->NewState
|= _NEW_PIXEL
;
925 /**********************************************************************/
926 /*** image convolution functions ***/
927 /**********************************************************************/
930 convolve_1d_reduce(GLint srcWidth
, const GLfloat src
[][4],
931 GLint filterWidth
, const GLfloat filter
[][4],
937 if (filterWidth
>= 1)
938 dstWidth
= srcWidth
- (filterWidth
- 1);
943 return; /* null result */
945 for (i
= 0; i
< dstWidth
; i
++) {
950 for (n
= 0; n
< filterWidth
; n
++) {
951 sumR
+= src
[i
+ n
][RCOMP
] * filter
[n
][RCOMP
];
952 sumG
+= src
[i
+ n
][GCOMP
] * filter
[n
][GCOMP
];
953 sumB
+= src
[i
+ n
][BCOMP
] * filter
[n
][BCOMP
];
954 sumA
+= src
[i
+ n
][ACOMP
] * filter
[n
][ACOMP
];
956 dest
[i
][RCOMP
] = sumR
;
957 dest
[i
][GCOMP
] = sumG
;
958 dest
[i
][BCOMP
] = sumB
;
959 dest
[i
][ACOMP
] = sumA
;
965 convolve_1d_constant(GLint srcWidth
, const GLfloat src
[][4],
966 GLint filterWidth
, const GLfloat filter
[][4],
968 const GLfloat borderColor
[4])
970 const GLint halfFilterWidth
= filterWidth
/ 2;
973 for (i
= 0; i
< srcWidth
; i
++) {
978 for (n
= 0; n
< filterWidth
; n
++) {
979 if (i
+ n
< halfFilterWidth
|| i
+ n
- halfFilterWidth
>= srcWidth
) {
980 sumR
+= borderColor
[RCOMP
] * filter
[n
][RCOMP
];
981 sumG
+= borderColor
[GCOMP
] * filter
[n
][GCOMP
];
982 sumB
+= borderColor
[BCOMP
] * filter
[n
][BCOMP
];
983 sumA
+= borderColor
[ACOMP
] * filter
[n
][ACOMP
];
986 sumR
+= src
[i
+ n
- halfFilterWidth
][RCOMP
] * filter
[n
][RCOMP
];
987 sumG
+= src
[i
+ n
- halfFilterWidth
][GCOMP
] * filter
[n
][GCOMP
];
988 sumB
+= src
[i
+ n
- halfFilterWidth
][BCOMP
] * filter
[n
][BCOMP
];
989 sumA
+= src
[i
+ n
- halfFilterWidth
][ACOMP
] * filter
[n
][ACOMP
];
992 dest
[i
][RCOMP
] = sumR
;
993 dest
[i
][GCOMP
] = sumG
;
994 dest
[i
][BCOMP
] = sumB
;
995 dest
[i
][ACOMP
] = sumA
;
1001 convolve_1d_replicate(GLint srcWidth
, const GLfloat src
[][4],
1002 GLint filterWidth
, const GLfloat filter
[][4],
1005 const GLint halfFilterWidth
= filterWidth
/ 2;
1008 for (i
= 0; i
< srcWidth
; i
++) {
1013 for (n
= 0; n
< filterWidth
; n
++) {
1014 if (i
+ n
< halfFilterWidth
) {
1015 sumR
+= src
[0][RCOMP
] * filter
[n
][RCOMP
];
1016 sumG
+= src
[0][GCOMP
] * filter
[n
][GCOMP
];
1017 sumB
+= src
[0][BCOMP
] * filter
[n
][BCOMP
];
1018 sumA
+= src
[0][ACOMP
] * filter
[n
][ACOMP
];
1020 else if (i
+ n
- halfFilterWidth
>= srcWidth
) {
1021 sumR
+= src
[srcWidth
- 1][RCOMP
] * filter
[n
][RCOMP
];
1022 sumG
+= src
[srcWidth
- 1][GCOMP
] * filter
[n
][GCOMP
];
1023 sumB
+= src
[srcWidth
- 1][BCOMP
] * filter
[n
][BCOMP
];
1024 sumA
+= src
[srcWidth
- 1][ACOMP
] * filter
[n
][ACOMP
];
1027 sumR
+= src
[i
+ n
- halfFilterWidth
][RCOMP
] * filter
[n
][RCOMP
];
1028 sumG
+= src
[i
+ n
- halfFilterWidth
][GCOMP
] * filter
[n
][GCOMP
];
1029 sumB
+= src
[i
+ n
- halfFilterWidth
][BCOMP
] * filter
[n
][BCOMP
];
1030 sumA
+= src
[i
+ n
- halfFilterWidth
][ACOMP
] * filter
[n
][ACOMP
];
1033 dest
[i
][RCOMP
] = sumR
;
1034 dest
[i
][GCOMP
] = sumG
;
1035 dest
[i
][BCOMP
] = sumB
;
1036 dest
[i
][ACOMP
] = sumA
;
1042 convolve_2d_reduce(GLint srcWidth
, GLint srcHeight
,
1043 const GLfloat src
[][4],
1044 GLint filterWidth
, GLint filterHeight
,
1045 const GLfloat filter
[][4],
1048 GLint dstWidth
, dstHeight
;
1051 if (filterWidth
>= 1)
1052 dstWidth
= srcWidth
- (filterWidth
- 1);
1054 dstWidth
= srcWidth
;
1056 if (filterHeight
>= 1)
1057 dstHeight
= srcHeight
- (filterHeight
- 1);
1059 dstHeight
= srcHeight
;
1061 if (dstWidth
<= 0 || dstHeight
<= 0)
1064 for (j
= 0; j
< dstHeight
; j
++) {
1065 for (i
= 0; i
< dstWidth
; i
++) {
1070 for (m
= 0; m
< filterHeight
; m
++) {
1071 for (n
= 0; n
< filterWidth
; n
++) {
1072 const GLint k
= (j
+ m
) * srcWidth
+ i
+ n
;
1073 const GLint f
= m
* filterWidth
+ n
;
1074 sumR
+= src
[k
][RCOMP
] * filter
[f
][RCOMP
];
1075 sumG
+= src
[k
][GCOMP
] * filter
[f
][GCOMP
];
1076 sumB
+= src
[k
][BCOMP
] * filter
[f
][BCOMP
];
1077 sumA
+= src
[k
][ACOMP
] * filter
[f
][ACOMP
];
1080 dest
[j
* dstWidth
+ i
][RCOMP
] = sumR
;
1081 dest
[j
* dstWidth
+ i
][GCOMP
] = sumG
;
1082 dest
[j
* dstWidth
+ i
][BCOMP
] = sumB
;
1083 dest
[j
* dstWidth
+ i
][ACOMP
] = sumA
;
1090 convolve_2d_constant(GLint srcWidth
, GLint srcHeight
,
1091 const GLfloat src
[][4],
1092 GLint filterWidth
, GLint filterHeight
,
1093 const GLfloat filter
[][4],
1095 const GLfloat borderColor
[4])
1097 const GLint halfFilterWidth
= filterWidth
/ 2;
1098 const GLint halfFilterHeight
= filterHeight
/ 2;
1101 for (j
= 0; j
< srcHeight
; j
++) {
1102 for (i
= 0; i
< srcWidth
; i
++) {
1107 for (m
= 0; m
< filterHeight
; m
++) {
1108 for (n
= 0; n
< filterWidth
; n
++) {
1109 const GLint f
= m
* filterWidth
+ n
;
1110 const GLint is
= i
+ n
- halfFilterWidth
;
1111 const GLint js
= j
+ m
- halfFilterHeight
;
1112 if (is
< 0 || is
>= srcWidth
||
1113 js
< 0 || js
>= srcHeight
) {
1114 sumR
+= borderColor
[RCOMP
] * filter
[f
][RCOMP
];
1115 sumG
+= borderColor
[GCOMP
] * filter
[f
][GCOMP
];
1116 sumB
+= borderColor
[BCOMP
] * filter
[f
][BCOMP
];
1117 sumA
+= borderColor
[ACOMP
] * filter
[f
][ACOMP
];
1120 const GLint k
= js
* srcWidth
+ is
;
1121 sumR
+= src
[k
][RCOMP
] * filter
[f
][RCOMP
];
1122 sumG
+= src
[k
][GCOMP
] * filter
[f
][GCOMP
];
1123 sumB
+= src
[k
][BCOMP
] * filter
[f
][BCOMP
];
1124 sumA
+= src
[k
][ACOMP
] * filter
[f
][ACOMP
];
1128 dest
[j
* srcWidth
+ i
][RCOMP
] = sumR
;
1129 dest
[j
* srcWidth
+ i
][GCOMP
] = sumG
;
1130 dest
[j
* srcWidth
+ i
][BCOMP
] = sumB
;
1131 dest
[j
* srcWidth
+ i
][ACOMP
] = sumA
;
1138 convolve_2d_replicate(GLint srcWidth
, GLint srcHeight
,
1139 const GLfloat src
[][4],
1140 GLint filterWidth
, GLint filterHeight
,
1141 const GLfloat filter
[][4],
1144 const GLint halfFilterWidth
= filterWidth
/ 2;
1145 const GLint halfFilterHeight
= filterHeight
/ 2;
1148 for (j
= 0; j
< srcHeight
; j
++) {
1149 for (i
= 0; i
< srcWidth
; i
++) {
1154 for (m
= 0; m
< filterHeight
; m
++) {
1155 for (n
= 0; n
< filterWidth
; n
++) {
1156 const GLint f
= m
* filterWidth
+ n
;
1157 GLint is
= i
+ n
- halfFilterWidth
;
1158 GLint js
= j
+ m
- halfFilterHeight
;
1162 else if (is
>= srcWidth
)
1166 else if (js
>= srcHeight
)
1168 k
= js
* srcWidth
+ is
;
1169 sumR
+= src
[k
][RCOMP
] * filter
[f
][RCOMP
];
1170 sumG
+= src
[k
][GCOMP
] * filter
[f
][GCOMP
];
1171 sumB
+= src
[k
][BCOMP
] * filter
[f
][BCOMP
];
1172 sumA
+= src
[k
][ACOMP
] * filter
[f
][ACOMP
];
1175 dest
[j
* srcWidth
+ i
][RCOMP
] = sumR
;
1176 dest
[j
* srcWidth
+ i
][GCOMP
] = sumG
;
1177 dest
[j
* srcWidth
+ i
][BCOMP
] = sumB
;
1178 dest
[j
* srcWidth
+ i
][ACOMP
] = sumA
;
1185 convolve_sep_reduce(GLint srcWidth
, GLint srcHeight
,
1186 const GLfloat src
[][4],
1187 GLint filterWidth
, GLint filterHeight
,
1188 const GLfloat rowFilt
[][4],
1189 const GLfloat colFilt
[][4],
1192 GLint dstWidth
, dstHeight
;
1195 if (filterWidth
>= 1)
1196 dstWidth
= srcWidth
- (filterWidth
- 1);
1198 dstWidth
= srcWidth
;
1200 if (filterHeight
>= 1)
1201 dstHeight
= srcHeight
- (filterHeight
- 1);
1203 dstHeight
= srcHeight
;
1205 if (dstWidth
<= 0 || dstHeight
<= 0)
1208 for (j
= 0; j
< dstHeight
; j
++) {
1209 for (i
= 0; i
< dstWidth
; i
++) {
1214 for (m
= 0; m
< filterHeight
; m
++) {
1215 for (n
= 0; n
< filterWidth
; n
++) {
1216 GLint k
= (j
+ m
) * srcWidth
+ i
+ n
;
1217 sumR
+= src
[k
][RCOMP
] * rowFilt
[n
][RCOMP
] * colFilt
[m
][RCOMP
];
1218 sumG
+= src
[k
][GCOMP
] * rowFilt
[n
][GCOMP
] * colFilt
[m
][GCOMP
];
1219 sumB
+= src
[k
][BCOMP
] * rowFilt
[n
][BCOMP
] * colFilt
[m
][BCOMP
];
1220 sumA
+= src
[k
][ACOMP
] * rowFilt
[n
][ACOMP
] * colFilt
[m
][ACOMP
];
1223 dest
[j
* dstWidth
+ i
][RCOMP
] = sumR
;
1224 dest
[j
* dstWidth
+ i
][GCOMP
] = sumG
;
1225 dest
[j
* dstWidth
+ i
][BCOMP
] = sumB
;
1226 dest
[j
* dstWidth
+ i
][ACOMP
] = sumA
;
1233 convolve_sep_constant(GLint srcWidth
, GLint srcHeight
,
1234 const GLfloat src
[][4],
1235 GLint filterWidth
, GLint filterHeight
,
1236 const GLfloat rowFilt
[][4],
1237 const GLfloat colFilt
[][4],
1239 const GLfloat borderColor
[4])
1241 const GLint halfFilterWidth
= filterWidth
/ 2;
1242 const GLint halfFilterHeight
= filterHeight
/ 2;
1245 for (j
= 0; j
< srcHeight
; j
++) {
1246 for (i
= 0; i
< srcWidth
; i
++) {
1251 for (m
= 0; m
< filterHeight
; m
++) {
1252 for (n
= 0; n
< filterWidth
; n
++) {
1253 const GLint is
= i
+ n
- halfFilterWidth
;
1254 const GLint js
= j
+ m
- halfFilterHeight
;
1255 if (is
< 0 || is
>= srcWidth
||
1256 js
< 0 || js
>= srcHeight
) {
1257 sumR
+= borderColor
[RCOMP
] * rowFilt
[n
][RCOMP
] * colFilt
[m
][RCOMP
];
1258 sumG
+= borderColor
[GCOMP
] * rowFilt
[n
][GCOMP
] * colFilt
[m
][GCOMP
];
1259 sumB
+= borderColor
[BCOMP
] * rowFilt
[n
][BCOMP
] * colFilt
[m
][BCOMP
];
1260 sumA
+= borderColor
[ACOMP
] * rowFilt
[n
][ACOMP
] * colFilt
[m
][ACOMP
];
1263 GLint k
= js
* srcWidth
+ is
;
1264 sumR
+= src
[k
][RCOMP
] * rowFilt
[n
][RCOMP
] * colFilt
[m
][RCOMP
];
1265 sumG
+= src
[k
][GCOMP
] * rowFilt
[n
][GCOMP
] * colFilt
[m
][GCOMP
];
1266 sumB
+= src
[k
][BCOMP
] * rowFilt
[n
][BCOMP
] * colFilt
[m
][BCOMP
];
1267 sumA
+= src
[k
][ACOMP
] * rowFilt
[n
][ACOMP
] * colFilt
[m
][ACOMP
];
1272 dest
[j
* srcWidth
+ i
][RCOMP
] = sumR
;
1273 dest
[j
* srcWidth
+ i
][GCOMP
] = sumG
;
1274 dest
[j
* srcWidth
+ i
][BCOMP
] = sumB
;
1275 dest
[j
* srcWidth
+ i
][ACOMP
] = sumA
;
1282 convolve_sep_replicate(GLint srcWidth
, GLint srcHeight
,
1283 const GLfloat src
[][4],
1284 GLint filterWidth
, GLint filterHeight
,
1285 const GLfloat rowFilt
[][4],
1286 const GLfloat colFilt
[][4],
1289 const GLint halfFilterWidth
= filterWidth
/ 2;
1290 const GLint halfFilterHeight
= filterHeight
/ 2;
1293 for (j
= 0; j
< srcHeight
; j
++) {
1294 for (i
= 0; i
< srcWidth
; i
++) {
1299 for (m
= 0; m
< filterHeight
; m
++) {
1300 for (n
= 0; n
< filterWidth
; n
++) {
1301 GLint is
= i
+ n
- halfFilterWidth
;
1302 GLint js
= j
+ m
- halfFilterHeight
;
1306 else if (is
>= srcWidth
)
1310 else if (js
>= srcHeight
)
1312 k
= js
* srcWidth
+ is
;
1313 sumR
+= src
[k
][RCOMP
] * rowFilt
[n
][RCOMP
] * colFilt
[m
][RCOMP
];
1314 sumG
+= src
[k
][GCOMP
] * rowFilt
[n
][GCOMP
] * colFilt
[m
][GCOMP
];
1315 sumB
+= src
[k
][BCOMP
] * rowFilt
[n
][BCOMP
] * colFilt
[m
][BCOMP
];
1316 sumA
+= src
[k
][ACOMP
] * rowFilt
[n
][ACOMP
] * colFilt
[m
][ACOMP
];
1319 dest
[j
* srcWidth
+ i
][RCOMP
] = sumR
;
1320 dest
[j
* srcWidth
+ i
][GCOMP
] = sumG
;
1321 dest
[j
* srcWidth
+ i
][BCOMP
] = sumB
;
1322 dest
[j
* srcWidth
+ i
][ACOMP
] = sumA
;
1330 _mesa_convolve_1d_image(const GLcontext
*ctx
, GLsizei
*width
,
1331 const GLfloat
*srcImage
, GLfloat
*dstImage
)
1333 switch (ctx
->Pixel
.ConvolutionBorderMode
[0]) {
1335 convolve_1d_reduce(*width
, (const GLfloat (*)[4]) srcImage
,
1336 ctx
->Convolution1D
.Width
,
1337 (const GLfloat (*)[4]) ctx
->Convolution1D
.Filter
,
1338 (GLfloat (*)[4]) dstImage
);
1339 *width
= *width
- (MAX2(ctx
->Convolution1D
.Width
, 1) - 1);
1341 case GL_CONSTANT_BORDER
:
1342 convolve_1d_constant(*width
, (const GLfloat (*)[4]) srcImage
,
1343 ctx
->Convolution1D
.Width
,
1344 (const GLfloat (*)[4]) ctx
->Convolution1D
.Filter
,
1345 (GLfloat (*)[4]) dstImage
,
1346 ctx
->Pixel
.ConvolutionBorderColor
[0]);
1348 case GL_REPLICATE_BORDER
:
1349 convolve_1d_replicate(*width
, (const GLfloat (*)[4]) srcImage
,
1350 ctx
->Convolution1D
.Width
,
1351 (const GLfloat (*)[4]) ctx
->Convolution1D
.Filter
,
1352 (GLfloat (*)[4]) dstImage
);
1361 _mesa_convolve_2d_image(const GLcontext
*ctx
, GLsizei
*width
, GLsizei
*height
,
1362 const GLfloat
*srcImage
, GLfloat
*dstImage
)
1364 switch (ctx
->Pixel
.ConvolutionBorderMode
[1]) {
1366 convolve_2d_reduce(*width
, *height
,
1367 (const GLfloat (*)[4]) srcImage
,
1368 ctx
->Convolution2D
.Width
,
1369 ctx
->Convolution2D
.Height
,
1370 (const GLfloat (*)[4]) ctx
->Convolution2D
.Filter
,
1371 (GLfloat (*)[4]) dstImage
);
1372 *width
= *width
- (MAX2(ctx
->Convolution2D
.Width
, 1) - 1);
1373 *height
= *height
- (MAX2(ctx
->Convolution2D
.Height
, 1) - 1);
1375 case GL_CONSTANT_BORDER
:
1376 convolve_2d_constant(*width
, *height
,
1377 (const GLfloat (*)[4]) srcImage
,
1378 ctx
->Convolution2D
.Width
,
1379 ctx
->Convolution2D
.Height
,
1380 (const GLfloat (*)[4]) ctx
->Convolution2D
.Filter
,
1381 (GLfloat (*)[4]) dstImage
,
1382 ctx
->Pixel
.ConvolutionBorderColor
[1]);
1384 case GL_REPLICATE_BORDER
:
1385 convolve_2d_replicate(*width
, *height
,
1386 (const GLfloat (*)[4]) srcImage
,
1387 ctx
->Convolution2D
.Width
,
1388 ctx
->Convolution2D
.Height
,
1389 (const GLfloat (*)[4])ctx
->Convolution2D
.Filter
,
1390 (GLfloat (*)[4]) dstImage
);
1399 _mesa_convolve_sep_image(const GLcontext
*ctx
,
1400 GLsizei
*width
, GLsizei
*height
,
1401 const GLfloat
*srcImage
, GLfloat
*dstImage
)
1403 const GLfloat
*rowFilter
= ctx
->Separable2D
.Filter
;
1404 const GLfloat
*colFilter
= rowFilter
+ 4 * MAX_CONVOLUTION_WIDTH
;
1406 switch (ctx
->Pixel
.ConvolutionBorderMode
[2]) {
1408 convolve_sep_reduce(*width
, *height
,
1409 (const GLfloat (*)[4]) srcImage
,
1410 ctx
->Separable2D
.Width
,
1411 ctx
->Separable2D
.Height
,
1412 (const GLfloat (*)[4]) rowFilter
,
1413 (const GLfloat (*)[4]) colFilter
,
1414 (GLfloat (*)[4]) dstImage
);
1415 *width
= *width
- (MAX2(ctx
->Separable2D
.Width
, 1) - 1);
1416 *height
= *height
- (MAX2(ctx
->Separable2D
.Height
, 1) - 1);
1418 case GL_CONSTANT_BORDER
:
1419 convolve_sep_constant(*width
, *height
,
1420 (const GLfloat (*)[4]) srcImage
,
1421 ctx
->Separable2D
.Width
,
1422 ctx
->Separable2D
.Height
,
1423 (const GLfloat (*)[4]) rowFilter
,
1424 (const GLfloat (*)[4]) colFilter
,
1425 (GLfloat (*)[4]) dstImage
,
1426 ctx
->Pixel
.ConvolutionBorderColor
[2]);
1428 case GL_REPLICATE_BORDER
:
1429 convolve_sep_replicate(*width
, *height
,
1430 (const GLfloat (*)[4]) srcImage
,
1431 ctx
->Separable2D
.Width
,
1432 ctx
->Separable2D
.Height
,
1433 (const GLfloat (*)[4]) rowFilter
,
1434 (const GLfloat (*)[4]) colFilter
,
1435 (GLfloat (*)[4]) dstImage
);
1445 * This function computes an image's size after convolution.
1446 * If the convolution border mode is GL_REDUCE, the post-convolution
1447 * image will be smaller than the original.
1450 _mesa_adjust_image_for_convolution(const GLcontext
*ctx
, GLuint dimensions
,
1451 GLsizei
*width
, GLsizei
*height
)
1453 if (ctx
->Pixel
.Convolution1DEnabled
1455 && ctx
->Pixel
.ConvolutionBorderMode
[0] == GL_REDUCE
) {
1456 *width
= *width
- (MAX2(ctx
->Convolution1D
.Width
, 1) - 1);
1458 else if (ctx
->Pixel
.Convolution2DEnabled
1460 && ctx
->Pixel
.ConvolutionBorderMode
[1] == GL_REDUCE
) {
1461 *width
= *width
- (MAX2(ctx
->Convolution2D
.Width
, 1) - 1);
1462 *height
= *height
- (MAX2(ctx
->Convolution2D
.Height
, 1) - 1);
1464 else if (ctx
->Pixel
.Separable2DEnabled
1466 && ctx
->Pixel
.ConvolutionBorderMode
[2] == GL_REDUCE
) {
1467 *width
= *width
- (MAX2(ctx
->Separable2D
.Width
, 1) - 1);
1468 *height
= *height
- (MAX2(ctx
->Separable2D
.Height
, 1) - 1);