codester Posted October 21, 2008 Share Posted October 21, 2008 Hello community! If I understood this in the right way, Paint.NET calls the render method of an effect plugin several times to allow a multithreaded rendering. I've created an effect plugin where multithreaded rendering is quite useless because the parts of the image have to be rendered in a predefined order, that means the simultaneous rendering of two parts could cause bad results. I'd like to ask if it's possible to prevent multiple calls of my render function. Quote Link to comment Share on other sites More sharing options...
becauseiwantedto Posted October 21, 2008 Share Posted October 21, 2008 From what I understand in your post, you should simply tell people on the topic you post for the plugin that they should not Ctrl+F it, or multithread render it. Quote Changed the text in the signature yay! PDN gallery! Link to comment Share on other sites More sharing options...
Rick Brewster Posted October 22, 2008 Share Posted October 22, 2008 No, simply pass the appropriate EffectFlags to the base constructor, "EffectFlags.SingleThreaded". This will not necessarily give you control over the ordering of calls to Render(). Keep in mind that your effect will not necessarily be rendering against a square region-of-interest, either, as it is clipped to whatever arbitrary selection the user has crafted. Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
codester Posted October 22, 2008 Author Share Posted October 22, 2008 Thank you, works great. Quote Link to comment Share on other sites More sharing options...
codester Posted October 25, 2008 Author Share Posted October 25, 2008 Unfortunately there's still a problem I didn't remark at first... PDN still calls the render function of my plugin for several different rectangles of interest. I actually wanted it to call the render function only once so I can draw the whole image. Is that possible? Quote Link to comment Share on other sites More sharing options...
Rick Brewster Posted October 25, 2008 Share Posted October 25, 2008 Nope, not possible. Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
pyrochild Posted October 27, 2008 Share Posted October 27, 2008 Rick will bite me for telling you this, as it's not exactly how plugins are supposed to work, but anything that has to process on the entire image before anything else can be processed can be done in the OnSetRenderInfo method. Anything that can be done in an arbitrary order (once that function has finished) should be put in Render. This is how ScriptLab works, because there is simply no other way to do it. To avoid the Wrath of Rick, however, it may be worth it to just rethink the way your plugin does what it does. Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
pyrochild Posted October 27, 2008 Share Posted October 27, 2008 From what I understand in your post, you should simply tell people on the topic you post for the plugin that they should not Ctrl+F it, or multithread render it. Ctrl+F has nothing to do with multi-threaded rendering. All it does is tell Paint.NET, "hey, you know that thing I just did? Do it again." Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
aphillips Posted March 13, 2009 Share Posted March 13, 2009 pyrochild said: > ... anything that has to process on the entire image before anything else can be processed can be done in the OnSetRenderInfo method This is also what I was trying to do. That is, I have a large amount of initialization code which would make rendering the effect very slow if it was performed every time Render was called. I did not know about OnSetRenderInfo, so what I did was this: private bool firstCall = true; public override void Render(EffectConfigToken parameters, ...) { lock(this) { if (firstCall) { // Do time-consuming init here using srcArgs .... firstCall = false; } } for (int i = startIndex; i < startIndex + length; ++i) // render to current rect(s) } Note that this assumes that PDN itself does not lock have a lock on the effect instance at the time, which is a pretty safe bet (but Rick can confirm this). If this turns out to be a problem you can use a private member object to lock instead. The above will work even if you have not specified the EffectFlags.SingleThreaded flag in the ctor, since the lock means that the initialization is only performed once even if other threads are also executing the Render method. I have looked at the source code for a few effects and I have noticed 2 common problems: ** they specify EffectFlags.SingleThreaded when they do not need to ** they repeat a lot of initialization code each time Render is called which can be done once Back to the original question: codester said: > ... parts of the image have to be rendered in a predefined order ... I don't think turning off multithreaded rendering will help you. Even if you set the EffectFlags.SingleThreaded flag it is still not defined which order the rects are passed to consecutive calls to Render. All EffectFlags.SingleThreaded does is ensure that multiple Renders are not running at the same time (ie in different threads). I think what you really need to do is organise your code so that most of your code is done as above in an "init" block. Then render different parts appropriately in the specific calls to Render. You can always do this even if you have to create a temp surface in the "init" code, and then just copy the appropriate pixels (as spec'ed by rois, startIndex, length). Quote Link to comment Share on other sites More sharing options...
becauseiwantedto Posted March 15, 2009 Share Posted March 15, 2009 From what I understand in your post, you should simply tell people on the topic you post for the plugin that they should not Ctrl+F it, or multithread render it. Ctrl+F has nothing to do with multi-threaded rendering. All it does is tell Paint.NET, "hey, you know that thing I just did? Do it again." I realized that, yeah I misunderstood the English. As soon as he reposted and Rick posted below him, I understood that. His wording was a little confusing. Quote Changed the text in the signature yay! PDN gallery! Link to comment Share on other sites More sharing options...
Enormator Posted April 25, 2009 Share Posted April 25, 2009 I have the same problem but I'm using Codelab. For this plugin I want to first calculate the middle color and then start processing on the image in a multithreaded way with all threads using the precalculated color. (The middle color should be the arithmetic middle of all pixels) Do I have a chance? Quote :Link: website Link to comment Share on other sites More sharing options...
Simon Brown Posted April 25, 2009 Share Posted April 25, 2009 As far as I know you can still read all colours whatever part of the image your thread is responsible for. Quote Link to comment Share on other sites More sharing options...
pyrochild Posted April 25, 2009 Share Posted April 25, 2009 In older versions of CodeLab you could override OnSetRenderInfo to do some pre-processing, but I don't think you can anymore. You can set a flag that tells you when you're running through your Render method for the first time, process the entire image, and then use subsequent passes of Render to actually do your Rendering. Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
Enormator Posted April 25, 2009 Share Posted April 25, 2009 process the entire image What are the edges of the entire image? "rect" is only a small part of the image, isn't it? Couldn't it happen, that the second rendering thread tries to read the color before it the first is ready with calculating it? I could set a flag for being ready, but how do I wait for the flag? Like this? while(!ready){} Quote :Link: website Link to comment Share on other sites More sharing options...
Simon Brown Posted April 25, 2009 Share Posted April 25, 2009 What are the edges of the entire image? "rect" is only a small part of the image, isn't it? srcArgs.Size But as i've said, why not just read it every time - it's not as if reading the centre pixel takes a lot of computing power. Quote Link to comment Share on other sites More sharing options...
pyrochild Posted April 25, 2009 Share Posted April 25, 2009 process the entire image What are the edges of the entire image? "rect" is only a small part of the image, isn't it? You can get all the rects of the selection via Rectangle[] selectionScans = this.EnvironmentParameters.GetSelection(src.Bounds).GetRegionScansInt(); Couldn't it happen, that the second rendering thread tries to read the color before it the first is ready with calculating it? I could set a flag for being ready, but how do I wait for the flag? Like this? while(!ready){} I'm not sure if you can use CodeLab to set an Effect as single threaded, but if you can that would be better. If not, change that to while(!ready){Thread.Sleep(1);} This avoids bogging down the CPU with spinning a loop. @ Simon: srcArgs.Size will process the entire image. It's the size of the Surface, not the selection. Also, even if it was the size of the selection, you wouldn't know if the selection was anywhere but at the top-left, or if it was non-rectangular. And by "middle" he means arithmetic mean, not center pixel. Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
Enormator Posted April 25, 2009 Share Posted April 25, 2009 What are the edges of the entire image? "rect" is only a small part of the image, isn't it?You can get all the rects of the selection via Rectangle[] selectionScans = this.EnvironmentParameters.GetSelection(src.Bounds).GetRegionScansInt(); To access every selected pixel I would then have to write a triple loop like this? for (int i = 0; i < selectionScans.size(); i++) { for (int y = selectionScans[i].Top; y < selectionScans[i].Bottom; y++) { for (int x = selectionScans[i].Left; x < selectionScans[i].Right; x++) { //add this pixel to the arithmetic mean calculation } } } and to access ie the red value of a pixel would I then use this? selectionScans[i][x,y].R Quote :Link: website Link to comment Share on other sites More sharing options...
pyrochild Posted April 25, 2009 Share Posted April 25, 2009 To access every selected pixel I would then have to write a triple loop like this? for (int i = 0; i { for (int y = selectionScans[i].Top; y { for (int x = selectionScans[i].Left; x { //add this pixel to the arithmetic mean calculation } } } Arrays don't have a size() function. To get the number of elements, use the Length property. But I would clean it up to this (where you don't need to know the size of the array anyway) foreach(Rectangle rect in selectionScans){ for(int y=rect.Top;y for(int x=rect.Left;x //add this pixel to the arithmetic mean calculation } } } and to access ie the red value of a pixel would I then use this? selectionScans[i][x,y].R No, the rectangles themselves don't have pixel data. They're just a struct containing location and size information. (x, y, width, height). To get the pixel value, just use srcArgs.Surface[x,y].R Again, the current working rectangle is irrelevant this way, cleaning up the code. Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.