View Full Version : JPSDR Avisynth's plugins pack
jpsdr
29th December 2019, 12:35
New version, see first post.
jpsdr
29th April 2020, 00:12
New version, see first post.
FranceBB
29th April 2020, 02:08
New version, see first post.
Yep, I silently lurked the awarpsharp thing on the other topic.
Thank you for the update, it seems to work fine on Windows XP; perhaps I never noticed the error 'cause AVX are not a thing on XP (and I don't encode anime at work where I have Win10), so I never used that part of the code...
Cheers,
Frank. :)
real.finder
29th April 2020, 02:50
Yep, I silently lurked the awarpsharp thing on the other topic.
Thank you for the update, it seems to work fine on Windows XP; perhaps I never noticed the error 'cause AVX are not a thing on XP (and I don't encode anime at work where I have Win10), so I never used that part of the code...
Cheers,
Frank. :)
awarpsharp may made for anime, but it used in YAHR by Didée which a general use dehalo
https://web.archive.org/web/20090803132834/https://forum.doom9.org/showthread.php?p=1205653
SeregaDS
4th May 2020, 17:30
Hi!
I have an issue with last version of plugins_JPSDR_v3_2_1 (But with the previous version plugins_JPSDR_v3_2_0 - all right).
The next code produce strange video:
TempGaussMC_beta2u (tr0=2,tr1=2,tr2=3,EdiMode="NNEDI3", SLrad=2)
http://i.piccy.info/i9/f3ec96ae2f3670bb9db63c9351551e5d/1588609494/62178/1376488/Annotation_2020_05_04_192103.jpg
(without using NNEDI3 - also all right)
In the same time, the next code produce normal video:
QTGMC(tr0=2,tr1=2,tr2=3,EdiMode="NNEEDI3", SLrad=2)
http://i.piccy.info/i9/c1d372a553cb92f064f781910ab264db/1588609723/68642/1376488/Annotation_2020_05_04_192109.jpg
Win10x64. AviSynth+ 3.5.2 (r3218, neo, x86_64)
In VDub, this seems to work :
ColorBars(width=640, height=480, pixel_type="yv12")
#QTGMC().SelectEven()
but this one crash inside avisynth:
QTGMC(preset="Very Slow", InputType=0,sourceMatch=3, sharpness=0.2, tr2=2, ediThreads=1).SelectEven()
The second one involve FFT3DFilter.
Is TempGaussMC_beta2u using FFT3DFilter ?
I'll try to make a version not using the new Pplanar, maybe it was too soon for the new headers... (if it's that).
SeregaDS
5th May 2020, 14:32
Is TempGaussMC_beta2u using FFT3DFilter ?
I don't think so...
Search for string "FFT3" inside script didn't find any results...
And if i use EEDIx (not NNEDI3) - script works normal.
pinterf
5th May 2020, 14:42
In VDub, this seems to work :
ColorBars(width=640, height=480, pixel_type="yv12")
#QTGMC().SelectEven()
but this one crash inside avisynth:
QTGMC(preset="Very Slow", InputType=0,sourceMatch=3, sharpness=0.2, tr2=2, ediThreads=1).SelectEven()
The second one involve FFT3DFilter.
Is TempGaussMC_beta2u using FFT3DFilter ?
I'll try to make a version not using the new Pplanar, maybe it was too soon for the new headers... (if it's that).
Previous version (0.9.4.53) was staying at 306MB (avsmeter64) and works at 8+fps (whole qtgmc), this last one seems to have a memory leak, shortly reaches 4GB where Avisynth is slowing down since it tries to free up caches.
My standard PC (the one i'm writting with here) is under standard avs2.6.1, this is why the second qtgmc script crash, it's probably not working under avs2.6.1.
SeregaDS
5th May 2020, 15:23
So, please try to use TempGaussMC_beta2u :)
It works with all versions of Avs...
Ok, i've figure out where it's happening, but i'm unable to figure out the proper syntax for transmiting parameters.
Before, the src was created and used inside the copyPad function, called at the begining of the GetFrame function:
void nnedi3::copyPad(int n, int fn, IScriptEnvironment *env)
{
const int off = 1-fn;
PVideoFrame src = child->GetFrame(n, env);
and src wasn't needed outside anymore.
Now, i need the src to create the dst, so, now, instead of:
PVideoFrame __stdcall nnedi3::GetFrame(int n, IScriptEnvironment *env)
{
int field_n;
if (field>1)
{
if (n&1) field_n = field == 3 ? 0 : 1;
else field_n = field == 3 ? 1 : 0;
}
else field_n = field;
copyPad(field>1?(n>>1):n,field_n,env);
i have:
PVideoFrame __stdcall nnedi3::GetFrame(int n, IScriptEnvironment *env)
{
int field_n;
if (field>1)
{
if (n&1) field_n = field == 3 ? 0 : 1;
else field_n = field == 3 ? 1 : 0;
}
else field_n = field;
PVideoFrame src = child->GetFrame(n,env);
copyPad(src,field>1?(n>>1):n,field_n,env);
This is what creating the memory leak and the issues.
I've tried
void copyPad(const PVideoFrame &src,int n,int fn,IScriptEnvironment *env);
and without const and also
void copyPad(PVideoFrame src,int n,int fn,IScriptEnvironment *env);
still the same behavior...
I'll try a mix with previous version, copyPad geting src and return it...
MeteorRain
5th May 2020, 16:35
I noticed src was used in both copyPad and NewVideoFrameP. Any chance it's the latter?
No... It's the new thing, now i need src for NewVideoFrameP.
I've made my tests by implementing the changes step by step, and kept NewVideoFrameP for the end, so, i've re-created the issue before puting back NewVideoFrameP.
It seems that a mix, creating src inside copyPad and having it return src works, no memory leak anymore and identical speed.
New build soon.
pinterf
5th May 2020, 16:41
I noticed src was used in both copyPad and NewVideoFrameP. Any chance it's the latter?
I have tried with an old r2900 avs+, and it still leaks, that is not using the P vesion. For the first sight I cannot tell what is happening.
pinterf
5th May 2020, 17:00
No... It's the new thing, now i need src for NewVideoFrameP.
I've made my tests by implementing the changes step by step, and kept NewVideoFrameP for the end, so, i've re-created the issue before puting back NewVideoFrameP.
It seems that a mix, creating src inside copyPad and having it return src works, no memory leak anymore and identical speed.
New build soon.
GetFrame recursively called itself with the same n, but 'n' is different in copyPad.
This one works:
int x = field > 1 ? (n >> 1) : n;
PVideoFrame src = child->GetFrame(x,env);
OMFG !!! This is what i've missed !!!
:thanks:
New version, see first post, should be fixed.
jpsdr
22nd July 2020, 06:12
New version, see first post.
jpsdr
2nd August 2020, 08:52
New version, see first post.
DTL
2nd August 2020, 14:31
As an addition to readme.txt about SincLin2Resize:
It designed as workaround to fix edge bugs with SincResize if using too few number of taps. 'Too few' mean about < 60..70 with 8-bit integer samples processing. It gives at least taps/2 full-strike sinc kernel size and last taps are linearly faded to zero (something like 'trapezoidal weighting'). At some testcases it allows to get clean 8-bit result with taps parameter as low as 15. That is significally faster in compare with SincResize(taps=70). With lesser taps parameter it may definetly expose same edge 'ghosting' and 'object griding' bugs as old SincResize. So for high quality work it is recommended to keep taps >15..20. It is a bit sharper in compare with LanczosResize with same number of taps because of less aggressive sinc kernel weighting.
dREV
24th November 2020, 03:15
Hi, I wanted to ask about which of the NNEDI's would be best to use on my PC. It's a AMD Ryzen 5 2nd generation I think it's either 6 or 12 cores not sure with 16 GB and on Windows 7 64 bit OS using MeGUI and AviSynth+ 3.6.1 86x version.
I tried reading the readme.txt but not much info there. I been using the folder marked "Release_W7_AVX2" with no issues not sure about the other ones tho.
I was also going to ask a question about the prefetch but it seems really complicated. I've been trying to understand it and more than likely I've been doing it wrong seeing I've had it set to "prefetch=1" according to your multithreading.txt file. I'll just use the default from now on as my fps is a lot faster then when I try the prefetch.
FranceBB
24th November 2020, 09:45
Afaik AMD Ryzen have up to AVX2 instructions set, so you're probably already using the best possible build.
Please note, though, that since it's coded in C++, the fact that the compiler is instructed to use up to AVX2 doesn't always reflect in improved speed performance.
This is because it's the compiler that is trying to understand what the programmer is doing and write the corresponding assembly optimizations to use all the available instructions set, so it might not make use of them anyway (it can happen) or even misunderstand and generate a slightly slower code (very rare, but it can happen and if you look at other posts here on Doom9 for other plugins there have been times in which some builds were faster than others while it was supposed to be the other way round).
Anyway, as far as everything is behaving correctly and according to a logic, you're already using the fastest build.
If you want, though, you can benchmark the various builds with AVSMeter and in your case I would benchmark two builds in particular: Clang W7 AVX2 and W7 AVX2 so that you can see whether Visual Studio or clang llvm produced a faster build.
I generally stick with the Visual Studio ones, but many people say that Clang ones are faster on their machines, so I guess it's worth giving them a shot. ;)
Boulder
24th November 2020, 10:49
Clang build for various plugins have generally been faster on my Zen (1 & 2) systems.
jpsdr
24th November 2020, 18:06
If you're not using the avisynth MT part (so prefetch in your script), no need to set the prefetch.
If you're using prefetch in your script, the best would be to have prefetch*threads=CPU.
StainlessS
25th November 2020, 03:35
prefetch*threads=CPU
What exactly might that mean [x*y="AMD Ryzen 5600X", or maybe something else].
jpsdr
25th November 2020, 19:46
CPU, core, it's the same...
So, CPU=core number.
StainlessS
25th November 2020, 20:41
so physical cores.
Thank you.
jpsdr
26th November 2020, 20:48
I think the optimal value is probably between the number of physical and logical cores. But this optimal value will probably never be the same between different peoples...:(
larisk2
28th November 2020, 20:51
I have a video card from ATI, please advise some high-quality deinterlace filter / plugin for avisint. I tried different ones, but I didn't like the quality of the result.
jpsdr
29th November 2020, 11:20
Deinterlacing is not realy my stuff, so personnaly i can't realy advise (my use of nnedi3 is only nnedi3_rpow for upsampling). Even more if you're already tested the avisynth's classic ones (nnedi3, QTGMC, ... ... ... ... i realise if there is others i don't know them).
DTL
30th November 2020, 12:17
It looks like there is somewhere memory corruption bug or buffer overrun if processing too small sized buffers: https://forum.doom9.org/showthread.php?t=182108
If source image is about 1200x720 being down-sized to /10 = 120x72 and then upsized to 8..10x we got buggy blue pixels at the bottom and also non-stable corrupted pixels at bottom (at different runs the pattern of corrupted pixels may vary) and also the progam may crash with memory protection error (like illegal writing to...). Ofcourse processing so small buffers is not commom task but if programmer have time it is good to search the reason of the bug.
I remember there is an assert somewhere in resampler to refuse processing too small buffers with too large 'support' or taps number - may be bug is somewhere close like the limits of assert is too small and processing engine still runs out of the end of buffers and reads from memory with other data content and sometime attempts to write out of reserved pages boundary and finally cautch hardware memory protection error.
jpsdr
1st December 2020, 18:44
Is it only on ResampleMT, or also on standard resample ?
DTL
1st December 2020, 23:10
Changed resizers to 'standard' GaussResize and BilinearResize - the result is same buggy. So the bug is in the main Avisynth resample engine (used in ResampleMT too) ? I post bug description with simplest reproduction script to main Avisynth+ thread.
real.finder
2nd December 2020, 13:09
since SincLin2Resize and SinPowResizeMT was added, is they like NoHalo and LoHalo (https://graphicdesign.stackexchange.com/a/138061)?, if not can they be added? and seems there are others (LoBlur and LoJaggy)
edit: there are also JincResize maybe worth adding too
DTL
2nd December 2020, 23:02
"SincLin2Resize and SinPowResizeMT was added, is they like NoHalo and LoHalo?,"
No. They are small additions to 'linear' signal processing based on sinc and Nyquist theorem. SincLin2 is simply workaround for fixing computational bugs of SincResize with too few taps typically used. They just adds a bit step to complete tools for '1D' linear signals processing. For better 2D image processing it is required step to significally different '2D math' - like that EWA/Jinc and other.
" there are also JincResize maybe worth adding too"
JincResize is from completely different 'true-2D' resizers family. It is based on completely different resampling engine. And all ResampleMT resizers including SincLin2 and SinPow uses the one and the only resampler for V+H 1D+1D processing engine (resampler) taken from standard Avisynth. Just MT added. SincLin2 and SinPow are just very small kernel-generation functions added.
Also the only known here JincResize for Avisynth is unstable and buggy still and need more developer resources to be usable. So it is very hard to add them to ResampleMT with all MT functionality.
real.finder
3rd December 2020, 08:13
Also the only known here JincResize for Avisynth is unstable and buggy still and need more developer resources to be usable.
even this https://github.com/Asd-g/AviSynth-JincResize ?
DTL
3rd December 2020, 19:59
even this https://github.com/Asd-g/AviSynth-JincResize ?
This one looks more stable. I test 0.x versions and 1.x ported from VapourSynth looks more stable. Though it outputs significally different results with different 'tap' parameter. And only work with 'planar' formats. And it looks only useful for upsampling (and looks do not have corresponding 'true-2D' downsample function for production work like complentary pair SinPow(downsample)/Sinc(upsample) resizers).
May separate thread at forum exists for this plugin ?
You think it will significally gain up speed from internal multithreading ?
jpsdr
4th December 2020, 18:40
From what i've noticed, the more computation there is using data from a small source area (-> fitting in cache), the more you can gain with MT, and the more you can gain increasing the number of core.
DTL
4th December 2020, 20:26
For 1-pass Jinc-family resamplers I think the direct 2D convolution of 2D kernel with 2D lines-sampled image buffer may significally suffer from long-stride memory access and cache pollution of unused prefetch. So there may be different shemes of MT task assignment for different cores. May be even many threads processing different but neibour input sample steps of 1 input buffer area (not differend areas of input buffer nor different frames of input sequence) - so there will be less long stride memory reads. But the threads syncing may be harder and time losses on threads syncing may be significant too. The main idea is by some way perform sync of different threads processing neibour input samples - so the processed image buffer area will be cached once and available for many cores.
Like for 2 cores processing:
static void resize_plane_c(EWAPixelCoeff* coeff, const void* src_, void* VS_RESTRICT dst_,
int dst_width, int dst_height, int src_stride, int dst_stride, float peak)
{
EWAPixelCoeffMeta* meta = coeff->meta;
const T* srcp = reinterpret_cast<const T*>(src_);
T* VS_RESTRICT dstp = reinterpret_cast<T*>(dst_);
src_stride /= sizeof(T);
dst_stride /= sizeof(T);
for (int y = 0; y < dst_height; y++)
{
// threads sync start point
//core 1 process
for (int x = 0; x < dst_width; x+=2)
{
const T* src_ptr = srcp + meta->start_y * static_cast<int64_t>(src_stride) + meta->start_x;
const float* coeff_ptr = coeff->factor + meta->coeff_meta;
float result = 0.f;
for (int ly = 0; ly < coeff->filter_size; ly++)
{
for (int lx = 0; lx < coeff->filter_size; lx++)
{
result += src_ptr[lx] * coeff_ptr[lx];
}
coeff_ptr += coeff->coeff_stride;
src_ptr += src_stride;
}
if (!(std::is_same_v<T, float>))
dstp[x] = static_cast<T>(lrintf(clamp(result, 0.f, peak)));
else
dstp[x] = result;
meta+=2;
}
// core 2 process (very close with x-coord to core 1 - so both cores will share almost same src_ptr[lx] memory area)
for (int x = 1; x < dst_width; x+=2)
{
meta++;
const T* src_ptr = srcp + meta->start_y * static_cast<int64_t>(src_stride) + meta->start_x;
const float* coeff_ptr = coeff->factor + meta->coeff_meta;
float result = 0.f;
for (int ly = 0; ly < coeff->filter_size; ly++)
{
for (int lx = 0; lx < coeff->filter_size; lx++)
{
result += src_ptr[lx] * coeff_ptr[lx];
}
coeff_ptr += coeff->coeff_stride;
src_ptr += src_stride;
}
if (!(std::is_same_v<T, float>))
dstp[x] = static_cast<T>(lrintf(clamp(result, 0.f, peak)));
else
dstp[x] = result;
meta+=2;
}
//threads end
dstp += dst_stride;
}
}
We can start profiling to look if current resampler in jincresize cpu-limited or memory-limited.
For mathematics it looks so:
Standard built-it old fast resampler in Avisynth and many other resamplers looks performs 1Dx1D convolution twice. And 'true-2D' resampler performs 2Dx2D convolution once. But 2Dx2D requires more MUL+ADD operations so it significally slower.
jpsdr
5th December 2020, 09:46
If i do a MT version, it will be like all the others : splitting image horizontaly.
DTL
5th December 2020, 11:44
If the full source plane for process will fit CPU cache it may be better in compare with different_thread_per_different_frame (as may be with MT-avisynth works). If not - it will creates as many memory read streams as threads count and user will see significant speed drop if processing input plane size > CPU cache size.
It looks the whole point of ResampleMT multithreading in compare with Avisynth-level MT is to make thread's processing pieces closer to each other in memory addresses space. The closest possible is neibour-samples processing.
" splitting image horizontaly."
May be an idea - at time of threads planning make compare of plane size against CPU cache size. If plane size < CPU cache size the threads planner may simply split image to N-threads parts. If input plane size is > CPU cache size so at first split input plane into number of parts like plane size / cache size and assign N-threads processing for each part sequentally.
May be because it may be hard to determine CPU cache size via API make separate user-defined parameter like CPU_cache_size (or may be better MAX_BLOCK_SIZE_FOR_MT). Because of different memory managers at different CPUs may be the optimal MT block size may be significally < CPU cache size. So user may determine the optimal size using tests at his hardware.
If user set too small MT block size it will got performance penalty because of too frequent threads start/stop/re-assigning new piece of work. If splitting image buffer horizontally to each thread workunit is measured in processing rows. May be allow user to determine max_thread_rows count. If undefined - threads planner as now calculated each_thread_rows = height/num_threads (i suppose). If defined - threads planner limit each_thread_rows to max_thread_rows and after (all ?) intial threads finishes - start new threads to process the remaining rows (blocks of remaining rows). The waiting for _all_ initial threads finishes before starting threads processing new rows blocks may be required for keeping current cached data unchanged (because new rows blocks required new memory reads). So it is also may be user-defined parameter - wait_for_all_threads_finish=yes/no.
2Dx2D convolution require many reads of input samples (I think as many as kernel_size^2 times) so will definately benefits from cached reads and may perform uncached writes to memory because output samples are never required for processing again (in compare with Avisynth 1Dx1D processing twice for resize). So if possible the ASM 2Dx2D convolution subroutines may be modified to use non-cached hinted write instructions and may be look into WinAPI for caching properties of memory pages.
DTL
6th December 2020, 07:06
edit: there are also JincResize maybe worth adding too
The more 'strategic' ideas:
Actually the 'linear math' resizers consists of 3 discrete and interconnected parts:
kernel_base x weighting/windowing x resampler
Typical kernel_base are sinc,gauss,linear,cubic, etc. Jinc is also only kernel_base function defined as 1D f(x)=BesselJ1(x)/x. Sinc is equal to spherical BesslJ0(x) as i wee from wiki.
Typical weighting/windowing is 'non' that is 'rectangular' 1-based window limiting 'width/size' of kernel and many more like 1 lobe of Sinc, Jinc, linear, trapecoidal and any other function typically =1 at zero(start) and fading to =0 at its weighting/windowing end.
The most typical resampler is separated vertical + horizontal processing (1Dx1D twice convolution of weighted kernel with input source), that is fast and gives some acceptable quality with 2D image processing. There is also may be more suitable for 2D image processing resampler as direct of 'full' 2D convolution, but it require more CPU operations and typically not/rarely used because it was too slow on old CPUs and also not very great even on 2020 CPUs. It gives only 'a bit better' quality (may be +20..30% by my taste at some (extreme) tests) in compare with much more faster V+H processing. The main difference is that 2D-convolution resampler allow equally good process all angles spatial frequencies and V+H resampler only good process vertical and horizontal. Though on many real practical (usually and not very sharp) images the difference may be not greatly visible.
So typically 'named' 'linear math' resizers are just named some combination of kernel_base and weighting like:
Lanczos = sinc kernel weighted by sinc
Gauss = gauss kernel non-weighted (rect weighted and with good self-weighting properties)
Sinc = sinc non-weighted
SinPow = sort of 'self-weighted'
And typically processed by V+H resampler.
Jinc as in that pluging is looks jinc weighted by jinc and processed by 2D-convolution resampler. It is because Jinc mostly benefits of 2D-convolution resampler though can also be kernel for V+H resampler (and produce close results to sinc-family resizers I think, especially with small taps value).
So the 'linear' resizer library may use just 'one' resize function (like that in z.lib) and just defines all 3 components of resize like kernel + weighting + resampler as arguments. And also for user-friendly looking may provide named functions like typical Bilinear/Lancsos/etc. Because it is hard to make all possible combinations of 3-parts as named - so for advanced users the one_for_all parametrized function is shorter.
So currently to add Jinc to ResampleMT plugin the 2D-convolution resampler must be added as the most hard part and also some kernel functions like jinc as kernel base and jinc as weighting (may be jinc weighted by jinc for beginning as 1 func). The kernel+weighting is the simpliest part because todays C-programming uses standard math library for both sin(x) and bessel*(x).
As i see image-processing software (advanced enough/for 'geeks') already uses command-line syntax for providing manual-input of kernel_base and weighting functions to resampler - I see it in imagemagic forums.
It is good to have in ResamplerMT to have ability also perform user-defined function calls for required combination of kernel + resampler or even kernel_base + weighting + resampler. Because most kernel functions are good applicable for both V+H and 2D-convolution resamplers with may be small parameters tweaking. 1D kernel for 2D-convolution I think is usually radius/distance-argumented rotation of 1D kernel around center point. i.e. (kernel_2D(x,y) = kernel_1D(sqrt(x^2+y^2))).
DTL
14th December 2020, 10:16
even this https://github.com/Asd-g/AviSynth-JincResize ?
There is a sample build of this plugin with internal multithreading by OpenMP https://forum.doom9.org/showthread.php?p=1930687#post1930687 . It MT only main frames processing loop so start time of preparing large full-frame coeff array is the same. And uses full-auto threading without manual control.
From my test it actually uses a bit less multi-core CPU (about 90%) in compare with Avisynth+ MT (100% CPU) and runs a bit slower. So there is not great advance for speed if using newer MT Avisynths. But it uses only one large array of coeffs for all threads processing so require much less memory in compare with Avisynth's frame-based MT. I beleive somedays it will be rewritten for small full cacheable LUT-based additive convolution approach instead of full-frame coeffs array mul+add. At least for integer ratio of scaling. So the large memory requirement for each frame-processing thread will be removed too.
real.finder
14th December 2020, 10:52
There is a sample build of this plugin with internal multithreading by OpenMP https://forum.doom9.org/showthread.php?p=1930687#post1930687 . It MT only main frames processing loop so start time of preparing large full-frame coeff array is the same. And uses full-auto threading without manual control.
From my test it actually uses a bit less multi-core CPU (about 90%) in compare with Avisynth+ MT (100% CPU) and runs a bit slower. So there is not great advance for speed if using newer MT Avisynths. But it uses only one large array of coeffs for all threads processing so require much less memory in compare with Avisynth's frame-based MT. I beleive somedays it will be rewritten for small full cacheable LUT-based additive convolution approach instead of full-frame coeffs array mul+add. At least for integer ratio of scaling. So the large memory requirement for each frame-processing thread will be removed too.
maybe jpsdr can make it MT in another way like by frame division "not just splitting image horizontaly" base on resize samples and taps with threads?
jpsdr
14th December 2020, 20:56
I don't know if i'll be working on this... For now, i've put an alt to coding in my spare time for others personnal projects.
Isn't "splitting image horizontaly" a "frame division" ?
real.finder
14th December 2020, 23:11
I don't know if i'll be working on this... For now, i've put an alt to coding in my spare time for others personnal projects.
Isn't "splitting image horizontaly" a "frame division" ?
it is, but I was mean as blocks, don't know if splitting image horizontaly will work with 2D resizes
jpsdr
15th December 2020, 19:44
While there is no feed back (you need some previous results to compute next result), you can divide however you want and do things in whatever order you want. Of course doing in a total random order will not be the most efficient/faster way. But I see no reasons why splitting horizontaly shouldn't work.
BTW, i meant "i've put an halt"...
jpsdr
21st February 2021, 17:58
New version, see first post.
DTL
23rd February 2021, 10:00
it is, but I was mean as blocks, don't know if splitting image horizontaly will work with 2D resizes
As my current progress shows for real (possibly future main) multicores CPUs like 5..10+ cores and current slow progress with memory speed (also even SRAM cache L4..L3..L2) it is required to split task to much smaller blocks in compare with just horizontal stripes.
Splitting horizontaly is currently implemented even with small per-thread temp buf processing but it introduce some overhead in processing for correct align of edges of stripes.
Because the only cache that can feed FMA units at acceptable speed is L1. And because for 2D it is required to have in temp buf the number of rows and columns like taps*mul_ratio*2 it is not possible to fit to L1d even the minimum full rows required for process even FullHD.
Current versions of upsampler uses up to 50% of FMA CPU performance with 4 cores/threads but almost zero scaled in performance when executed on 10..20 cores CPUs.
So I think in the future try to use re-arrangement in memory the scan order of frame buf to significaly shorter lines/rows so several rows may fit in half of L1d cache.
Like 8K frame of 7680 samples per full scanline may be scanned to 10 of 768 samples per line vertical stripes. So each 10 sub-rows of stripe in float32 may fit in L1d cache. And processing core can have access to all required samples in vertical direction from L1d instead of about twice slower L2/L3.
This approach may completely ruine the simple auto-multithreading usind OpenMP and require to write own threads manager because the frame will be divided on a large enough number of workunits - much more in compare with available cores per execution.
Each small step to higher performance significally increases of complexity of program and also changing the scan order of frames in memory raises the global question to Avisynth core design: If the future of current computing hardware is only large number of multicoring with still slow memory it may be better to introduce new memory layout formats in addition to simple 'planar' - like 'multi-blocks' instead of simple full line scans. Or the each plugin will need to spend resources for pre and post re-arrangement in memory for currenlty used full frame line scans. But this require core and plugins to be re-written for support new scan formats.
FranceBB
23rd February 2021, 16:19
Thanks for the new version! Downloading right now! :D
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.