Log in

View Full Version : RedAverage plugin (version 1.4.3 biiiiig bugfix)


Pages : 1 [2]

LoRd_MuldeR
19th November 2011, 02:23
If Avisynth' API doesn't provide this info, you might have to detect it yourself.

Maybe this can help:
http://git.videolan.org/gitweb.cgi?p=x264.git;a=blob;f=common/cpu.c

redfordxx
19th November 2011, 02:43
This is fun: switch (lsb)
{
case 3://16bit in 16bit out
{
#define LSB_IN
#define LSB_OUT
#include "WAM16asm.hpp"
#undef LSB_OUT
#undef LSB_IN
}
break;
case 1://16bit in 8bit out
{
#define LSB_IN
#undef LSB_OUT
#include "WAM16asm.hpp"
#undef LSB_IN
}
break;
case 2://8bit in 16bit out
{
#undef LSB_IN
#define LSB_OUT
#include "WAM16asm.hpp"
#undef LSB_OUT
}
break;
default://8bit in 8bit out
{
#undef LSB_OUT
#undef LSB_IN
#include "WAM16asm.hpp"
}

I got error message, that labels (for jumping in asm) are redefined.
I understand that, but... what is the best practice to do with that?

IanB
19th November 2011, 21:47
I have in my code SSSE3 and SSE4 instruction. They probably will get replaced, but for now, how do I detect these processors? I didn't find it in avisynth.h enum.
Didn't look to hard, lines 649, 652 and 666 of the current Avisynth.hif ((env->GetCPUFlags() & CPUF_SSSE3) && (env->GetCPUFlags() & CPUF_SSE4_1)) {
...

IanB
19th November 2011, 22:18
I got error message, that labels (for jumping in asm) are redefined.
I understand that, but... what is the best practice to do with that?

The labels are of the scope of the routine so if you #include the code chunk multiple times in the same routine you will get clashes.

Either make the labels unique each time :-// Use LABEL1 and LABEL2 in WAM16asm.hpp

#define LABEL1 label1a
#define LABEL2 label2a
#include "WAM16asm.hpp" // uses label1a and label2a as jmp targets
#undef LABEL1
#undef LABEL2

......

#define LABEL1 label1b
#define LABEL2 label2b
#include "WAM16asm.hpp" // uses label1b and label2b as jmp targets
#undef LABEL1
#undef LABEL2
Or only include the code once per routine :-type Wam1616(type1 arg1, type2 arg2) {
#define LSB_IN
#define LSB_OUT
#include "WAM16asm.hpp"
#undef LSB_OUT
#undef LSB_IN
}

type Wam168(type1 arg1, type2 arg2) {
#define LSB_IN
#include "WAM16asm.hpp"
#undef LSB_IN
}
....

redfordxx
20th November 2011, 09:48
Either make the labels unique each time :-
Well, I have 4 types of procedure and then 3 types of processors, that means 12 usages of this routine. That will be nice;-)
By the way, I won't bother will less than SSE2 at the moment, maybe later I'll look if that is feasible. I think I will have tough time getting rid of pshufb to be SSE2.

redfordxx
20th November 2011, 09:54
Didn't look to hard, lines 649, 652 and 666 of the current Avisynth.h
And now, I downloaded AVISYNTH_INTERFACE_VERSION = 5 :D

redfordxx
20th November 2011, 10:13
Well, this is something new also. I guess there is bit of difference in the avisynth.h ...I got 28 unresolved externals. Well got to find that out.

EDIT: I gave up, I went to version 3 (I was 2 before) and defined my own cpu constants. I hope it will work

redfordxx
20th November 2011, 15:36
Hi, has anyone clue why uncommenting these line can cause crashes?
And not only that! The only case it crahes is PLANE_U when input is 8bit and output stacked 16bits. And the crash seem to happen after going thru half of the height but not always the same cycleHeader file
const int MaxLen=64;

