Watch Face advice desired for several topics: layout, partial update, resource handling

Hi, I'm venturing in developing my first CIQ App WatchFace and I ran into questions if I choose the right solution for different issues. I hope you can give some advice.

I try to create some Display featuring Glyphs resembling those of the Predator selfdestruct device countdown from the movie.

1. layout and partial update

I tried to adapt the Analog Sample for my purposes to employ the partial update and offscreen rendering. But I also incorporated resurce based layout to avoid explicit positioning in code which turned out to be quite tricky with partial updates where I just need to redraw a part of the layouted components. I implemented a strategy to switch layouts on the fly to satisfy my rendering needs that worked but would instantiate new drawables every time when setLayout is called. I guess that's not the best way regarding memory and performance?

I refrained form that approach and now use layout for regular update components only. Additionally I have a separate drawable-list for some static graphics that must be omitted in low power mode w/o partial updates. Second data is drawn by custom drawables part of the main layout which can hide on demand. Works fine so far, but the hidden drawables still get draw calls in the regular cycle.

I guess there is no way to hide (temporarily remove) symbols (bitmaps, drawable-lists) from the drawing queue of the layout? Or is there a way to cache a separate layout not bound to the View? That may do the trick to render seconds separately while still using the layout technique.

2. Custom Drawable handling

The Custom Drawable class is actually some kind of segment-display featuring 12 segments which can be triggered individually to draw the required Glyphs. I choose this approach over custom font because I want to render random configurations for hour and minute digit values displaying the corresponting amount of segments istead of a fixed glyph and I want to scale freely.

One thing I'm pretty uncertain about is the way I use to draw the segments. I choose to supply the polygon cooordinates (16 Points) of each segment as jsonData and load them during draw if needed depending on the current configuration. These have to be translated to the position of the Drawable each time. I can't tell if that's a good idea regarding power budget for partial updates. I tried to compute all possible coordinates at instantiation time but that led to an out of memory exeption because each Drawable had to hold an array of 12*16*2 32bit vals.

I got several optimization ideas but don't know which are recommended.

  • Reduce polygon coordinates. 6 or 8 per segment should suffice. Less would possibly effort a lot of fine tuning, maybe depending on display size.
  • The segments have actually identic shapes only translated to different locations and angles. So it would be possible to calculate them from one initial set. Despite my lack of expertise in such cartesian transformations I doubt an advantage beyond little less memory required by the resources.
  • Use only one glyph display instance to render all values. Requires dynamic positioning without layout and major code refactoring.
  • Pre-render segments as bitmaps and draw them on demand. Doesn't seem to be any better than loading the coordinates each time.
  • Move coordinates array(s) from json resource to constant or instance variable in code. Bloats the code and will persumably block more memory permanently.

3. Json Resources

Besides those coordinate arrays I set up 60 fixed configurations as jasonData arrays for 4 of those display instance to render uniform second represantations. Each 2 dimensiononal array stores up to 4*12 Number values representing the active segment indices. Actually none of the configurations reaches this worst case. But looking at the recommendation not to load resources during partial updates I like to know if I should rather move that stuff to the code (i.e. as static const).

Instead of storing indices in the array a single Long bitmask per second configuration would also suffice. Thoug it would obfuscate what is to be rendered.

4. Device

I actually own a FR 735xt. I noticed it doesn't seem to support partial updates despite beeing SDK 2.4.x compatible. Is there any way to activate that feature or is the display hardware incapable? The documentation seem to be very vague about which devices actually feature this mode.

  • The 735 doesn't have the HW to handle partial updates  The first watch to do so was the Fenix 5/935/similar.

    With onPartial update, you want to be really careful what you do at the time, as you are limited to an avg of 30ms per call.  Things like loading resources at that time burns a great deal of time.  Also, the amount of screen (# of rows) has a big impact.

    Here's a whole thread about 1hz/onPartialUpdate()

    https://forums.garmin.com/developer/connect-iq/f/discussion/5156/1hz-watch-faces---q-a

  • Yes I read that thread (and others) before. Any chance I can test the impact with the simulator realistically?. Ran Fenix 5 and FR935 configurations which seemed to perform well most of the time.

  • In the sim, under File, use "View Watchface Diagnostics."

    You can see how you're doing.

    The WF must be running in low power mode.

    Here's an example (total time that second is 9.29ms):

    If after a full minute, you've exceeded the avg power budget, onPartialUpdate is no longer called.  (so it might take 1-2 minutes to see this.

    The reason it's an avg, is that number of rows matters, where on an analog face, 12 and 6 are the most expensive, while 3 and 9 the least expensive, so be sure to watch around 12 and 6.

  • Thx, that did the trick. Didn't think it takes so long til the average is calculated. I'm actually far beyond the budget.

    Because it's rather a digital interface I got fixed rows. I could split the rendering into 4 horizontally distributed cliping areas but I guess that won't help much or at all, right?

  • When you have multiple clip regions, they get combined.  So if you have 10 rows at the top and 10 at the bottom, the combined is the whole screen.

    The average is calculated over the minute (0 secs to 59 secs) and the analog is a good example as to why.  At 12 and 6 is could be over 30ms, but at 3 and 9, well under.

  • Well I got partial updates running properly but now memory consumtion exceeds the capabilities of FR735xt. Very frustrating. I wil have to reconsider some parts including layout and offscreen buffering.

  • The 735 doesn't support onPartialUpdate.Maybe look at jungles to reduce the size for the 735.

  • Yes, good hint. That could be part of the solution, but I'm pretty sure eliminating partial update code alone wont do. The major Problem is runtime polygon coordinates storage to render the second glyphs as fast as possible which is used in full power mode without partial updates too. But I think I can implement different polygon lookup strategies facilitating jungles exclude annotations.

    However I'm still not happy with the current memory consumption on fenix5/935/etc either. At the moment I got time components on the view exclusively . Adding date, bat, dnd and what else may fit will likely blow the limits again.

  • You may also have problems with devices with a screen larger than 240x240.  The va4,some of the f6 devices, etc.

  • I too have looked at the second hand issue for some time and read many posts about partial updates.  I had originally designed an unpublished analog face for a Fenix3 that I then updated that for a Fenix 5 (before partial updates had been implemented.)  I now have a Fenix 6 which is 260x260.  I'd love to be able to show the second hand for at least 1 minute.  BUT the watch face has a background image AND complex Hour and Minute hands.  

    I assume there no way to implement partial updates to accommodate a longer than 10 sec second hand given those parameters?  Or if there's a technique (such as forcing full power mode) I should explore can you point me that direction?  The battery life on these newer units is so good, that most of the time I'd prefer to sacrifice battery life for better graphics.