Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Hexamon
Newbie

How does roImageCanvas handle multiple layer redraws?

Sorry for a rather long post, I searched other, similar questions on the forum but to no avail. Please, feel free to point me to another thread which might have already answered these questions. I can also provide a simple test script which demonstrates the issue.

Test setup:

I have roImageCanvas with two layers. Layer 0 contains a large background image, layer 1 contains a small red square. When the user presses "ok" the script changes the metadata on layer 1 and sets it a new green square. The size of the square is exactly the same. The layer is set using the "canvas.SetLayer(1, ...)" method call.

Question:

1. Does this call cause the system to redraw (repaint) all layers? Please, note, nothing has changed on layer 0.
2. If yes, is there a way to change the color of the square on layer 1 in such a way that only affected area (of layer 1) is updated, not both layers. This does not have to be done by calling "SetLayer()", any method will do as long as it works.

What it looks like:

Somewhat sparse description of "SetLayer()" from the documentation says:

Void SetLayer(int zOrder, roAssociativeArray contentMetaData)
 zOrder is a z-order specifier with higher z-orders closer to the viewer. Negative z-orders are "behind the display" and are thus invisible. Each call to SetLayer replaces the previous contentMetaData that previously existed at that z-order layer. The caller passes an roAssociativeArrays (Content Meta-Data objects) representing the information for each image to be displayed on the roImageCanvas. See “Content Meta-Data” for details on the attributes for each element in the array. The screen is redrawn when SetLayer()is called.


I think the last sentence means entire screen is redrawn, although it is not clear. It also appears from the timing aspect of the ordeal that this is the case. When the background image is present on layer 0, it takes noticeably longer to have the color on layer 1 to change from red to green. It would be really helpful to know if there is a way to have several layers on top of each other, change the top layers and have only associated areas redrawn on the layers "underneath" it.

An almost workaround:

The following approach almost worked, although it is awfully kludgey - I had the background image drawn on a different canvas object. That different canvas (lets call it "canvas0") gets painted before the main canvas. It is no longer repainted then when the object on the main canvas get changed (it is obviously up to the developer at this point to figure out a clever way to avoid the background being "washed out" by the front). This essentially worked with one exception - the bloody screensaver! It kicks in, then when the user wakes up the system (by clicking on something) only the main canvas is repainted, "canvas0" is never repainted (understandably so, the system has probably thrown it out of the memory since the main canvas has replaced it). I would have the script "manually" repaint it on waking up from the screensaver but unfortunately I haven't found a way to determine the script has been just awaken from being in a screensaver mode.

Is there a way to tell from the script it has been just awaken from a screensaver "sleep"? Some sort of a "screensaverWakieWakie" type of event? Or a function I could call to determine it?
0 Kudos
4 REPLIES 4
TheEndless
Channel Surfer

Re: How does roImageCanvas handle multiple layer redraws?

I've found there are significant performance increases if you slice the background image up into more pieces. I got the same performance increase by just using the SourceRect attribute, instead of physically slicing the image, to paint the background in 6 different squares on the same layer. I'm not clear if that causes the background layer to just redraw the sliced portion or not, but I saw an increase on the order of 2-3 times. If the top most red square is solid, then setting the CompositionMode to "Source" should speed it up marginally, as well, as it doesn't need to do any alpha blending.
My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
0 Kudos
Hexamon
Newbie

Re: How does roImageCanvas handle multiple layer redraws?