WAM16asm.hpp
...
_declspec(align(16)) unsigned char* rowendptrs[(MaxLen+2)*4];// needs constant :-(
...
int y_cnt=s_height;
__asm{
...
LABEL_VERTICAL:
...
movdqa xmm1, xmmword ptr [rowendptrs+32]
paddd xmm1, xmmword ptr [pitches+32]
//movdqa xmmword ptr [rowendptrs+32], xmm1
movdqa xmm1, xmmword ptr [rowendptrs+16]
paddd xmm1, xmmword ptr [pitches+16]
//movdqa xmmword ptr [rowendptrs+16], xmm1

movdqa xmm1, xmmword ptr [rowendptrs]
paddd xmm1, xmmword ptr [pitches]
movdqa xmmword ptr [rowendptrs], xmm1

dec y_cnt
jnz LABEL_VERTICAL
...
}

The only difference of the situation seems to be the content, but movdqa cannot crash based on content provided it is moved to declared area?

Gavino
20th November 2011, 16:27
Hi, has anyone clue why uncommenting these line can cause crashes?
And not only that! The only case it crahes is PLANE_U when input is 8bit and output stacked 16bits. And the crash seem to happen after going thru half of the height
Perhaps that is a clue...

...
int y_cnt=s_height;
__asm{
...
LABEL_VERTICAL:
...
dec y_cnt
jnz LABEL_VERTICAL
...
}

Where does s_height come from?
Note that for YV12, chroma planes are half the height of luma.

redfordxx
20th November 2011, 20:49
OMG thank you...Where does s_height come from?
const int src_height=frames[0]->GetHeight(plane);I knew that putting an output frame in the beginnig of the array of the input frames would sooner or later cause trouble:(

redfordxx
21st November 2011, 16:24
PSRAD has no Reg32 variant. Only Immediate and MMreg versions.I was not able to find explicitly this:
When shifting based on (x)mm register, is just one value from the bottom taken same way as intermediate, or it is that every word/double is shifted based on individual count in the corresponding word/double? So:

psraw xmm1,xmm2 //xmm2=0303060609090d0d
means that first two words are shifted 3bits next two words are shifted 6bits etc?

redfordxx
21st November 2011, 16:36
Is there anything I can do to help caching issues?
I mean: doing 16bit average means that I read 16bytes from four different locations in the memory (2 per clip), then I go to next clip and again 4 location only 16bytes etc and then I go back to the first location and read next 16 bytes...that must be pretty confusing for any caching algorithm or whatever the machine has, isn't it?

redfordxx
21st November 2011, 16:54
I have no idea, how expensive is conditional jumping, but I put is this way: Can be expected any difference in performance between these two cases?
Cycle:
...
dec eax
jnz Cycle

Cycle:
...
dec eax
jz EndCycle
jmp Cycle
EndCycle:

IanB
21st November 2011, 22:35
@Moderator,

Attachment approval please. post 1537311


@redfordxx,

You need to help the busy Moderators, they generally only glance at new posts not edits of old posts (mention the changed attach with a link in a new post).


The psrad function is the less useful variant, all dwords shift the same ;)

http://www.google.com.au/search?q=PSRAD+PSRAW


Cache lines are 64 bytes => do more than 64 bytes per cycle if possible.

But as long as the cache is big enough to hold all the reference within a minor cycle it should not be a problem. 1MB of cache has 16384 lines.


The single jump is better. Active jump instructions spoil the instruction prefetch and decode, with 2 jumps both paths get spoilt. But with a loop the Jc is active N times and the fall through 1 times, so it not very important.

More important is jump targets being 16 byte aligned, use align 16 before every target label.

Also put a non-condition (MMX/SSE) instruction between the condition (flag modifying) instruction and the jump test instruction to dodge the stall.

Gavino
21st November 2011, 23:25
From the first post:
All parameters are mandatory, except there must be some input clip pair.
Don't you mean all parameters are optional, except ... ? :confused:

redfordxx
22nd November 2011, 02:53
From the first post:

Don't you mean all parameters are optional, except ... ? :confused:My bad english...I will fix it.

redfordxx
22nd November 2011, 03:34
www.google.com.au
Don't worry I try to google before asking. It just didn't seem clear to me.
(I have like twenty windows in Opera open with asm references etc.)
Cache lines are 64 bytes => do more than 64 bytes per cycle if possible.Well, that won't be possible and moreover, I would understand "do 64bytes" to use all the cache, but don't understand why more...

