Filter Factory - "cnv" function

Back to function listing

"Convolve". Applies a convolution matrix and divides with d.
Attention: Crashes in 3.0.4 because of bad programming (use src workaround or the inofficial patch).

This function is was documented in the PDF documentation of Filter Factory 3.00,
but removed in the documentation of 3.0.4, because it had a bug which was not fixed. It was described in the 3.0.4 *.wri file, though.

Syntax:

cnv(m11,m12,m13,m21,m22,m23,m31,m32,m33,d)

Synonyms

cnv0
cnv1

What it does:

Applies a convolve (weighted) matrix and divides with d:

+-----+-----+-----+
| m11 | m12 | m13 |
+-----+-----+-----+
| m21 | m22 | m23 |
+-----+-----+-----+
| m31 | m32 | m33 |
+-----+-----+-----+

Attention! In FilterFactory 3.0.4, cnv() will crash when running in a protected mode environment since the not existing border pixels (e.g. x=-1) are taken from memory which causes a memory access violation. Without protected mode, the values for the border pixels will be unexpected because the memory in the border areas is not initialized/assigned. Use the src() workaround or use the inofficial patch 3.1.x which will fix the cnv() bug.
Both variants are using the neighbor pixel values at the borders instead of 0.

Workaround:

cnv(m11,m12,m13,m21,m22,m23,m31,m32,m33,d)

can also be written as:

(src(x-1,y-1,z)*m11 +
src(x ,y-1,z)*m12 +
src(x+1,y-1,z)*m13 +
src(x-1,y ,z)*m21 +
src(x ,y ,z)*m22 +
src(x+1,y ,z)*m23 +
src(x-1,y+1,z)*m31 +
src(x ,y+1,z)*m32 +
src(x+1,y+1,z)*m33 ) / d.

Disassembly

Registers

eax = result
ebx = difference to the next pixel
ecx = beginning of the current row (inside CANVAS)
edx = current position (inside CANVAS)
edi = (reserved for the constant pool "EDI memory")
esi = Temp variable for multiplying factors
(At cnv_v3: Additionally temp variable for condition checks)
[esp-$4] = At cnv_v3: backup of the edx value

Original Machine Code (in OPER resource) of Filter Factory 3.0 and 3.0.4 for Photoshop/Win32

8B 04 24 mov eax,[esp] (param_d) result = param_d;
0B C0 or eax,eax .
0F 84 AC 00 00 00 jz +$000000ac (@div_zero) if (param_d == 0) goto @div_zero; // return 0
8B 8F A8 45 00 00 mov ecx,[edi+$000045a8] (CANVAS) ecx = CANVAS;
8B 47 58 mov eax,[edi+$58] (z) .
2B 47 5C sub eax,[edi+$5c] (zmin) .
03 C8 add ecx,eax ecx += z-zmin;
8B 47 4C mov eax,[edi+$4c] (y) .
48 dec eax .
2B 47 50 sub eax,[edi+$50] (ymin) .
F7 A7 A0 45 00 00 mul dword ptr [edi+$000045a0] (ROW_SIZE) .
03 C8 add ecx,eax ecx += (y-ymin - 1) * ROW_SIZE;
8B 47 40 mov eax,[edi+$40] (x) .
48 dec eax .
2B 47 44 sub eax,[edi+$44] (xmin) .
8B 5F 60 mov ebx,[edi+$60] (Z) .
2B 5F 5C sub ebx,[edi+$5c] (zmin) ebx = Z-zmin;
F7 E3 mul ebx .
03 C8 add ecx,eax ecx += (x-xmin - 1) * ebx;
2B C0 sub eax,eax result = 0;
8B D1 mov edx,ecx edx = ecx; // (1)
0F B6 32 movzx esi,[edx] .
0F AF 74 24 24 imul esi,[esp+$24] (param_m11) .
03 C6 add eax,esi result += [edx] * param_m11; // [edx] == src(x-1,y-1,z)
03 D3 add edx,ebx edx += Z-zmin; // next pixel
0F B6 32 movzx esi,[edx] .
0F AF 74 24 20 imul esi,[esp+$20] (param_m12) .
03 C6 add eax,esi result += [edx] * param_m12; // [edx] == src(x  ,y-1,z)
03 D3 add edx,ebx edx += Z-zmin; // next pixel
0F B6 32 movzx esi,[edx] .
0F AF 74 24 1C imul esi,[esp+$1c] (param_m13) .
03 C6 add eax,esi result += [edx] * param_m13; // [edx] == src(x+1,y-1,z)
03 8F A0 45 00 00 add ecx,[edi+$000045a0] (ROW_SIZE) ecx += ROW_SIZE;
8B D1 mov edx,ecx edx = ecx; // next line
0F B6 32 movzx esi,[edx] .
0F AF 74 24 18 imul esi,[esp+$18] (param_m21) .
03 C6 add eax,esi result += [edx] * param_m21; // [edx] == src(x-1,y  ,z)
03 D3 add edx,ebx edx += Z-zmin; // next pixel
0F B6 32 movzx esi,[edx] .
0F AF 74 24 14 imul esi,[esp+$14] (param_m22) .
03 C6 add eax,esi result += [edx] * param_m22; // [edx] == src(x  ,y  ,z)
03 D3 add edx,ebx edx += Z-zmin; // next pixel
0F B6 32 movzx esi,[edx] .
0F AF 74 24 10 imul esi,[esp+$10] (param_m23) .
03 C6 add eax,esi result += [edx] * param_m23; // [edx] == src(x+1,y  ,z)
03 8F A0 45 00 00 add ecx,[edi+$000045a0] (ROW_SIZE) ecx += ROW_SIZE;
8B D1 mov edx,ecx edx = ecx; // next line
0F B6 32 movzx esi,[edx] .
0F AF 74 24 0C imul esi,[esp+$0c] (param_m31) .
03 C6 add eax,esi result += [edx] * param_m31; // [edx] == src(x-1,y+1,z)
03 D3 add edx,ebx edx += Z-zmin; // next pixel
0F B6 32 movzx esi,[edx] .
0F AF 74 24 08 imul esi,[esp+$08] (param_m32) .
03 C6 add eax,esi result += [edx] * param_m32; // [edx] == src(x  ,y+1,z)
03 D3 add edx,ebx edx += Z-zmin; // next pixel
0F B6 32 movzx esi,[edx] .
0F AF 74 24 04 imul esi,[esp+$04] (param_m33) .
03 C6 add eax,esi result += [edx] * param_m33; // [edx] == src(x+1,y+1,z)
99 cdq .
F7 3C 24 idiv dword ptr [esp] (param_d) result /= param_d;
@div_zero: @div_zero:
83 C4 28 add esp,$28 (= 10x pop) .
50 push eax return result;

