YOUR ACCOUNT

Login or Register to post new topics or replies
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
I ran into the issue of multithreading in trying to store variables during the get_sample() function.

Apparently, if you initiate a variable in the prepare() function and try to use that in get_sample(), it will work independently in every thread.

At least so it has been with what I've tried to do.

For example, this script uses a counter to try and control when to start and stop a process. However, the same counter is used independently in every single thread.

Is there a way around this?

TD

  Details E-Mail
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
The script is this:

function prepare()
counter = 1
counterMax = get_intslider_input(COUNTERMAX)
end;

function get_sample(x, y)
if counter < counterMax then
v = 1
else
v = 0
end
counter = counter + 1
return v, v, v, 1
end;

If it wasn't for multithreading, there would only be a small white line in the top left corner of the image. Instead, it is all over the image in every render thread square.

Here's the file.

Test a1m.ffxml
  Details E-Mail
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
Here's what I'm trying to do.

I want to make a "Ramp" filter which is a sort of wind blur type filter. The color values decrease in one direction until a higher value is found.

By calculating the ramp for every single pixel produces the correct output.



  Details E-Mail
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
So far so good. However at the setting of 100 pixels, the render takes 24,34 seconds, since every pixel is sampled 100 times.

So, methinks, I'm going to optimize it by just using three variables that hold the last RGB value in memory and compares it to the current pixel. And this would work if the image was calculated from top left to bottom right line by line. Instead, the result is this:





  Details E-Mail
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
Render time is just 0.65 seconds, but the result is a wreck.

Now, if I could just turn off multithreading (is that possible?), it would be correct.

I can think of a rather complex handling: treat each thread image rectangle as a separate image and write code that takes this into account.

Seems messy.

Anybody know of a simpler handling?
  Details E-Mail
Sphinx.
Filter Optimizer

Posts: 1750
Filters: 39
We can just hope they will add some sort of bitmap script component.. you can't expect a top,left.. bottom,right rasterization order, not only because of multithreading: put a distorter in front and you'll have a very funky looking windblur, lol!

I asked about something related here
  Details E-Mail
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
Well, I tried my complex solution and it worked, at least to a degree.

Looks just like it should and renders in 0,63 secs.

The only problem is, it works beautifully with antialiasing turned OFF. Turning antialiasing ON messes it up as my script doesn't know we're now taking more samples. Once I sort that out, we'll have a Ramp Scrippet.
  Details E-Mail
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
Hi Sphinx,

Yes, I saw that. I was considering using a table to precalculate a whole image -- but that pretty much wiped that idea out.

Not sure what you mean by the problem with adding a distorter, seems to work fine. Here's the image put through Noise Distort and then Ramp.



  Details E-Mail
Sphinx.
Filter Optimizer

Posts: 1750
Filters: 39
Ah! That looks good, I thought it would screw up your ramp vars somehow.. I'm curious to how you're rendering this smile:)
  Details E-Mail
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
Oh crap, I see what you mean, you put it in reverse sequence, firts Ramp, then Distort, and you get... crap.

Why is that?



  Details E-Mail
Sphinx.
Filter Optimizer

Posts: 1750
Filters: 39
Bugger! Yes thats what I meant.. not img -> distorter -> script, but img -> script -> distorter.
  Details E-Mail
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
Bugger indeed.

I don't get it. What happens? Do the x and y coordinates change due to the Distort?

Here's the script:

Quote
function prepare()
d = OUTPUT_WIDTH/100*get_intslider_input(DISTANCE)
w = OUTPUT_WIDTH
ramp = 1/d
counter = 1
x0 = -1
end;

function get_sample(x, y)
if counter == 1 or x == x0 then
vr, vg, vb, va = get_sample_map(x, y, CLR_IMAGE)
x0 = x
for i = 0, d, 1
do
wr, wg, wb, wa = get_sample_map(x-i/w, y, CLR_IMAGE)
vr = math.max(vr, wr-i*ramp)
vg = math.max(vg, wg-i*ramp)
vb = math.max(vb, wb-i*ramp)
counter = 2
end
else
wr, wg, wb, wa = get_sample_map(x, y, CLR_IMAGE)
vr = math.max(vr-ramp, wr)
vg = math.max(vg-ramp, wg)
vb = math.max(vb-ramp, wb)
end
local r = vr
local g = vg
local b = vb
local a = 1
return r, g, b, a
end;
  Details E-Mail
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
As you see, I use the variable "counter", which is used once for every thread. After that the full calculation backwards from (x, y) is done when x=x0, that is, at the left edge of each render rectangle. In all other pixels, the stored value is "ramped" down and compared with the current value.

Thus the script does two different things depending on whether it is the leftmost row of pixels in each render rectangle or not.
  Details E-Mail
Sphinx.
Filter Optimizer

Posts: 1750
Filters: 39
Yeah, the coordinate system cannot be expected to be a linear progression during rasterization, many things in FF can change it, like transformations, distortions etc

A noise distortion is not really distorting its source.. it is distorting the coordinates passed to the source..