But as long as the cache is big enough to hold all the reference within a minor cycle it should not be a problem. 1MB of cache has 16384 lines.So the conclusion for me is: there is no need or no way to tell processor "keep this in cache because I will come back in few ticks".

The single jump is better. Active jump instructions spoil the instruction prefetch and decode, with 2 jumps both paths get spoilt. But with a loop the Jc is active N times and the fall through 1 times, so it not very important.I don't think I understand it fully but conclusion is that when there is reason to do it (like having the end of last cycle handled differently) I shouldnot hesitate?
More important is jump targets being 16 byte aligned, use align 16 before every target label.
likealign 16 temporal:?

redfordxx
22nd November 2011, 04:23
So, I am leaving masked average for now and going back to weighted average. Grrr, I just wrote few pages of code in constructor to check on rounding errors and decide proper method of calculation based on sign and magnitude of the parameters.
Again, multiplication of unsigned and signed words. There are multiple methods I can see and one of them is based on following fact:c=0..65535
w=-32768..32767
c*w=(c-32768)*w+32768*w
where 32768*w for me in this case is constant, so it should be fastthe thing I am not sure about is subtracting 32768 from packed word in range 0..65535. I believe there could be really easy way, however I am not sure about the overflow things and interpretation of negative numbers. Does PSUBW mm1, 8000800080008000 do the job? Or some logical operation?

redfordxx
23rd November 2011, 15:13
I made few test and calculations and now I see that I cannot tweak the filters for maximal speed because there was in all cases the same limiting factor:
memory transfer 70Gbit/sec (based on multiplication of achieved framerate and clip dimensions) ... (is that even possible???)
So...

redfordxx
25th November 2011, 02:27
Hi, I need to shift left packed signed words with saturation to unsigned word. Is there less complicated way to do this?
pxor xmm0, xmm0
pmaxsw xmm6, xmm0
pmaxsw xmm7, xmm0
movdqa xmm2, xmm6
movdqa xmm3, xmm7

psllw xmm6, xmm5
psllw xmm7, xmm5

movdqa xmm0, xmm6
movdqa xmm1, xmm7

psrlw xmm0, xmm5
psrlw xmm1, xmm5

pcmpgtw xmm2, xmm0
pcmpgtw xmm3, xmm1

por xmm6, xmm2
por xmm7, xmm3

I have data in xmm6,xmm7
the shift count is in xmm5
(I need to shift the integer left, but if it is negative, I want it to be zero and if it is so big, that the shifting would run it out of range, then I want it to be 65535)

IanB
25th November 2011, 06:08
To clarify the question.

Signed 16bit integer as in range -32768 (0x8000) to 32767 (0x7fff)

Unsigned 16bit integer as in range 0 (0x0000) to 65535 (0xffff)

Shift left as in *= 2^N

You want to do this but 16 at a time :-unsigned short int Function(signed short int ShortValue, unsigned int N) {
int x = ShortValue;
if (x<0) return 0;
x <<= N;
if (x>65535) return 65535;
return (unsigned short int)x;
}

redfordxx
25th November 2011, 11:26
You want to do this but 16 at a time :-Yes...8 at a time will be sufficient.

The situation is, that this is upscaling the result of the weighted average to 16bit precision and then I am going to split and save it in two parts (the high and low part)

redfordxx
25th November 2011, 11:32
Here is red the part in question
LABEL_HORIZONTAL:

movdqa xmm6, xmm4
movdqa xmm7, xmm4

LABEL_TEMPORAL:
mov eax, [rowendptrs+esi] //loading data here
mov ecx, [rowendptrs+esi+8]

movdqa xmm1, xmmword ptr [eax+edi]//clip n
movdqa xmm2, xmmword ptr [ecx+edi]//clip n+1
movdqa xmm3, [multipliers+esi-TEMPSTEP] //multiplier
//time to do something
movdqa xmm0, xmm1
punpcklbw xmm0, xmm2 //clips 0...7
punpckhbw xmm1, xmm2 //clips 8...f