Thanks for the suggestion. I tried it. Hard to tell whether or not there is a significant performance increase. There might be but it is relatively small (probably because the "red square" area takes up about half of the screen's real estate). Either case, even with this perf. improvement, the motion updates are noticeably slow (when compared to the "canvas0" approach). I'll stick with "canvas0" for now, hopefully there is some way to detect the "screensaver event".
0 Kudos
TheEndless
Channel Surfer

Re: How does roImageCanvas handle multiple layer redraws?

"Hexamon" wrote:
Thanks for the suggestion. I tried it. Hard to tell whether or not there is a significant performance increase. There might be but it is relatively small (probably because the "red square" area takes up about half of the screen's real estate).

That could be the difference. If the "red square" takes up half the screen, then it may need to be sliced up, too, otherwise you're incurring some of the same penalty of drawing a large swatch in a single layer.
I also used that method for redrawing smaller parts of the screen (ex. listbox selection background, individual poster art, blocks of text, etc), and saw increases from as much as 2 seconds down to 500ms, so it may just not be as effective for larger portions of the screen. Maybe a combination of the two methods would produce better results.

"Hexamon" wrote:
Either case, even with this perf. improvement, the motion updates are noticeably slow (when compared to the "canvas0" approach). I'll stick with "canvas0" for now, hopefully there is some way to detect the "screensaver event".

Detecting the screensaver will actually require writing data to a common area, and checking that periodically. It's not pretty, and there will be a delay on return from screensaver, but it's possible. The audio player sample in the SDK does something similar in order to share data between the main app and the screensaver, so there may be something there you can leverage. It's also important to note that the issue isn't limited to the screensaver. Anything you draw on top of the "canvas0" will leave an artifact unless you redraw it.

I'm sure you've already seen them, but we've had a few good conversation about roImageCanvas performance awhile back:
viewtopic.php?f=34&t=30944
viewtopic.php?f=34&t=32884
viewtopic.php?f=34&t=31062
My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
0 Kudos
Hexamon
Newbie

Re: How does roImageCanvas handle multiple layer redraws?

"TheEndless" wrote:
That could be the difference. If the "red square" takes up half the screen, then it may need to be sliced up, too, otherwise you're incurring some of the same penalty of drawing a large swatch in a single layer.
I also used that method for redrawing smaller parts of the screen (ex. listbox selection background, individual poster art, blocks of text, etc), and saw increases from as much as 2 seconds down to 500ms, so it may just not be as effective for larger portions of the screen. Maybe a combination of the two methods would produce better results.


I'll try to combine these two results. The nature of the change within the "red" square is not very demanding though - it only involves changing a small rectangle in a sort of "moving" way. Basically, the "red square" is a sort of a "menu" to select from different items. I'll play around with segmenting the images to smaller ones in a separate test area and measure the performance results. See what comes of it. It is indeed a very clever suggestion, hopefully I'll get it working.

Detecting the screensaver will actually require writing data to a common area, and checking that periodically. It's not pretty, and there will be a delay on return from screensaver, but it's possible. The audio player sample in the SDK does something similar in order to share data between the main app and the screensaver, so there may be something there you can leverage.


I actually checked that example out earlier this morning and realized it would entail writing a dedicated screensaver for the application and some monstrously inelegant approach to "share" the info between the app and the screensaver. I figured it wasn't worth it at this point. There is something I did though, a "poor man's" idle timeout detection of sorts - I keep an internal "lastTimeUserDidSomething" variable in the script which gets renewed every time user clicks something. After an extended timeout there's a piece of code which redraws "canvas0". This is not perfect - e.g. when user wakes up the system after a timeout, "canvas0" is not redrawn until s/he clicks another button (which is something reasonable to expect, the user probably woke it up to do something with it :)). At this point the entire screen comes back to normal. Is this perfect? No. Is the "good enough for now"? Certainly. Also, if I really dig into it, there might be a way to work around this issue too by setting up a timeout on the "wait()" function call to get the control back every 100ms or so. I might try it just for the fun of it, maybe it'll kill the box?

It's also important to note that the issue isn't limited to the screensaver. Anything you draw on top of the "canvas0" will leave an artifact unless you redraw it.


True. For example, the same thing happens on playing some clip with a roVideoScreen object. I'm sure there are other cases. These situations are more or less under the script control though, so, I do redraw "canvas0" as needed.

I'm sure you've already seen them, but we've had a few good conversation about roImageCanvas performance awhile back:
viewtopic.php?f=34&t=30944
viewtopic.php?f=34&t=32884
viewtopic.php?f=34&t=31062


Thanks for the references. Like you said some of them might not directly answer my questions but very educational for a beginner Roku developer such as yours truly.
0 Kudos