Log in

View Full Version : what's so scary about writing a C++ plugin?


feisty2
8th July 2021, 11:19
it is simply beyond my grasp why people would rather have nonsense like this (http://forum.doom9.net/showthread.php?p=1947045#post1947045):

# mode name prone to change (suggestions welcome :P )
mode == "undot2" ? "x[-1,1] A^ x[0,1] B^ x[1,1] C^ x[-1,0] D^ x[1,0] E^ x[-1,-1] F^ x[0,-1] G^ x[1,-1] H^ " \
+"A C min AA^ A C max CC^ " \
+"B D min BB^ B D max DD^ " \
+"E G min EE^ E G max GG^ " \
+"F H min FF^ F H max HH^ " \
+"AA EE min A^ AA EE max E^ " \
+"BB FF min B^ BB FF max F^ " \
+"CC GG min C^ CC GG max G^ " \
+"DD HH min D^ DD HH max H^ " \
+"A B min AA^ A B max BB^ " \
+"C D min CC^ C D max DD^ " \
+"E F min EE^ E F max FF^ " \
+"G H min GG^ G H max HH^ " \
+"CC EE min C^ CC EE max E^ " \
+"DD FF min D^ DD FF max F^ " \
+"BB E min B^ BB E max EE^ " \
+"D GG min DD^ D GG max G^ " \
+"B C min BB^ B C max CC^ " \
+"DD EE min D^ DD EE max E^ " \
+"F G min FF^ F G max GG^ " \
+"x[0,0] BB GG clip" : \

over this

auto MedianKernel = [](auto Center) {
auto Samples = std::array{
Center[-1][-1], Center[-1][0], Center[-1][1],
Center[0][-1], Center[0][0], Center[0][1],
Center[1][-1], Center[1][0], Center[1][1]
};
std::nth_element(Samples.begin(), Samples.begin() + 4, Samples.end());
return Samples[4];
};

just to avoid C++.

where does this irrational fear of C++ come from?

wswartzendruber
8th July 2021, 18:13
Can whatever that is be written in Rust instead?

let median_kernel = |center| -> {
let mut samples = [
center(-1, -1), center(-1, 0), center(-1, 1),
center( 0, -1), center( 0, 0), center( 0, 1),
center( 1, -1), center( 1, 0), center( 1, 1),
];
samples.partition_by_kth(4)
samples[4]
};
:cool:

I'll go run and hide now. :D

feisty2
8th July 2021, 19:42
rust has very poor metaprogramming capabilities compared to C++, it lacks various advanced type systems, higher kinded types, dependent types, impredicative types (rust does not even have higher ranked types or polymorphic lambdas) and its associated types (a form of type family) are kind of awkward compared to C++'s extremely powerful type inspection.

take a look at the example rust plugin (https://github.com/YaLTeR/vapoursynth-rs/blob/master/sample-plugin/src/lib.rs#L71), see how verbose it is compared to the C++ implementation of the same thing:

struct Invert {
static constexpr auto Signature = "clip: vnode";
field(InputClip, VideoNode{});

Invert(auto Arguments) {
InputClip = Arguments["clip"];
if (!InputClip.WithConstantFormat() || !InputClip.WithConstantDimensions() || InputClip.BitsPerSample > 16)
throw std::runtime_error{ "only 8 - 16bit clips with constant format and dimensions supported." };
}
auto SpecifyMetadata() {
return InputClip.ExtractMetadata();
}
auto GenerateFrame(auto Index, auto GeneratorContext, auto Core) {
auto DrawInvertedFrame = [&](auto&& InputFrame) {
auto ProcessedFrame = Core.CreateBlankFrameFrom(InputFrame);
for (auto c : Range{ InputFrame.PlaneCount })
for (auto y : Range{ InputFrame[c].Height })
for (auto x : Range{ InputFrame[c].Width })
ProcessedFrame[c][y][x] = (1 << InputFrame.BitsPerSample) - InputFrame[c][y][x] - 1;
return ProcessedFrame.Transfer();
};
if (InputClip.BitsPerSample > 8)
return DrawInvertedFrame(InputClip.AcquireFrame<const std::uint16_t>(Index, GeneratorContext));
else
return DrawInvertedFrame(InputClip.AcquireFrame<const std::uint8_t>(Index, GeneratorContext));
}
};


if you truly want a C++ replacement for writing avs/vs plugins, I would suggest D or Nim.

wswartzendruber
8th July 2021, 19:57
Relax. I'm just giving you a hard time.

feisty2
8th July 2021, 20:09
oh, I'm just offering you free education. so next time you try to be witty, the joke wouldn't be on you ;)

wswartzendruber
8th July 2021, 20:26
The joke, you say? Here are two jokes:

Error: segmentation fault
Error: use after free

feisty2
8th July 2021, 20:30
I got one for you:

unsafe

wswartzendruber
8th July 2021, 20:31
...which is why you won't find it in any of my work.

wonkey_monkey
8th July 2021, 20:36
It's simply beyond my grasp why you'd start this thread instead of leaving someone to do their own thing in peace after you've already given them your advice and they've politely declined.

As for your suggestion:

auto MedianKernel = [](auto Center) {
^~~~
main.cpp: In lambda function:
main.cpp:10:20: error: ‘array’ is not a member of ‘std’
auto Samples = std::array{
^~~
main.cpp:15:5: error: ‘nth_element’ is not a member of ‘std’
std::nth_element(Samples.begin(), Samples.begin() + 4, Samples.end());
^~~

Well that didn't work very well.

And even if you add the rest of the boilerplate code that you omitted, it still wouldn't make an Avisynth plugin, which seems to be the currently favoured environment of Dogway, who you seem hell-bent on belittling to the extent of creating an entire thread just to pour scorn on his work. You've already given him your advice; why spawn a whole new thread just because he's chosen, for the time being at least, not to follow it?

(And even if you made it an Avisynth plugin, it wouldn't actually do what that Expr expression does)

feisty2
8th July 2021, 20:50
memory errors are rare in modern C++ codebases. C++ today sort of took the blame for many old projects written primarily in C or C++98 where smart pointers didn't exist.
anyways, I have no interest in going further with this memory safety thing because in the context of avs/vs plugins, the frameserver does the heavy lifting of multithreading and other error prone things. it is unlikely the kind of code that could potentially lead to memory corruption would appear in an avs/vs plugin, whether it's written in C++ or rust.

the extra expressiveness that C++ has over rust, however, makes a real difference in this scenario.

feisty2
8th July 2021, 20:58
As for your suggestion:

auto MedianKernel = [](auto Center) {
^~~~
main.cpp: In lambda function:
main.cpp:10:20: error: ‘array’ is not a member of ‘std’
auto Samples = std::array{
^~~
main.cpp:15:5: error: ‘nth_element’ is not a member of ‘std’
std::nth_element(Samples.begin(), Samples.begin() + 4, Samples.end());
^~~

Well that didn't work very well.



update your compiler and compile with the C++20 standard or #include the missing headers.

feisty2
8th July 2021, 21:21
who you seem hell-bent on belittling to the extent of creating an entire thread just to pour scorn on his work. You've already given him your advice; why spawn a whole new thread just because he's chosen, for the time being at least, not to follow it?

I bear no hostility towards his work. I am genuinely curious why people would rather make cryptic RPN expressions that are almost as hard to decipher as the asm than write simpler and clearer C++ code. what's stopping them from writing a proper C++ plugin? the requirement of a compiler? the C++ language? something else?

feisty2
8th July 2021, 21:27
(And even if you made it an Avisynth plugin, it wouldn't actually do what that Expr expression does)


fine.

auto RemoveGrainMode4 = [](auto Center) {
auto Samples = std::array{
Center[-1][-1], Center[-1][0], Center[-1][1],
Center[0][-1], Center[0][0], Center[0][1],
Center[1][-1], Center[1][0], Center[1][1]
};
std::sort(Samples.begin(), Samples.end());
return std::clamp(Center[0][0], Samples[3], Samples[5]);
};

feisty2
8th July 2021, 21:52
And even if you add the rest of the boilerplate code that you omitted, it still wouldn't make an Avisynth plugin

for operations that do not change the size or the format of the input clip. you can make an adhoc filter skeleton that takes a callable object, you can absolutely do this for avisynth. you might end up with something like this:


auto RG4 = FilterTemplates::Eval([](auto Center) {
auto Samples = std::array{
Center[-1][-1], Center[-1][0], Center[-1][1],
Center[0][-1], Center[0][0], Center[0][1],
Center[1][-1], Center[1][0], Center[1][1]
};
std::sort(Samples.begin(), Samples.end());
return std::clamp(Center[0][0], Samples[3], Samples[5]);
});

RegisterFunction(RG4);

FranceBB
9th July 2021, 16:43
I bear no hostility towards his work. I am genuinely curious [...] what's stopping them from writing a proper C++ plugin? the requirement of a compiler? the C++ language?

The fact that they're used to the Avisynth syntax. It's what they deal with everyday and writing a plugin isn't really that much different from writing a "normal" Avisynth Script in everyone's mind. I think that whoever writes an Avisynth Function is an encoder in the first place who has been encoding videos etc all the time using this syntax.

I'm gonna put you in front of this scenario (and keep in mind that it's different from the one of the specific user you were talking about, but it applies to the more general Doom9 population): you're a normal user, you've just approached the frameserver world and you pick Avisynth 'cause it's the oldest yet still maintained one. Bit by bit you switch from using a silly GUI to writing scripts yourself with AVSPmod as IDE and "compiling" with it to see the results before launching a BAT to encode. Years pass, you get more and more familiar with it, you grab plugins yourself from other people, you read documentations, you even help reporting bugs and contribute to the community. Then, one day, there's something you need to do and you google the solution. You look everywhere: Doom9, the Avisynth Wiki, Videohelp, nothing, you can't find any plugin that does what you want, so you try to write something yourself in the script you want to encode and you succeed. Eventually, you don't want to copy-paste the same code at every encode, so you decide to write a function to call every time: congratulations you've just made your first .avsi (Avisynth Plugin). And once you've done that, you keep doing it, over and over again every time you need something and you get better and better 'till you end up writing all your functions/plugins as Avisynth Plugins in the pseudo-C++ Avisynth internal scripting language.

feisty2
9th July 2021, 18:29
Eventually, you don't want to copy-paste the same code at every encode, so you decide to write a function to call every time: congratulations you've just made your first .avsi (Avisynth Plugin). And once you've done that, you keep doing it, over and over again every time you need something and you get better and better 'till you end up writing all your functions/plugins as Avisynth Plugins in the pseudo-C++ Avisynth internal scripting language.

I believe you and I are talking about different things. an avsi or py file, no matter how complex it is, can be boiled down to a call graph. It has no direct access to the pixels of a video frame (in general). you may apply some filtering to a plane and that's about the finest level of control it can achieve directly.

a C++ plugin is a whole 'nother story, it has direct access to the pixels and it can describe any filtering process.

and that's exactly my point, what's stopping them from writing a proper C++ plugin when they want pixel-level manipulation?

wonkey_monkey
9th July 2021, 19:46
Someone could write for Expr yet not know the first thing about C++ and/or the Avisynth SDK. Even knowing C++, an "adhoc filter skeleton" would hardly be the breeze you make it out to be.

It's disingenous to offer up 10 lines of C++ as a replacement for 20 lines of Expr yet neglect to include the other 100 or so lines that still need to be wrapped around it. That's like teaching someone to draw an owl by saying "Draw two circles for eyes... then the rest of the owl."

What if someone just wanted to add the pixels of two clips together (pretend Overlay doesn't exist - Expr is faster anyway). Would Expr(clip1, clip2, "x y +") be reasonble then, or would you still call them irrational for not wanting to write a C++ plugin?

That aside, why was a simple "I don't want to" not a good enough answer in the first place?

feisty2
9th July 2021, 20:02
Someone could write for Expr yet not know the first thing about C++ and/or the Avisynth SDK. Even knowing C++, an "adhoc filter skeleton" would hardly be the breeze you make it out to be.

It's disingenous to offer up 10 lines of C++ as a replacement for 20 lines of Expr yet neglect to include the other 100 or so lines that still need to be wrapped around it. That's like teaching someone to draw an owl by saying "Draw two circles for eyes... then the rest of the owl."



where's the 100 or so lines? the complete code of gaussblur is less than 40 lines, and can be further reduced if you don't wanna bother checking the validity of the input. a skeleton template that completely eliminates any boilerplate for Expr-like filters is absolutely doable in C++. it seems to me that you don't know anything at all about the abstraction power of modern C++ and yet, you hold such strong opinions about things you don't know.

feisty2
9th July 2021, 20:12
What if someone just wanted to add the pixels of two clips together (pretend Overlay doesn't exist - Expr is faster anyway). Would Expr(clip1, clip2, "x y +") be reasonble then, or would you still call them irrational for not wanting to write a C++ plugin?

That aside, why was a simple "I don't want to" not a good enough answer in the first place?

I've said it before, I'll say it again. I am myself a frequent user of Expr and I never said that people shouldn't use Expr in general.

Expr works perfectly fine for expression evaluation but I think any sane person would agree that

"x[-1,1] A^ x[0,1] B^ x[1,1] C^ x[-1,0] D^ x[1,0] E^ x[-1,-1] F^ x[0,-1] G^ x[1,-1] H^ " \
+"A C min AA^ A C max CC^ " \
+"B D min BB^ B D max DD^ " \
+"E G min EE^ E G max GG^ " \
+"F H min FF^ F H max HH^ " \
+"AA EE min A^ AA EE max E^ " \
+"BB FF min B^ BB FF max F^ " \
+"CC GG min C^ CC GG max G^ " \
+"DD HH min D^ DD HH max H^ " \
+"A B min AA^ A B max BB^ " \
+"C D min CC^ C D max DD^ " \
+"E F min EE^ E F max FF^ " \
+"G H min GG^ G H max HH^ " \
+"CC EE min C^ CC EE max E^ " \
+"DD FF min D^ DD FF max F^ " \
+"BB E min B^ BB E max EE^ " \
+"D GG min DD^ D GG max G^ " \
+"B C min BB^ B C max CC^ " \
+"DD EE min D^ DD EE max E^ " \
+"F G min FF^ F G max GG^ " \
+"x[0,0] BB GG clip"

is pure insanity compared to

auto RemoveGrainMode4 = [](auto Center) {
auto Samples = std::array{
Center[-1][-1], Center[-1][0], Center[-1][1],
Center[0][-1], Center[0][0], Center[0][1],
Center[1][-1], Center[1][0], Center[1][1]
};
std::sort(Samples.begin(), Samples.end());
return std::clamp(Center[0][0], Samples[3], Samples[5]);
};

FranceBB
9th July 2021, 20:40
and that's exactly my point, what's stopping them from writing a proper C++ plugin when they want pixel-level manipulation?

We're back to my point actually: they've approached programming starting with Avisynth and its syntax and got proficient with it, they didn't study C++, so it's easier for them to write an Avisynth Script and use things like Expr() than learning C++ from scratch.

A little throwback to what you wrote a while ago about Expr:

now you can write some plugins like removegrain kinda stuff with this, in a script, if you just don't wanna waste ur time to learn the hardass c/cpp

So... it seems you already know why people do it eheheheh :P

Someone could write for Expr yet not know the first thing about C++ and/or the Avisynth SDK. Even knowing C++, an "adhoc filter skeleton" would hardly be the breeze you make it out to be.

Exactly. :)
Not everyone who is proficient in writing those expressions knows C++




Anyway, feisty, regardless of what people do and what they use, I'm glad that they're developing for this amazing frameserver. :)

Have a lovely weekend you all!
Good night! ;)

feisty2
9th July 2021, 20:50
So... it seems you already know why people do it eheheheh :P

that comment was from years ago when:
a) C++20 didn't exist, therefore C++ was less powerful and was significantly harder to write
b) a script-like high level C++ API didn't exist.

I'd be happy to write C++ plugins back then if I had C++20 and a high level API.

feisty2
9th July 2021, 21:04
We're back to my point actually: they've approached programming starting with Avisynth and its syntax and got proficient with it, they didn't study C++, so it's easier for them to write an Avisynth Script and use things like Expr() than learning C++ from scratch.

Not everyone who is proficient in writing those expressions knows C++


but they don't need to know everything about C++ in order to write some simple filters.
they only need to know some basic stuff, variables, functions, loops, conditionals, all of which they have learned from avisynth.

wonkey_monkey
9th July 2021, 21:08
You keep trying to compare two pieces of code which are not comparable. The Expr string works as it is; your 10 lines of code do not.

If you want to defend your assertion properly, you should provide the full code for the Avisynth plugin that wraps around your snippet - preferably one that supports all colourspaces and shows similar performance to Expr when implementing the same logic.

And then consider what it would take for someone who has only half, or a quarter, or even none (because Avisynth users range all across that spectrum) of your proficiency with C++ and Avisynth to do the same, and whether you really think it would be fair to call them "irrational" for using Expr instead.

I know perfectly well that it's doable. I never said it wasn't. But it's not doable by everyone.

feisty2
9th July 2021, 21:56
You keep trying to compare two pieces of code which are not comparable. The Expr string works as it is; your 10 lines of code do not.

If you want to defend your assertion properly, you should provide the full code for the Avisynth plugin that wraps around your snippet - preferably one that supports all colourspaces and shows similar performance to Expr when implementing the same logic.

And then consider what it would take for someone who has only half, or a quarter, or even none (because Avisynth users range all across that spectrum) of your proficiency with C++ and Avisynth to do the same, and whether you really think it would be fair to call them "irrational" for using Expr instead.

I know perfectly well that it's doable. I never said it wasn't. But it's not doable by everyone.

the user merely needs to have this "FilterTemplate.hxx" placed in the include path.

template<typename T>
struct Eval {
field(InputClip, VideoNode{});

public:
static auto SpecifySignature(auto&& FilterName) {
return FilterName + "(clip: vnode)"s;
}
static inline auto Kernel = T{};

public:
Eval(auto Arguments) {
InputClip = Arguments["clip"];
if (!InputClip.WithConstantFormat() || !InputClip.WithConstantDimensions())
throw std::runtime_error{ "only clips with constant format and dimensions supported." };
}
auto SpecifyMetadata() {
return InputClip.ExtractMetadata();
}
auto GenerateFrame(auto Index, auto GeneratorContext, auto Core) {
auto ApplyKernel = [&](auto&& InputFrame) {
auto ProcessedFrame = Core.CreateBlankFrameFrom(InputFrame);
for (auto c : Range{ InputFrame.PlaneCount })
for (auto y : Range{ InputFrame[c].Height })
for (auto x : Range{ InputFrame[c].Width })
ProcessedFrame[c][y][x] = Kernel(InputFrame[c].View(y, x));
return ProcessedFrame.Transfer();
};
if (InputClip.IsSinglePrecision())
return ApplyKernel(InputClip.AcquireFrame<const float>(Index, GeneratorContext));
else if (InputClip.BitsPerSample > 8)
return ApplyKernel(InputClip.AcquireFrame<const std::uint16_t>(Index, GeneratorContext));
else
return ApplyKernel(InputClip.AcquireFrame<const std::uint8_t>(Index, GeneratorContext));
}
};

auto RegisterAbbreviatedFilter(auto&& FilterName, auto&& Kernel) {
using FilterType = Eval<std::decay_t<decltype(Kernel)>>;
FilterType::Kernel = std::forward<decltype(Kernel)>(Kernel);
RegisterFilter<FilterType>(FilterName);
}


and then this is every line of code that the user needs to write to create 3 filters.

#include <FilterTemplate.hxx>

auto Main() {
auto Descriptor = PluginInfo{
.Namespace = "test",
.Identifier = "com.dont.care",
.Description = "whatever"
};
SpecifyConfigurations(Descriptor);

RegisterAbbreviatedFilter("GaussBlur", [](auto Center) {
auto WeightedSum = Center[-1][-1] + Center[-1][0] * 2 + Center[-1][1] +
Center[0][-1] * 2 + Center[0][0] * 4 + Center[0][1] * 2 +
Center[1][-1] + Center[1][0] * 2 + Center[1][1];
return WeightedSum / 16;
});

RegisterAbbreviatedFilter("Median", [](auto Center) {
auto Samples = std::array{
Center[-1][-1], Center[-1][0], Center[-1][1],
Center[0][-1], Center[0][0], Center[0][1],
Center[1][-1], Center[1][0], Center[1][1]
};
std::nth_element(Samples.begin(), Samples.begin() + 4, Samples.end());
return Samples[4];
});

RegisterAbbreviatedFilter("RemoveGrainMode4", [](auto Center) {
auto Samples = std::array{
Center[-1][-1], Center[-1][0], Center[-1][1],
Center[0][-1], Center[0][0], Center[0][1],
Center[1][-1], Center[1][0], Center[1][1]
};
std::sort(Samples.begin(), Samples.end());
return std::clamp(Center[0][0], Samples[3], Samples[5]);
});
}

InstantiatePluginFrom(Main);

wonkey_monkey
9th July 2021, 22:09
You seem to keep overlooking every mention of the word "Avisynth."

Regardless, show both approaches to someone with no experience of Expr/RPN or C++ and you'd have a much easier time explaining the Expr string to them, and they'd have a much easier time modifying it.

feisty2
9th July 2021, 22:15
Regardless, show both approaches to someone with no experience of Expr/RPN or C++ and you'd have a much easier time explaining the Expr string to them, and they'd have a much easier time modifying it.

lol, you call this

"x[-1,1] A^ x[0,1] B^ x[1,1] C^ x[-1,0] D^ x[1,0] E^ x[-1,-1] F^ x[0,-1] G^ x[1,-1] H^ " \
+"A C min AA^ A C max CC^ " \
+"B D min BB^ B D max DD^ " \
+"E G min EE^ E G max GG^ " \
+"F H min FF^ F H max HH^ " \
+"AA EE min A^ AA EE max E^ " \
+"BB FF min B^ BB FF max F^ " \
+"CC GG min C^ CC GG max G^ " \
+"DD HH min D^ DD HH max H^ " \
+"A B min AA^ A B max BB^ " \
+"C D min CC^ C D max DD^ " \
+"E F min EE^ E F max FF^ " \
+"G H min GG^ G H max HH^ " \
+"CC EE min C^ CC EE max E^ " \
+"DD FF min D^ DD FF max F^ " \
+"BB E min B^ BB E max EE^ " \
+"D GG min DD^ D GG max G^ " \
+"B C min BB^ B C max CC^ " \
+"DD EE min D^ DD EE max E^ " \
+"F G min FF^ F G max GG^ " \
+"x[0,0] BB GG clip"

"much easier time to explain" and "easier time to modify"?

is this again a joke? are you listening to yourself?

feisty2
9th July 2021, 22:28
You seem to keep overlooking every mention of the word "Avisynth."


the fact that this could be done for vaporsynth means the exact same could be done for avisynth, as long as someone's willing to write the same abstraction layer for avisynth. I don't know why you keep focusing on this irrelevant detail, possibly to cover up your faulty logic?

Dogway
10th July 2021, 01:41
@feisty2: You could have simply asked me. MSVC size is over half the size of my SSD partition. GCC, is that as fast on Intel CPU's? As I said I know some scripting languages, AVS, AHK, Python, a bit of GLSL, BATCH and regex. The problem with C++ or other compiler languages is they are too verbose and force you to focus on things you are not interested in. I don't want to care about parallelization, adapt code to an instruction set, OS, etc etc. I just want to get the work done, and by seeing that ex_boxblur() is virtually the same speed as removegrain(12) I rhetorically wonder, what's the benefit of a plugin? You shouldn't demerit Expr(), it's very powerful and promotes liquid code (easy to test, debug, port, mod). Anyone is free to port any of my functions to a plugin, specially those that don't have a counterpart.

About that sorting network block you quoted like 4 times already, do you want me to tabulate it? Or maybe merge them to just 5 lines? Even C++ uses one of the many sorting algorithms existent (https://en.wikipedia.org/wiki/Sorting_algorithm), which ultimately reduces to a bunch of min, max (or ternaries), but you don't see them when using a sorting function/abstraction-layer (to avoid these kind of panics).

feisty2
10th July 2021, 04:55
You could have simply asked me. MSVC size is over half the size of my SSD partition. GCC, is that as fast on Intel CPU's?

I just checked the MSVC installation folder on my computer, MSVC with only C++ components is about 3.3GB.
what do you mean by "fast"? the execution speed of the generated executable? GCC often generates faster code than MSVC.

feisty2
10th July 2021, 05:03
As I said I know some scripting languages, AVS, AHK, Python, a bit of GLSL, BATCH and regex. The problem with C++ or other compiler languages is they are too verbose and force you to focus on things you are not interested in.

like I said before, C++20 is a scripting language if you will it to, the core language is not any more verbose than python.
have you seen the code at #24, that's how concise C++ can get in terms of writing small plugins.

feisty2
10th July 2021, 05:34
I don't want to care about parallelization, adapt code to an instruction set, OS, etc etc. I just want to get the work done, and by seeing that ex_boxblur() is virtually the same speed as removegrain(12) I rhetorically wonder, what's the benefit of a plugin?

you don't need to care about any of those things if you don't want to. I think you probably got the wrong idea from the code of many existing plugins. these plugins are the way they are because:
a) they were manually optimized for best possible performance on every platform, you don't need to think about "parallelization, adapt code to an instruction set, OS, etc" if you don't need that. the compiler automatically makes the best possible decisions for your target, which is by default the architecture of your own machine.
b) they were written without the help of a high level API, so you see a lot of "irrelevant" stuff going round and round in their code. this shouldn't be a problem if you have a high level API, I made one for vaporsynth, you can request someone to write something similar for avisynth.
c) they were written in C or older versions of C++.

the benefit is that you enjoy the expressive power of a real programming language, so hopefully things become much easier to write and to read. I don't wanna post that giant block of Expr code again so you get the idea.

feisty2
10th July 2021, 05:48
You shouldn't demerit Expr(), it's very powerful and promotes liquid code (easy to test, debug, port, mod). Anyone is free to port any of my functions to a plugin, specially those that don't have a counterpart.

like I have said many times, I am myself a frequent use of Expr, and I have no reason to demerit Expr. but there's a limit of what it can do gracefully.
you should switch to a real programming language if you're going beyond that limit, rather than turn Expr into a frankenstein

ask yourself, do you honestly think that RemoveGrainMode4 is something that Expr can do gracefully?

feisty2
10th July 2021, 06:14
About that sorting network block you quoted like 4 times already, do you want me to tabulate it? Or maybe merge them to just 5 lines? Even C++ uses one of the many sorting algorithms existent, which ultimately reduces to a bunch of min, max (or ternaries), but you don't see them when using a sorting function/abstraction-layer (to avoid these kind of panics).

that's exactly my point, a real programming language has enough expressive power to free you from being distracted by irrelevant details, so in C++ you just call std::sort to do the work for you. whereas in Expr you're cursed to write the sort function yourself in the most inefficient way (the most efficient sorting algorithm in general is quicksort, and it requires recursion, good luck with implementing recursion in Expr).

Dogway
11th July 2021, 00:39
b) they were written without the help of a high level API, so you see a lot of "irrelevant" stuff going round and round in their code. this shouldn't be a problem if you have a high level API, I made one for vaporsynth, you can request someone to write something similar for avisynth.

