Jump to content

Plugin processing according to Rick


MJW
 Share

Recommended Posts

Rick Brewster has made a number of very informative comments about how plugins are processed. I decided to collect them into one place. This is a work in progress. I will try to weed out outdated information.

 

Posted December 28, 2009

Quote

.NET threads will correspond to Win32 threads. The abstraction between "managed thread ID" and "native thread ID" mapping does exist, but it only matters if you are doing custom .NET hosting, e.g. SQL Server. Also, .NET is not a virtual machine or environment, so you are doing yourself a disservice by thinking that way.

As a corollary, in Paint.NET you can be sure that a managed thread will not be "migrated" among native threads, or processes. Fibers are never used anywhere.

And you're right that Paint.NET has a lot of "ambitious ambiguity" in the contract. However, at this point (5 years later) it's safe to say:

1) OnSetRenderInfo() will always be called first, and always by itself.

2) OnRender() will be called next. The first ROI is always executed by itself. After that, parallelism ensues.

Also, the token that is given to the effect is a Clone() of the one from the effect config dialog. From there, each thread used for OnRender() has its own Clone() of the token.

So, there is some "bracketing" that takes place. You can be assured that calls to OnSetRenderInfo() and OnRender() will never overlap when drawn on a timeline.

Also, in v3.5.2 I am adding an IsCancelRequested property that you can poll from within OnSetRenderInfo() or OnRender(). The guarantee at that point is that when IsCancelRequested flips to true that any "in-flight" OnRender() calls will be discarded.

In a future version, I plan to redo the effect system to provide more control over execution and progress reporting type stuff. Basically you'll be given an object to report progress through, and a simple ReadPixels() / WritePixels() interface. From there, additional classes will be provided which will take care of chunking of ROIs, parallelism, etc. But at that point those things will be optional -- great for multipass effects, and also great for effects where a different ROI "chunking" strategy is preferred.

 

Posted May 21, 2010

Quote

Sweet. On my system* it runs at the same performance no matter what setting I choose for "distance", during with PaintDotNet.exe only shows a few % of CPU usage.

As for an optimization hint, you can treat the OnRender() call as "this region must be finished rendering by the time you return, after which you can't write to it anymore." Contrast this to, "you can only render to this region when I hand it to you." In other words, you are allowed to render to a region at any time between OnSetRenderInfo() and the completion of your OnRender() implementation that is told to render that region.

I believe Ed is using a trick in his Fast Blur such that he queues up and begins all rendering in OnSetRenderInfo() and then each OnRender() call simply waits for that region to be finished before it returns. (He is doing his own background/worker thread management.)

 

Posted September 3, 2011

Quote

The way it works is,

1. Your Effect is instantiated (your constructor is called)

2. The user configures stuff (your CreateEffectConfigDialog() is called, or IndirectUI just does it for you)

3. OnSetRenderInfo() is called with the new token.

4. OnRender() is called many times, once for each section of the region of interest. These calls are made in parallel on multiple threads.

5. If the user changes the configuration (the token), then IsCancelRequested is set to true and Paint.NET waits for any pending OnRender() calls to finish. Go back to step 3. (IsCancelRequested is also reset to false)

If you want you can do all your rendering in OnSetRenderInfo() and then OnRender() would be implemented to do nothing. It doesn't provide a great user experience though.

 

Posted June 21, 2016

Quote

 

Quote
As I remember it, a single Render thread runs first, and when it completes, the multi-threading begins.)

 

Correct. That is intentional.


// Render first tile by itself as an attempt at some extra thread safety guarding, and to support better quick-cancellation
rc.RenderNextTile(this.effectTokenCopy);

 

  • Like 1
  • Upvote 2
Link to comment
Share on other sites

On 07/03/2008 at 1:33 PM, Rick Brewster said:

For two pass effects of (1) analysis and (2) rendering, it is most appropriate to do the first pass in OnSetRenderInfo().

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...