On 2017-04-30 23:52, J. Landman Gay via use-livecode wrote:
I have been wanting to know that for years. I have the general idea
but I want to know exactly what each command or property does. How
does layerMode interact with rendering and when should I set it? (I
used it incorrectly and submitted a spurious bug report, but I'm still
not clear on why I was wrong.)

This is perhaps something we should have more clearly documented at the time,
it has been a while since I last looked at it...

Your description is generally correct, but I'll see if I can elaborate with
more technical details.

First of all, just a reminder about how the engine handles screen updates...

The engine checks for the need to update the screen after every command has executed, or after 'unlock screen' if the screen has been locked and the unlock causes the lock count to reach zero.

During execution of a single command (when the screen is not locked), or the execution of all commands if under lock screen, any required visual changes to the object are accumulated in the stack's 'dirty region'. This is a collection of rectangles (on the stack) which need updated.

The acceleratedRendering property changes the way the engine renders the stack when changes are applied (either after each command, or after an unlock screen which resets the lock count to zero).

When it is false, the engine creates an offscreen buffer big enough to cover the dirty region, uses the dirty region as clip, then iterates through all objects on the card back to front, rendering each in turn into the single offscreen buffer. When that is complete, the engine copies the offscreen buffer to the screen.

When acceleratedRendering is true, however, this changes. Accelerated rendering mode views the tree of top-level objects as a flat sequence of layers, ordered from back to front. Each layer can have one of three layerModes:
  - static
  - dynamic
  - scrolling

The static mode indicates to the engine that that layer is not going to move, so once rendered once (in theory) it and any thing it covers won't need to be re-rendered.

The dynamic mode indicates to the engine that the layer is going to move, so ideally should be rendered independently of everything else.

The scrolling mode is the same as dynamic *except* that it indicates that the layer is just a view (clipped rectangle) into a larger area - e.g. what you can see in a field currently, and what the field would look like if rendered on an infinite screen with no clipping.

When there are multiple static mode objects next to each other in the list, they are all elided into a single layer. e.g.

   Graphic - static (bottom object)
   Image - static
   Image - static
   Button - dynamic
   Image - static
   Field - static (top object)

This would generate three separately rendered layers - the bottom one being the first three controls, the middle one being just the button, the top on being the last two controls.

The key thing here is that these layers can just be composited - i.e. they are existing bitmaps, which are blended together into the screen buffer on demand - this is something GPUs are very very very good at. In particular, when you have moving (dynamic) layers, moving those layers/objects doesn't require re-rendering anything *just* re-compositing to the screen with the layers in a different place. This is the source of the speed improvement you can see with acceleratedRendering (e.g. you can have, say, 100 objects moving about smoothly whereas you'd only manage maybe 10 before).

This is not the whole story, as acceleratedRendering mode makes one other 'optimization' - it doesn't actually use object-sized buffers for any layer. Instead, it splits up each (merged) layer into tiles with size the compositorTileSize. So the compositing step is actually blending together lots of small bitmaps, rather than a collection of large bitmaps - this makes no real difference to performance (as it is number of pixels blended which is the key factor, not number of bitmaps) but does to updating things when any object changes as only those tiles which intersect with the dirty region need to be considered... Furthermore, in acceleratedRendering mode, the 'virtual layers' (which come about through merging together adjacent statics, but leaving dynamic and scrolling ones alone) each have their own dirty region. This means, much less re-rendering needs to take place (in any one case) *and* much less data transfer from memory -> compositor's tile storage / format need to take place.

In terms of the compositor properties:

- the compositorType determines what kind of technology the blending step uses. There is a software mode, which works on all platforms and just uses the
    engine's not-too-shabby compositing code.
There is a coregraphics mode, which works on Mac/iOS, which uses CoreGraphics (which gives an advantage because CoreGraphics images can be blitted direct
     to the window buffer)
There is OpenGL mode, which works on Android/iOS, this uses tile-sized
    textures on the GPU, and the GPU to do all the blending.

- the compositorTileSize determines the size of tile to use (which must be
    a power-of-two up to 256 pixels).

- the compositorCacheLimit determines the maximum amount of memory to use
    for tiles.

The third point here needs a little bit of explanation. As acceleratedRendering mode splits things up into tiles, it can leave rendering any tile which is not visible until it is actually visible. For example, if you have a large opaque dynamic layer over a stack of static layers, chances are that you will never see most of the static layers underneath, so the tiles for the (virtual) static layer will never need to be rendered, or stored - so it doesn't. This minimizes the number of tiles/textures/images which are created, and minimizes rendering time for any one update.

Now to answer you direct questions:

- What does layerMode tell the engine, and when is it read? I think it
tells the engine to create a buffer for the object. I had read a long
time ago that it would help to reset the layermode to static if the
object was done moving, but there should have been a caveat: don't
reset if the object will move again later, because in that case you
want to preserve the existing buffer. That seems to imply that
resetting layermode to static will dump the buffer. Is that right?

When you change the layerMode it will cause a recalculation of layers around it (potentially) when the current dirty list (collection of per-layer dirty regions) is processed. If a layer is not going to move for quite a while, then you it might be reasonable to set it to static, as long as you can anticipate when it might move so you can set it to dynamic again (setting to dynamic and then moving immediately is likely to cause a stutter).

- When set to true, what does acceleratedRendering actually do? Is it
effectively a command to scan every object on the card and create
buffers? Does it scan more than just the current card?

It changes the approach to rendering as described above. The accelRendering buffers, tiles and such are keyed to the stack, but flushed whenever there is a card change - so essentially it is card local (but you only ever have one accelRendering context per stack).

- Is it okay to turn it on and off as needed? Are there disadvantages
to that, assuming the objects won't be moving any more? Can I turn it
on at the beginning of a handler and turn it off at the end if those
objects won't be moving any more?

This would be ill-advised unless all movement you want is happening within that handler. Turning acceleratedRendering on will mean the engine has to re-render all visible tiles in all the virtual layers; turning it off again deletes the accelRendering context for the stack, dumps all its tiles and then re-renders the stack using the normal painter's algorithm into offscreen buffer approach.

- When I turn it off, does it dump all the buffers? I think it does.

Yes.

- What does it do between card changes? Does it keep old buffers until
the cache limit is hit?

No - the buffer is flushed whenever the card changes.

Hope this helps!

Warmest Regards,

Mark.

--
Mark Waddingham ~ m...@livecode.com ~ http://www.livecode.com/
LiveCode: Everyone can create apps

_______________________________________________
use-livecode mailing list
use-livecode@lists.runrev.com
Please visit this url to subscribe, unsubscribe and manage your subscription 
preferences:
http://lists.runrev.com/mailman/listinfo/use-livecode

Reply via email to