pmaddubsw xmm0, xmm3
pmaddubsw xmm1, xmm3
//time to do something
sub esi, TEMPSTEP

paddw xmm6, xmm0
paddw xmm7, xmm1

jnz LABEL_TEMPORAL

#ifdef LSB_OUT
test [ivst],1 //is scaling shift right or left (inverse)
mov eax, [rowendptrs]
mov ebx, [rowendptrs+4]
jnz LABEL_INV_SHIFT

psraw xmm6, xmm5
psraw xmm7, xmm5
mov esi, [length8]

movdqa xmm1, qword ptr [shufmask]

pxor xmm0, xmm0
pmaxsw xmm6, xmm0
pmaxsw xmm7, xmm0

pshufb xmm6, xmm1
pshufb xmm7, xmm1

movdqa xmm3, xmm6

punpcklqdq xmm3, xmm7
punpckhqdq xmm6, xmm7

movdqa xmmword ptr [ebx+edi], xmm3
movdqa xmmword ptr [eax+edi], xmm6

add edi, DATASTEP
jnz LABEL_HORIZONTAL
jmp LABEL_PITCHCYCLE

LABEL_INV_SHIFT:
mov esi, [length8]

pxor xmm0, xmm0
pmaxsw xmm6, xmm0
pmaxsw xmm7, xmm0
movdqa xmm2, xmm6
movdqa xmm3, xmm7

psllw xmm6, xmm5
psllw xmm7, xmm5

movdqa xmm0, xmm6
movdqa xmm1, xmm7

psrlw xmm0, xmm5
psrlw xmm1, xmm5

pcmpgtw xmm2, xmm0
pcmpgtw xmm3, xmm1

por xmm6, xmm2
por xmm7, xmm3

movdqa xmm1, qword ptr [shufmask]

pshufb xmm6, xmm1
pshufb xmm7, xmm1

movdqa xmm3, xmm6

punpcklqdq xmm3, xmm7
punpckhqdq xmm6, xmm7

movdqa xmmword ptr [ebx+edi], xmm3
movdqa xmmword ptr [eax+edi], xmm6

add edi, DATASTEP
jnz LABEL_HORIZONTAL

#else
test [ivst],1
mov eax, [rowendptrs]
jnz LABEL_INV_SHIFT

psraw xmm6, xmm5
psraw xmm7, xmm5
mov esi, [length8]

packuswb xmm6, xmm7
movdqa xmmword ptr [eax+edi], xmm6

add edi, DATASTEP
jnz LABEL_HORIZONTAL
jmp LABEL_PITCHCYCLE

LABEL_INV_SHIFT:
mov esi, [length8]

movdqa xmm1, [limiter8bit]
pxor xmm0, xmm0

pmaxsw xmm6, xmm0
pmaxsw xmm7, xmm0

movdqa xmm2, xmm6
movdqa xmm3, xmm7
pcmpgtw xmm2, xmm1
pcmpgtw xmm3, xmm1

movdqa xmm0, qword ptr [shufmask]

psllw xmm6, xmm5
psllw xmm7, xmm5
por xmm6, xmm2
por xmm7, xmm3

pshufb xmm6, xmm0
pshufb xmm7, xmm0
punpcklqdq xmm6, xmm7

movdqa xmmword ptr [eax+edi], xmm6

