Skip to main content
Inspiring
June 9, 2009
Question

Writing safely to a layer

  • June 9, 2009
  • 1 reply
  • 5672 views


Hello everyone,

I m writing an effect with a layer parameter LP.

I copy to a source layer SL the LP with scale, rotation ... using the transform_world function from PF_WorldTransformSuite

My problem is that when two copy overlap i got artifacts in my result


I guess it is related to multithreaded issues, with try to write the  same pixel at the same time.

does anyone has any suggestions?

This topic has been closed for replies.

1 reply

Community Expert
June 9, 2009

what do you mean by "copy to a source layer"?

do you mean you try to copy into the input? (no... you can't mean that...)

what are the artifacts you're getting?

I seriously doubt this is a multi threading issue.

the transformWorld() function is very safe in that respect.

if you'd like to post a snippet of the code perhaps i could be of more help.

Inspiring
June 10, 2009

Thank you for the answer. i will explain in details:

Here is what I'm doing:

Render function:
- create a temporary layer (same size as input layer)
- call iterate function to iterate over all pixels

Here is code snippet:
ERR(in_data->utils->new_world(in_data->effect_ref, input->width,
             input->height, PF_NewWorldFlag_NONE, &tmpLayer));
err = suites.Iterate8Suite()->iterate(in_data,
                                            progress_base,
                                            progress_final,
                                             src,   
                                            area,                   
                                            refcon,                   
                                            pix_fn,
                                             dst);


Here is what the per-pixel function (i.e. pix_fn) does:

1) read from input buffer at (x,y)
2) Clear the temp buffer region (x-width, y-height) to (x+width, y+height) in tmpLayer
3) Render the transformed kira to tmpLayer
4) For every pixel (i,j) in region (x-width, y-height) to (x+width, y+height) in tmpLayer
a) read from tmpLayer location (i,j)
b) do some math using read value
c) write a result value to output buffer location (i,j)

Steps 2 and 3 implemented with the following code:
    dstRect.bottom = (A_short)data->height-1;
    dstRect.top    = 0;
    dstRect.left   = 0;
    dstRect.right  = (A_short)data->width-1;
    ERR(suites.FillMatteSuite1()->fill(
         data->effect_ref,
        NULL,
        &dstRect,
        temp ));
    ERR(suites.WorldTransformSuite1()->transform_world(
        data->effect_ref,
        data->quality,
        PF_MF_Alpha_STRAIGHT,
         PF_Field_FRAME,
        &context->shapeLayerParam.u.ld,
        &compositeMode,
        NULL,
        &mat, 1,
        TRUE,
        &dstRect,
        temp ));

The result is corrupt rendering.

I suspect this is because the iterate function can process two pixels at once.

Between step 2 and step 4c there maybe FillMatteSuite1 that is called by another thread and may result in a corrupted result

I thought about three solutions:

1-allocate the temporary layer in the iterate function.

2-dont use the iterate function and process sequentially pixels

3-find a way to lock the temporary layer to avoid corruption

By using solution 2 and not using the iterate() function and instead processing all the pixels sequentially on my own, the corruption problem was resolved.

I will try the solution 1, hoping AE is doing good caching and memory management to avoid performance hit.

I dont know if there is a way to do the solution 3.

i would be happy to hear If you have any ideas that could help

Community Expert
June 10, 2009

well...

you were right in you assumption that the multi threading causes the problem,

as the tests you did confirm.

the tempLayer you create prior to the iterate function does indeed get overwritten by the different threads or the iterate function.

I can think of two solutions:

1. as you already sudgested, create and destroy the tempLayer inside the pix_fn.

this way each pixel gets it's own layer to render to.

2. create a few temp layers, and use iterate_generic() instead of iterate().

now you can tell which thread is running at the moment and make sure it uses it's own tempLayer.

both solutions allow you to use multi-threading.

but i must say that the whole process seems wasteful to me.

if you're willing to tell what your plug-in does then perhaps we could find a more efficient method.