Ok, so that's the other untold half of the story, now I need a high level API that doesn't exist. And I have nothing against C++, the contrary, if it was that easy as you make it to be I would be the first to jump in.

ask yourself, do you honestly think that RemoveGrainMode4 is something that Expr can do gracefully?

Given how MedianBlur performs (https://forum.doom9.org/showthread.php?p=1947045#post1947045)I'd say, yes. And we have no doubts about pinterf, if C++ was that easy I wonder why MedianBlur barely scratches the performance of 1% of removegrain(4)

Also to end this, I already said that ex_median is not supposed to replace removegrain by any means (among other, SSSE3 vs AVX2), but I still wanted to add the algos for completion of the library. This is also a personal project to learn myself. One benefit of this is the liquidity of Expr that I talked before. By seeing the naked algos I (or anyone) can merge ex_binarize with ex_expand and gain a whooping 20% of performance (https://forum.doom9.org/showthread.php?p=1943156#post1943156) (compared to mt_binarize+mt_expand) in LSFmod. That's not practical to do by compiling a specific plugin for the case.

feisty2
11th July 2021, 07:22
Given how MedianBlur performs I'd say, yes. And we have no doubts about pinterf, if C++ was that easy I wonder why MedianBlur barely scratches the performance of 1% of removegrain(4)

I haven't used avisynth for a very long time so I have no comment on the performance of avisynth plugins.
the question was that, does Expr have enough expressive power to elegantly describe the core logic of removegrain(4)?
if your answer to that question is yes, I think that huge block of assembly code looking RPN expression is elegant, then I have no words.


One benefit of this is the liquidity of Expr that I talked before.

there's nothing "liquid" when your code becomes incomprehensible. people cannot debug/modify or sometimes even test code they don't understand.
anyone, even those who know nothing about C++ or programming in general, can instantly grasp what removegrain(4) does by looking at the C++ code

auto RemoveGrainMode4 = [](auto Center) {
auto Samples = std::array{
Center[-1][-1], Center[-1][0], Center[-1][1],
Center[0][-1], Center[0][0], Center[0][1],
Center[1][-1], Center[1][0], Center[1][1]
};
std::sort(Samples.begin(), Samples.end());
return std::clamp(Center[0][0], Samples[3], Samples[5]);
};

I highly doubt that you could say the same for your RPN implementation of removegrain(4).

if something as simple as removegrain(4) already requires so much effort to describe in Expr, I don't see how you can make any non-trivial operations "liquid" with Expr.

feisty2
11th July 2021, 08:23
if you want the ability to generate machine code on the fly for whatever reason, there're other viable options:

a) embed C++ code in your script and compile the embedded code on the fly, someone did this for vaporsynth (https://github.com/Endilll/exprcpp)
b) completely get rid of Expr and extend the avisynth language with the ability to manipulate pixels, vaporsynth is actually capable of doing this, but this functionality is rarely used in vaporsynth because pixel-level manipulation can be extremely slow in python

I think option b is far superior than the current Expr frankenstein. the avisynth language has many constructs of a real programming language, variables, arrays, functions, loops, conditionals, it definitely qualifies for writing simple plugins.

lvqcl
11th July 2021, 11:40
have you seen the code at #24
Ugly.

feisty2
11th July 2021, 11:56
Ugly.

Poor kid, are you that desperate for attention? k.

wswartzendruber
12th July 2021, 01:54
Well your user name checks out.

feisty2
12th July 2021, 03:23
Well your user name checks out.

Don’t you have things other than trolling online to do in Idaho, like growing potatoes?

wswartzendruber
12th July 2021, 04:32
So does your location.

feisty2
12th July 2021, 04:42
lol no you