Render pictures in colour on Kaleido panels (Clara Colour, Libra Colour) - #99
Render pictures in colour on Kaleido panels (Clara Colour, Libra Colour)#99abhishek-anand wants to merge 2 commits into
Conversation
Clara Colour and Libra Colour carry a colour filter array over the same greyscale panel, but Cobalt has only ever written luminance to them. This adds a colour path for pictures end to end while keeping every greyscale device byte-for-byte on its current behaviour. kobo-profile: a `colour_panel` flag on each device profile, true only for the two Kaleido models. A test pins the flag to the profile name so applications, which only ever see the name, can rely on it. kobo-abi: the hwtcon waveform ids and update flags the MTK driver uses for colour (GCK16/GLKW16/GCC16/GLRC16, dithering, monochrome-only and the colour-filter mode field), checked against Kobo's published kernel header by the existing conformance build. kobo-hal: a `ColourContent` refresh intent that asks for the standard colour-filter mode on hwtcon and degrades to `QualityContent` on any other panel; `ChannelOrder` derived from the framebuffer bitfields so RGB lands in the right bytes on both i.MX and MTK layouts; and `RegionSnapshot::from_rgb`. kobo-ui: `Surface` gains an optional chroma plane that is allocated lazily, kept in step by every write, and dropped on clear, so screens without colour cost nothing extra. The frame planner emits a `Colour` waveform when the region it is about to write carries colour, and the picture cache accepts `PictureFormat::Rgb` uploads alongside grey. kobo-protocol: RGB pictures travel on new tags (28 inline, 29 begin upload) so the grey tags are unchanged on the wire and no version bump is needed. `DeviceIdentity::colour_panel()` reads the profile name. kobo-sdk: `put_colour_picture` and a `format` on `Command::PutPicture`. kobo-image: `Picture` keeps an RGB plane when decoded with `decode_colour`, scales it with the grey, and can encode it as PNG. kobod: the painter writes the RGB region through the display session when the transition carries colour and the panel can show it, and the grey plane otherwise. kobo-sim: accepts the new messages; its preview panel is a Clara BW so colour updates land as luminance, which is what the device would do. Untested on hardware. The colour path needs a run on a Clara Colour or Libra Colour before release; on every other device the written bytes and flags are unchanged.
There was a problem hiding this comment.
🔵 Needs a closer look
It changes the on-device rendering/refresh pipeline for a new hardware class and is explicitly unvalidated on Kaleido hardware, so it needs careful human + device testing before approval.
Pull request overview
Adds end-to-end support for rendering RGB pictures in colour on Kaleido (CFA) Kobo panels while preserving byte-for-byte behaviour for existing greyscale devices by downgrading colour-specific intents/flags and keeping legacy picture tags unchanged.
Changes:
- Introduces a colour-aware refresh intent/flags path (HWTCON) and RGB region snapshot writing with per-device channel order.
- Extends UI surfaces, picture caching, and drawing to optionally carry and render a chroma plane alongside the existing grey plane.
- Extends protocol/SDK to transport RGB pictures via new tags (28/29) while keeping the legacy grey picture tags (18/20) unchanged.
File summaries
| File | Description |
|---|---|
| tools/abi/hwtcon_conformance.c | Adds ABI conformance asserts for new waveform IDs and colour-related update flags. |
| crates/kobo-abi/src/lib.rs | Defines colour-era waveform IDs and HWTCON flag constants used by the new colour refresh path. |
| crates/kobo-profile/src/lib.rs | Adds colour_panel to device profiles and marks Kaleido profiles accordingly, with tests pinning naming/flag consistency. |
| crates/kobo-hal/src/surface.rs | Adds ChannelOrder and RegionSnapshot::from_rgb to write RGB into the framebuffer byte layout safely. |
| crates/kobo-hal/src/refresh.rs | Adds RefreshIntent::ColourContent and emits HWTCON colour-filter flags only for colour updates. |
| crates/kobo-hal/src/display.rs | Offers colour capability (DisplaySession::colour) and downgrades colour intents on non-colour panels. |
| crates/kobo-ui/src/lib.rs | Adds chroma plane to Surface, colour-aware planning (PanelWaveform::Colour), picture formats, caching, scaling and tests. |
| crates/kobo-protocol/src/lib.rs | Adds PictureFormat to picture messages; introduces new tags for RGB pictures without bumping protocol VERSION. |
| crates/kobo-sdk/src/lib.rs | Adds put_colour_picture and threads PictureFormat/pixels through the command/message pipeline. |
| crates/kobo-sim/src/lib.rs | Accepts new picture messages and treats colour waveform as luminance on the BW preview panel. |
| crates/kobo-image/src/lib.rs | Adds colour-preserving decode/encode and picture scaling that keeps grey+colour planes in step. |
| crates/kobod/src/main.rs | Updates picture message handling to use format + pixels APIs. |
| crates/kobod/src/device.rs | Writes RGB regions when a transition carries colour and the display reports a channel order; otherwise uses grey. |
| apps/morse/src/main.rs | Updates tests for the grey → pixels field rename in Command::PutPicture. |
Review details
- Files reviewed: 14/14 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The painter copied the colour bytes of a region out of the frame and then converted that copy into framebuffer bytes, holding two buffers for one write. `Surface::colour_rows` now lends the rows straight out of the chroma plane and `RegionSnapshot::from_rgb_rows` builds the snapshot from them, so only the snapshot is allocated. A source with more or fewer rows than the region, or a row of the wrong length, is refused rather than cropped. `DeviceIdentity::colour_panel` compares case-insensitively over the name's bytes instead of lowering a copy of it, and the picture scaling loop names the three bytes of a pixel explicitly rather than relying on `zip` to stop reading.
|
Blocked on a port rather than a conflict. #79 (now on To land on
The runtime side is already reconciled locally: Also failing independently of the merge: the host job's |
Why
Clara Colour and Libra Colour have a Kaleido 3 colour filter over the same greyscale panel every other Kobo uses. Cobalt has only ever written luminance to them, so pictures on those devices came out grey. This PR adds a colour path for pictures end to end while keeping every greyscale device byte-for-byte on its current behaviour.
Not tested on hardware yet — I don't have a Kaleido device. It needs a run on a Clara Colour or Libra Colour before this can be released (see checklist below). Nothing changes in what gets written on the BW/Libra 2/Clara HD/Elipsa devices, so those are unaffected.
What changes, by crate
kobo-profilecolour_panel: boolonDeviceProfile, true only forCLARA_COLOUR_393andLIBRA_COLOUR_390. A test pinscolour_panel == id.contains("colour")for every supported profile, because applications only ever see the name (see protocol note).kobo-abiGCK16 8 / GLKW16 9 / GCC16 10 / GLRC16 11and update flags (dithering0x1, monochrome-only0x8000, colour-filter mode mask0x7f00, standard mode0x100). Added as_Static_asserts intools/abi/hwtcon_conformance.c;check-hwtcon.shpasses against Kobo's published kernel header (linux/v4.9/include/linux/hwtcon_ioctl_cmd.hfrom Kobo's GPL source drop).kobo-halRefreshIntent::ColourContent— GC16 with the standard colour-filter flag on hwtcon, plain GC16 on mxcfb.DisplaySession::issue()downgrades it toQualityContenton any panel withoutcolour_panel, so nothing new is ever sent to a greyscale driver.ChannelOrderis read from the framebuffer bitfields (i.MX is BGRA, MTK is RGBA) andRegionSnapshot::from_rgbwrites accordingly.kobo-uiSurfacegets an optional chroma plane, allocated lazily on the first colour blend, kept in step by every write method, dropped onclear. Screens with no colour cost nothing extra.PanelWaveform::Colour;FramePlanneremits it when the region it is writing carries colour and tracks previous chroma for change detection.PictureFormat { Grey, Rgb },PictureCache::put_report_with/begin_upload_with; existing grey methods are unchanged wrappers.draw_picturescales RGB per channel.luma()is Rec.601.kobo-protocolVERSIONbump.PictureChunk.greyrenamed topixels(wire unchanged).DeviceIdentity::colour_panel()is derived from the profile name becauseWelcomeis a fixed 7-byte frame andkobo-profileispublish = falseso the published crates cannot depend on it.kobo-sdkput_colour_picture(handle, w, h, rgb);Command::PutPicturegainsformatandgrey→pixels. Re-exportsPictureFormat.kobo-imagePicturekeeps an optional RGB plane.decode_colour(grey output byte-identical todecode),from_rgb,encode_png_rgb;scaled_to/coverscale both planes.ditheris grey-only and documented as such.kobodPainter::paintwrites the RGB region when the transition carries colour and the display reports a channel order; grey plane otherwise.kobo-simapps/morseDesign decisions worth a look
GCC16. GCC16 is not guaranteed to be present in every device's waveform table; GC16 is, and the colour-filter mode field is what actually tells the driver to render through the CFA. If a Kaleido test shows GCC16 is better, it's a one-line change inrefresh.rs.hwtcon_flags()returns the colour-filter flag only forColourContent. Validated devices see exactly what they saw before.kobodwill reject tag 28/29 with the existing unknown-tag error.Hardware validation needed (Clara Colour / Libra Colour)
kobodtrace showsColourContentonly on colour transitionsGCC16in place ofGC16inRefreshIntent::ColourContentand compareConflicts
Touches
Painter::paintinkobod/src/device.rs, which #79 also edits. The overlap is small (the intent match and the frame-building block); whichever lands second needs a short rebase.Checks
cargo fmt --all -- --check✓cargo test --workspace --all-targets --all-features✓ (0 failures)cargo clippy --workspace --all-targets --all-features -- -D warnings✓sh tools/abi/check-hwtcon.sh <kobo kernel header>✓Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.