add edi, DATASTEP
jnz LABEL_HORIZONTAL
#endif
LABEL_PITCHCYCLE: //next line, so here increasing pitch
Storing the result is like twice so complex than calculation :(

redfordxx
25th November 2011, 21:00
When I am debugging in VC++ 2010 Express, is there possibility to see xmm registry's content or it is possible only in Pro version?

redfordxx
27th November 2011, 05:19
Another weird thing. Crash and I don't know why:
_declspec(align(64)) signed int array64[20];
signed int* zeros1=array64;
signed int* rounder1=array64+4;
signed int* shifter1=array64+8;
signed int* xmm_word_0x8000=array64+12;
....
__asm{
//this is ok
punpckhbw xmm1, [array64]
movdqa xmm0, xmmword ptr [array64+8*4]
paddw xmm0, [xmm_word_0x8000]
//this crashes....
punpckhbw xmm1, [zeros1]
movdqa xmm0, xmmword ptr [shifter1]
}Probably some basic knowledge missing here, so pls help

redfordxx
29th November 2011, 17:39
Hi, can someone tell me how easily and precisely measure the performance of the filter? The thing is, I cannot play it faster than about 10GB/s in Megui. If I do, the process eats whole core. And if it is not fast enough, on the contrary, the process shows almost negligible CPU time consumption. I don't know what to do.

As I mentioned sooner in this thead, I found some library cycles.h, but I wasn't able to make use of it.
I am spending too much time measuring with no effect, because it is all affected by memory transfer limits.

Thankyou

redfordxx
1st December 2011, 11:52
Just letting you know there is a bugfix

redfordxx
2nd December 2011, 00:48
Q: how is it with pointers? should I somehow somewhere release the references on frames and planes to free memory?

Bloax
2nd December 2011, 20:18
I can happily say now that the plugins are working like a charm. :)
The biggest advantage this has over Mt_MakeDiff is that you can specify the intensity. (Weights 2 & -2 provide much less extreme results compared to weights 32 & -32)

That reminds me, I should go ahead and mess with "CalmGrain" some more. Now that my biggest problem is solved by this. :P
Edit: As said, I now managed to make it a bit more useful using this. (Huzzah!)

redfordxx
3rd December 2011, 18:06
Thanx for words of support;-)

redfordxx
14th December 2011, 19:45
Hi, I'd like to know, if anyone of you guys thinks that RMerge(mode=256) makes sense and will be used and I should spend my notenoughtime on optimizing it or it was just my imagination that it is needed.
(This is basically me asking the customer...)

Bloax
14th December 2011, 19:49
What purpose "exactly" does it serve?

Because as far as my limited knowledge tells me, it's a mode for 16-bit merging.

redfordxx
16th December 2011, 06:45
No, it is 8bitThe goal of mode 256 is to allow merge values in full range and if m=255, then r8=c2 ... (...and not r8=(c1+c2*255+128)/256 like usually and in mode 255)

Meaning:
The problem of all mask-merge tools in avs I know is that you cannot get full range on the result.
Imagine you have the mask value=255. This is supposed to mean that you have 100% of second clip and 0% of first clip. However, the maximum value of the second clip you can get is 254, and the minimum value of the first clip (in case it is 255) is 1.
This is not the issue in mode=256. The mask values are stretched to range between 0 and 255+127/128.

jmac698
16th December 2011, 16:49
Is it possible to add median? That would be useful for a few things, mostly denoising techniques.

Btw, stacked 16bit is obviously pretty bad to work with, if we use word format, it's faster but then we need a preview mode, that is a function to show msb or lsb, or convert to stacked. The real processing and even encoding can stay in word format.

redfordxx
16th December 2011, 17:39
Is it possible to add median? That would be useful for a few things, mostly denoising techniques.
Maybe... I don't see any good algorithm to find median of multiple clips. Preferably, I want to access every source value only once (I guess it's called n-complexity)

Btw, stacked 16bit is obviously pretty bad to work with, if we use word format, it's faster but then we need a preview mode, that is a function to show msb or lsb, or convert to stacked. The real processing and even encoding can stay in word format.I don't understand sorry, please explain

jmac698
17th December 2011, 00:59
The 16bit format you support is MSB on top half and LSB on bottom. This is slow in accessing memory. A faster format is two bytes in one word next to each other in memory, so each video channel is a 16bit word. This is the format that the x264 encoder uses (avs2yuv). It is faster to access in assembly. The only problem with this format is previewing your scripts. It would be ideal if virtualdub/avsPmod would support a display mode where the video is interpreted as 16bit words.
The format is the same as in dither package, conveyAs16bit or some such function.
Yes, I'm afraid arbitrary median requires a sort. There is a simple way to sort however with min and max. Example, min(min(a,b),c), min(max(a,b),max(a,c)), max(max(a,b),c) sorts the numbers a,b,c. The median would be the middle expression.