I'm not sure how you can solve that without creating a temporary buffer of some sort.
  Details E-Mail
Vladimir Golovin
Administrator
Posts: 3446
Filters: 55
A quick overview of how we implement multithreading in FF scripts:

1. Script components are executed in separate Lua interpreters (Lua's internal term is "Lua states"), so they can't communicate.

2. Before the rendering begins, we create a single Lua interpreter per script component and execute the prepare() function.

3. After the prepare() call has been successfully completed, we copy the Lua state (variables, tables etc.) into several new Lua interpreters, one per rendering thread, so when the rendering begins, each script component has as many Lua interpreters as there are rendering threads, and their states are identical.

4. The rendering is done per-block. We create Lua interpreters and initialize them with the state described in p.2 for every block. When a block is successfully rendered, we just kill its Lua interpreter without preserving its state.
  Details E-Mail
Vladimir Golovin
Administrator
Posts: 3446
Filters: 55
Quote
Sphinx. wrote:
Yeah, the coordinate system cannot be expected to be a linear progression during rasterization, many things in FF can change it, like transformations, distortions etc


Yes. This is very important to understand. Here's what I wrote for the Help file:

Sampling Order

Components must not assume that sampling calls they receive will conform to any particular order or pattern. A component must be able to report its color at any location at any time.

The sampling pattern and order may change when a component is sampled by an upstream distortion or transform component, or when Filter Forge applies smart anti-aliasing where some pixels receive more samples than others (especially when sample jittering is turned on), or even due to a GUI scenario where the renderer places higher priority on rendering blocks that are currently visible in the GUI viewport.
  Details E-Mail
Vladimir Golovin
Administrator
Posts: 3446
Filters: 55
Quote
Sphinx. wrote:
A noise distortion is not really distorting its source.. it is distorting the coordinates passed to the source..


Exactly. Here's an example script from the Help article (don't forget to add the inputs):

Quote

function prepare()
end;

function get_sample(x, y)
rd, gd, bd, ad = get_sample_map(x, y, DISTORTER)
samplex = x + (rd + bd/2) * ad
sampley = y + (gd + bd/2) * ad

r, g, b, a = get_sample_map(samplex, sampley, SOURCE)
return r, g, b, a
end;


Note that the second get_sample_map() call uses different sample coordinates than the original sample coordinates supplied to script's own get_sample() via its x and y arguments. Filter Forge components, including scripts, are free to sample their map inputs any number of times at any sample coordinates, and they can use the RGBA values returned by these calls in any manner, including the calculation of sample coordinates for subsequent sampling calls, as in the example script above.

(This was an excerpt from the Help file I'm currently working on.)
  Details E-Mail
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
Okay, so what I get from all this is that the x and y coordinates of the get_sample(x,y) function cannot be expected to be processed in a linear fashion, NOT EVEN WITHIN A SINGLE RENDERING BLOCK, so scripts have to take that into account.

Correct?
  Details E-Mail
Vladimir Golovin
Administrator
Posts: 3446
Filters: 55
Quote
ThreeDee wrote:
Okay, so what I get from all this is that the x and y coordinates of the get_sample(x,y) function cannot be expected to be processed in a linear fashion, NOT EVEN WITHIN A SINGLE RENDERING BLOCK, so scripts have to take that into account.


Not even within a single pixel. smile:)

Yes, that's correct.
  Details E-Mail
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
Quote
Vladimir Golovin wrote:
Not even within a single pixel.


Ouch, there goes my backup plan...

Is there a way for a script to retrieve the current anti-aliasing setting?
  Details E-Mail
ThreeDee
Lost in Space

Posts: 1672
Filters: 112
I believe I now understand why a distort component messes this up: The sampling process goes in reverse, later components querying earlier components. Thus the upstream distort component queries the (x,y) samples in the sequence they are needed to render the Distort component, from the previous Script component.
So, I need to take into account both multithreading and sample-based rendering process if I want to store values in variables or tables.
  Details E-Mail
Vladimir Golovin
Administrator
Posts: 3446
Filters: 55
Quote
ThreeDee wrote:
Is there a way for a script to retrieve the current anti-aliasing setting?


No, and we don't plan to expose that.

Quote
ThreeDee wrote:
I believe I now understand why a distort component messes this up: The sampling process goes in reverse, later components querying earlier components.


The sampling process goes as follows. First, the renderer requests a sample from its root component, which is usually the Result component (unless you're previewing a component in the middle of the filter tree in Filter Editor.)

Then, the root component samples components connected to its inputs. For example, if the root component is Result set to Surface mode, it will sample all components connected to its inputs (Surface Color, Height, Reflectivity, etc.)

In turn, these components sample components connected to their inputs. The process stops when it reaches a component with no other component connected to its inputs.
  Details E-Mail

Join Our Community!

Filter Forge has a thriving, vibrant, knowledgeable user community. Feel free to join us and have fun!

33,711 Registered Users
+18 new in 30 days!

153,533 Posts
+38 new in 30 days!

15,348 Topics
+73 new in year!

Create an Account

Online Users Last minute:

32 unregistered users.

Recent Forum Posts: