Forerunner 955 poor performance with Analog sample (drawBackground ~10ms)

I ran the Analog sample by switching the buffers to modern form:

_offscreenBuffer = Graphics.createBufferedBitmap({
    :width => dc.getWidth(),
    :height => dc.getHeight(),
        :palette=> [
            Graphics.COLOR_DK_GRAY,
            Graphics.COLOR_LT_GRAY,
            Graphics.COLOR_BLACK,
            Graphics.COLOR_WHITE
        ] as Array<ColorValue>
}).get();

And date buffer:

_dateBuffer = Graphics.createBufferedBitmap({
        :width=>dc.getWidth(),
        :height=>Graphics.getFontHeight(Graphics.FONT_MEDIUM)
}).get();

After that it compiles and runs. However when I profile it, I don't get good numbers:

drawBackground takes nearly 10 000 us on average with with Forerunner 955 whereas with Fenix 6 it takes just 4000 us.

That's more than twice as bad with Forerunner 955 than Fenix 6. Is something off? I also notice that emulator does not show antialiasing on FR955 but it does on older devices.

Thanks

  • Plot thickens.

    Turns out the profiler is garbage. All of my above screenshots are worth nothing. Profile won't give even remotely same numbers as Watch Face Diagnostics screen in low power mode.

    As pointed by Jim above, the Watch Face diagnostics screen is only thing that matters.

    But the problem gets even more complicated with that finding:

    I made a test repo Arrow heading up, and my initial findings are here as table:

    Type of drawing Type of clipping Total time
    Full bitmap No DC clipping  50ms
    Top half of full bitmap Clipped with DC 28ms
    Right half of full bitmap Clipped with DC 50ms
    Top half of full bitmap Clipped with drawOffsetBitmap 55ms
    Quarter (top right) of full bitmap Clipped with DC 28ms
    Quarter but with smaller bitmap Clipped with DC, and offset with drawBitmap  28ms
    Three small rectangles of same bitmap Clipped with DC 33ms

    I can't make sense out of this! Drawing smaller sections isn't guarateed to improve performance, it seems to be location sensitive. If the clipping overlaps the center part, performance seems to tank.

    Notable things that are surprising:

    • Drawing top half of the screen is faster than right half of the screen. Even though it's same surface area. It makes no sense to me.
    • Drawing top right quarter of the screen takes about same time as rendering top half of the screen.
    • drawOffsetBitmap is garbage, always use setClip
    • Making smaller bitmaps (with equal drawing area) is not increasing performance of drawing.
  • Understand the display is updated by row.  The more rows, the bigger impact. Think about a second hand with an analog face.  The lowest impact will be at 3 and 9, and the biggest at 6 and 12.

    Top right quarter and top half half screen would be the same number of rows.  When you have multiple clip regions, they get combines, so if you have one at the top of the screen and another at the bottom, it will be expensive, as all the rows between get updated.

    Right half of full bitmap and full bitmap would be the same number of rows and from your numbers, you see that's the case.

    Understand that 28ms is at the edge with the 30ms avg requirement, and it could excced that based on the screen demensions.  280x280 top half is more roes than 240x240 top half

    Yes, you always want to use setClip()  drawOffsetBitmap doesn't do a clip region, so it will be the full screen

  • Top right quarter and top half half screen would be the same number of rows.

    Now I get it! Thanks a lot. You seem to be king of Monkey C around here, reading other posts.

    I do get the sense though that Garmin in-house developers are not dogfooding the Monkey C. Their watch faces aren't probably written in Monkey C. So many omissions with basic bounding box math etc.

    Secondly if I look at the stock watch faces, they animate the analog dial like rolex for a while when you change it. I can't replicate that! Also they have full height analog second hand and parts of the screen are updating same time. It's getting very close to 30ms limit if not going above it, they must have other tricks not available to us Monkey C users.

    I tend to think that programming languages that are not dogfed by the main devs will languish. If the Garmin devs indeed are not using Monkey C to build their stock watch faces, what is the point of new language? I'm getting a bit ranty here, but this was pointed by main devs in Apple, they wanted their developers to develop with Swift and first thing they did, they made their engineers to develop with it too.

    Garmin should own the Monkey C and make their devs to write the stock Watch Faces and code them in Monkey C. Or indeed let us build the stuff with what ever they use to build their watch faces.

  • Garmin should own the Monkey C and make their devs to write the stock Watch Faces and code them in Monkey C. Or indeed let us build the stuff with what ever they use to build their watch faces.

    My hot take is neither of those things will happen because Garmin (as a whole) doesn't care enough about Connect IQ.

  • Native watch faces, glances, widgets, activities aren't written in Monkey C and can do things that can't be done in CIQ.  Garmin does publish some CIQ watch faces though and you can see them in the store, as well as things like the hydration widget.

  • Garmin also publishes CIQ device apps and data fields, some of which, hilariously enough, highlight shortcomings of CIQ.

    For example, one limitation with CIQ data fields is that they don't work seamlessly with the "Resume Later" feature of high-end Garmin watches, which lets you suspend an activity indefinitely and resume it later (instead of leaving it paused for an extended amount of time, which would waste battery).

    When you resume an activity later, CIQ data fields aren't suspended and resumed, but new instances are started. So if you don't write special code to handle this case, your data field will be starting from a blank state, which means that any activity data accumulated by the app will be lost.

    I don't know of any CIQ data fields which work properly with Resume Later, not even Garmin's own Running Power field.

    Another limitation is that CIQ data fields aren't allowed to replace native FIT activity data fields such as speed, distance, cadence and power. The FIT spec and Monkey C have a provision to *suggest* that a CIQ FIT field should override a given native field, but almost everyone ignores this suggestion, including Garmin's Connect app.