redfordxx
17th December 2011, 04:01
The 16bit format you support is MSB on top half and LSB on bottom. This is slow in accessing memory.I thought so also and I had few posts on this topic, but I realized, all test I did (no matter what function, number of inputs or bitdepth) were around 10GB/s processing speed. There was no significant difference... I agree that it would be faster and more importantly easier to code but I had bottleneck in the bandwidth, not random access A faster format is two bytes in one word next to each other in memory, so each video channel is a 16bit word. This is the format that the x264 encoder uses (avs2yuv). Really? It is faster to access in assembly. The only problem with this format is previewing your scripts. Pointresize(width/2,height) #or similar should do the job It would be ideal if virtualdub/avsPmod would support a display mode where the video is interpreted as 16bit words.
The format is the same as in dither package, conveyAs16bit or some such function.You mean the word format??? I have chosen this stacked format because it was chosen in dither package!
Yes, I'm afraid arbitrary median requires a sort. There is a simple way to sort however with min and max. Example, min(min(a,b),c), min(max(a,b),max(a,c)), max(max(a,b),c) sorts the numbers a,b,c. The median would be the middle expression.I hate sort. 3 clips I can figure out myself also, but that is not what we are talking about. If it should be implemented, then it must be general n-inputs approach. So, I guess this will wait for brighter days of mine, since I don't see any efficient way to implement is now.

mikenadia
17th December 2011, 16:29
http://ndevilla.free.fr/median/median.pdf

redfordxx
17th December 2011, 17:19
Interesting

Jenyok
25th September 2012, 13:32
redfordxx, krasnyj ford xx
.
It is very strange, functions RAverageW , RMerge work only with "sse = 0" ...
Other value of "sse" parameter crashes AVISynth.
.

#
# http://forum.doom9.org/showthread.php?t=163598
#
# Function name DetailSharpen() is replaced by SharpenDetail() name function ...
#
function SharpenDetail(clip orig, int "str", int "thr")
{
#
# Another filter by, oh you guessed it, Bloax.
# Requirements: RedAverage, RemoveGrain and ASharp.
#
# A sharpening filter, that unlike usually, doesn't sharpen edges.
# Instead it sharpens the details, and thus it avoids the classic haloing.
# Not my idea of course, but anyways, enjoy.
#
# "str" Is the sharpening strength.
# "thr" Is the threshold for detecting edges. The higher, the more "edges" are caught, and less details are sharpened.
# Value 5 Is the best value, because 4 starts sharpening edges, and 6 sharpens way too little.
#

str = Default(str, 5)
thr = Default(thr, 5)
Threshold = Pow(2, thr)
sse0 = 0 # change this constant for limits the processor capabilities.
# -1 = use all (bitwise... 16, 8, 4 = SSE4.1, SSSE3, SSE2),
# 0 = no asm, which is veeeeryyyy sloooow.

clp = orig.IsYV12() ? orig.ConvertToYV12() : orig
msk = RAverageW(clp, Threshold, clp.RemoveGrain(19, -1), (-1) * Threshold, u=0, v=0, sse=sse0, bias=128). \
RemoveGrain(2, -1).Mt_Inpand(mode="both").Mt_Deflate()

return (RMerge(clp, clp.ASharp(str, -1), msk, sse=sse0))

#
# for debugging only
#
# return (msk)
# return (clp)
}

StainlessS
25th February 2013, 09:17
@redfordxx,

Not online since 1 April 2012, hope all is well with you.

Is the source from any version available, all versions after (seemingly 1st ver$ without source) v1.3.5 have evaporated.

StainlessS
25th February 2013, 10:38
Found link to latest RedAverage v1.4.3 (2 Dec 2011) together with source:-
http://chaosking.de/avisynth-filter-db

Thanks, ChaosKing. :thanks:

dokworm
26th March 2013, 23:21
Would it be possible to have the average throw away any obvious outliers?

For video averaging where one source has dropouts (almost white, or almost black pixels) this would be an excellent alternative to doing a median for automated dropout/sparklies etc. removal.
How many clips can be averaged or is there no limit?