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?
 
  • If you plan to create, drawing etc bitmap on every update it rather won't be faster and more efficiency (rather twice slower).

  • In the actual glance I store the image once it's drawn, reducing hundreds of primitive draw calls to one bitmap draw call. This is definitely going to be more efficient.

    The code I pasted doesn't do that. It's merely to illustrate the problem that no matter what I draw onto a buffered bitmap, the buffered bitmap is then showing as black on the screen once drawn.

  • It really depends on how often the glans restarts.  If you move it off screen and back on, it will clearly be starting, but may also happen if you just move the glance.  Then you have the case where live_updates are false (background updates) and onUpdate is rarely called.

    See https://developer.garmin.com/connect-iq/core-topics/glances/#glances

  • So if you save image it can be faster but not always unfortunately, strange thing is the efficiency is problem with devices with gpu e.g. epix and sdk 4.0

  • Thanks but that would all be fine with me. The idea is to reduce the number of draw calls, and if onUpdate() is called less often and it just keeps displaying what it displays, all fine by me.

    The problem is buffered bitmaps don't work. This isn't really about efficiency. I just want to draw something onto a buffered bitmap and then draw that buffered bitmap onto the screen. And it doesn't seem to work at all. Not just sometimes.

  • The problem at hand is that a buffered image remains blank despite me having drawn to it. Efficiency aside, is there a reason why this would not work at all on a glance?

  • Ok wow, I think I found the solution: You must not call bitmap.getDc() repeatedly. If I do it once and use that via a variable, everything works. Here's the code along with the image caching.

        function onUpdate(dc as Dc) as Void {
            // Call the parent onUpdate function to redraw the layout
            GlanceView.onUpdate(dc);
            if (sd != null && sd.getData() != null && !sd.getData().isEmpty()) {
                if (sd.getGlanceBitmap() == null) {
                    var bitmapOpts = {
                        :width => dc.getWidth(),
                        :height => dc.getHeight()
                    };
                    var bitmap = Graphics has :createBufferedBitmap ?
                        Graphics.createBufferedBitmap(bitmapOpts).get() as BufferedBitmap :
                    new Graphics.BufferedBitmap(bitmapOpts);
                    var bitmapDc = bitmap.getDc();
                    bitmapDc.clearClip();
                    bitmapDc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_BLACK);
                    bitmapDc.clear();
                    var soc = sd.getSOC();
            	    bitmapDc.setColor(Graphics.COLOR_RED, Graphics.COLOR_BLACK);
            	    bitmapDc.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;
                        bitmapDc.drawLine(x+1, dc.getHeight()-1-height.toNumber(), x+1, dc.getHeight()-1);
                    }
                    bitmapDc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
                    bitmapDc.drawText(25, 60, Graphics.FONT_SYSTEM_XTINY, soc+"%", Graphics.TEXT_JUSTIFY_CENTER);
                    sd.setGlanceBitmap(bitmap);
                }
                dc.drawBitmap(0, 0, sd.getGlanceBitmap());
            }
        }
    

    The good news is that I can now do as many draw calls as I want and performance will not change, this means I can do expensive stuff like image processing effects and transparency with no change in performance.

    The bad news is that indeed the overall scrolling performance is still nowhere near that of a native glance. Changing to a buffered bitmap doesn't make it worse, but it does not improve things if you're just drawing a bit of text for example.

  • Have you looked at this?

    https://forums.garmin.com/developer/connect-iq/b/news-announcements/posts/widget-glances---a-new-way-to-present-your-data

    If you're doing a bunch of draws, you want to look at reducing that.

    Remember, native stuff isn't done in CIQ.

  • He is doing exactly what I'm doing (my sd.getGlanceBitmap will return null after a new data refresh, which only happens every 10 seconds or so). Reducing the number of draw calls per onUpdate was why I wrote the code above.

    I was hoping that the performance benefits would be more substantial but it seems there's a lot of unneccessary copying being done internally when using CIQ, vs. garmin's native implementations.

  • 1. how many colours do you use?

    2. how big is size of histogram?

    There is a few things to optimize in code, maybe we'll be faster...