Implementation in Windows plugin 3.00a (beta version)

In the beta version 3.00a, cnv crashes if d=0. Also, inRect.top instead of ymin, and inRect.left instead of xmin was be used.

Version 3.00a (beta version) Version 3.00b (internal build), 3.00 (final), and 3.0.4
mov eax,DWORD PTR [esp]
or eax,eax
je @@end-1 ; If d=0, the program will crash (jump between an instruction)
mov ecx,DWORD PTR [edi+0x45a8] ; *CANVAS
mov eax,DWORD PTR [edi+0x58] ; z
sub eax,DWORD PTR [edi+0x5c] ; zmin
add ecx,eax
mov eax,DWORD PTR [edi+0x4c] ; y
dec eax
sub eax,DWORD PTR [edi+0x88] ; inRect.top
mul DWORD PTR [edi+0x45a0] ; ROW_SIZE
add ecx,eax
mov eax,DWORD PTR [edi+0x40] ; x
dec eax
sub eax,DWORD PTR [edi+0x84] ; ; inRect.left
mov ebx,DWORD PTR [edi+0x60] ; Z
sub ebx,DWORD PTR [edi+0x5c] ; zmin
mul ebx
add ecx,eax
sub eax,eax
mov edx,ecx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x24]
add eax,esi
add edx,ebx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x20]
add eax,esi
add edx,ebx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x1c]
add eax,esi
add ecx,DWORD PTR [edi+0x45a0]
mov edx,ecx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x18]
add eax,esi
add edx,ebx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x14]
add eax,esi
add edx,ebx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x10]
add eax,esi
add ecx,DWORD PTR [edi+0x45a0]
mov edx,ecx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0xc]
add eax,esi
add edx,ebx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x8]
add eax,esi
add edx,ebx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x4]
add eax,esi
cdq
idiv DWORD PTR [esp]
@@end:
add esp,0x28
push eax 
mov eax,DWORD PTR [esp]
or eax,eax
je @@end
mov ecx,DWORD PTR [edi+0x45a8] ; *CANVAS
mov eax,DWORD PTR [edi+0x58] ; z
sub eax,DWORD PTR [edi+0x5c] ; zmin
add ecx,eax
mov eax,DWORD PTR [edi+0x4c] ; y
dec eax
sub eax,DWORD PTR [edi+0x50] ; ymin
mul DWORD PTR [edi+0x45a0] ; ROW_SIZE
add ecx,eax
mov eax,DWORD PTR [edi+0x40] ; x
dec eax
sub eax,DWORD PTR [edi+0x44] ; xmin
mov ebx,DWORD PTR [edi+0x60] ; Z
sub ebx,DWORD PTR [edi+0x5c] ; zmin
mul ebx
add ecx,eax
sub eax,eax
mov edx,ecx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x24]
add eax,esi
add edx,ebx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x20]
add eax,esi
add edx,ebx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x1c]
add eax,esi
add ecx,DWORD PTR [edi+0x45a0]
mov edx,ecx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x18]
add eax,esi
add edx,ebx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x14]
add eax,esi
add edx,ebx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x10]
add eax,esi
add ecx,DWORD PTR [edi+0x45a0]
mov edx,ecx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0xc]
add eax,esi
add edx,ebx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x8]
add eax,esi
add edx,ebx
movzx esi,BYTE PTR [edx]
imul esi,DWORD PTR [esp+0x4]
add eax,esi
cdq
idiv DWORD PTR [esp]
@@end:
add esp,0x28
push eax