BufferedBitmap on renders completely black on glance view

Hi! I'm trying to optimize the efficiency of a glance I've written. Drawing all the primitives each time onUpdate() is called slows down the scrolling speed significantly. So I thought I'd render this to a BufferedBitmap once and then just redraw that as long as the data is still the same. However, the BufferedBitmap is just black, there's nothing on the screen.

Here's the code I use in the glance's onUpdate(), with the image caching parts removed so as to highlight the problem.

                var bitmapOpts = {
                    :width => dc.getWidth(),
                    :height => dc.getHeight()
/*                    :palette => [Graphics.COLOR_BLACK,
                            Graphics.COLOR_WHITE,
                            Graphics.COLOR_RED,
                            Graphics.COLOR_BLUE]*/
                };
                var bitmap = Graphics has :createBufferedBitmap ?
                    Graphics.createBufferedBitmap(bitmapOpts).get() as BufferedBitmap :
                new Graphics.BufferedBitmap(bitmapOpts);
                bitmap.getDc().clearClip();
                bitmap.getDc().setColor(Graphics.COLOR_BLACK, Graphics.COLOR_BLACK);
                bitmap.getDc().clear();
                var soc = sd.getSOC();
        	    bitmap.getDc().setColor(Graphics.COLOR_RED, Graphics.COLOR_BLACK);
        	    bitmap.getDc().drawRectangle(0, 0, dc.getWidth(), dc.getHeight());
                var histogram = sd.getGridHistogram();
                var maxValue = sd.getMaxValue(histogram);
                for (var x = 0; x < histogram.size()*2; x++) {
                    var height = histogram[x/2].toFloat() / maxValue.toFloat() * dc.getHeight().toFloat() - 2.0f;
                    bitmap.getDc().drawLine(x+1, dc.getHeight()-1-height.toNumber(), x+1, dc.getHeight()-1);
                }
                bitmap.getDc().setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
                bitmap.getDc().drawText(25, 60, Graphics.FONT_SYSTEM_XTINY, soc+"%", Graphics.TEXT_JUSTIFY_CENTER);
                dc.drawBitmap(0, 0, bitmap);
I also tried using a palette (which means I can't render antialiased text onto the bitmap, but that's easy to fix by just rendering the text onto the screen dc).
No joy. What I am doing wrong?
 
  • I just tried to play with the palette since you mentioned colors, and reduced it to just black and red. That's when I noticed that for some reason my application was no longer updating. I removed it from the watch manually and reinstalled, then it would work.

    Lo and behold, performance is a lot better now - and as it turns out, it's equally fast now if I go back to full colors without a palette. Apparently at some point it stopped installing the new application on sideloading and was just using the old code. Doh!

    So yeah, now the code above with the image buffering is rendering about as fast as the native glances, certainly to the naked eye. And it's a big improvement compared to drawing lines at every onUpdate!

  • 1. How does whole picture look?

    2. Your code shows that the image is constant and you only draw it once on the bitmap, right?

  • 1) It looks like this:

    (Still a WIP)

    2) I am fetching data in the background every 10 seconds.Whenever a new set arrives, I invalidate the bufferedimage. On the next onUpdate(), if there's no stored bufferedimage, I create a new one and store it. I then render that stored image.

    Works a treat, once I figured out that I have to wipe the app from the watch before updating something non-visual, because otherwise it might not update. This is not a problem in the emulator. Speed is smooth now! (Well, at least as smooth as the other glances, but hey)

  • 1. Create bitmap in onLayout and save handle in member, you don't need to create it in onUpdate

    2. Use in bitmap only necessary colours.

    3. in onUpdate simple

    var _dc = getDc();
    _dc.setColor(-1, 0);

    _dc.clear();

    and draw image on _dc

    then use

    dc.drawBitmap(0, 0, bitmap);

    and now add text but directly on dc not on _dc because if bitmap has palette you can use antialiasing unless your doesn't it

  • 1. What's the benefit of doing this? Note that if there's an update, I want to see that immediately. Doesn't onLayout get called much less often?

    2. I used a high-speed camera to measure performance on the actual device (Epix). I did not see an improvement in drawing one image with no palette, and one that has just a two-color palette. So I think I'm gonna stick to full color now that the performance is ok.

    3. What is the benefit of doing setColor(-1,0) over what I'm doing, which is:

    bitmap.getDc().clearClip();
    bitmap.getDc().setColor(Graphics.COLOR_BLACK, Graphics.COLOR_BLACK);
    bitmap.getDc().clear();

  • Do you plan to target only epix? If yes, ok if you are happy after measuring it by camera (there is the profiler in SDK).

  • Oh yes, this is really just an internal thing for my home PV and energy storage. I have several consoles that display energy status (for example https://www.youtube.com/watch?v=Z9DQ40P-Wlk), I have a tizen app, a display using M5Stack, an e-paper display...

    Basically it loads a small json that contains all the statistics, but if you wanted to use my stuff you'd need to build that json based on data extracted from your own system because there's no commonly used standard.

  • So as I mentioned if you happy with your solution you don't have to do anything more Slight smile

  • Excellent, thanks!

    The only question is, why does this work:

    var myDc = bitmap.getDc();
    myDc.draw....
    myDc.draw....
    myDc.draw....

    But this doesn't:

    bitmap.getDc().draw....
    bitmap.getDc().draw....
    bitmap.getDc().draw....

    I mean, sure the first one is the way to go, but functionally it shouldn't matter, no? Unless it's not actually just getting the dc, but doing some sort of preparation operation...

  • myDc is local var pointed do dc, faster access 

    getDc() as Graphics.Dc

    if you call bitmap - "global" , slower

    getDc() like array bitmap[:symbol=getDc()], slower additional accessing

    a lot of nuances...

    look into memory monitor before and after changing to local, usually if you save memory code is faster

    and if something is "const" don't craete it many times, bitmap is "const" object only drawing is changed so cost of creating checking createBufferedBitmap, creating dictionary, bitmap can be big especially for epix when there is graphic pool when system has to put and manage graphic objects

    unnecessary clearClip() costs also :)