Skip to content

Large scale rendering refactor - #757

Draft
JanPetterMG wants to merge 3 commits into
mainfrom
chore/rendering-refactor
Draft

Large scale rendering refactor#757
JanPetterMG wants to merge 3 commits into
mainfrom
chore/rendering-refactor

Conversation

@JanPetterMG

Copy link
Copy Markdown
Collaborator

Refactor rendering logic to enhance performance and reduce complexity across various modes.

Key changes

  • Updated rendering methods, including refactoring of modes using the old ones
  • Simplified data structures in several modes to streamline rendering processes.

Impact

These changes optimize rendering performance, potentially improving responsiveness and reducing resource usage. The refactor also lays the groundwork for future enhancements and easier maintenance.

Copilot AI lite review requested due to automatic review settings August 4, 2026 17:02
@JanPetterMG JanPetterMG added firmware C++ related chore This issue or pull request is a maintenance task labels Aug 4, 2026
@JanPetterMG JanPetterMG added this to the v2.5.2 milestone Aug 4, 2026
@github-actions github-actions Bot added the extra Optional resources label Aug 4, 2026
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9454aa00-b1d3-4e1b-9dc8-7673389a6ff8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors firmware rendering by introducing faster frame operations (row/column/shape fills), simplifying mode drawing logic, and restructuring display mapping/orientation handling to support more efficient refresh.

Changes:

  • Reworked DisplayService rendering pipeline (pixel mapping, flush planes, new drawing/fill primitives, updated frame accessors).
  • Updated many modes/extensions to use the new DisplayService APIs (e.g., fillFrame, fillRow, fillColumn, ellipse/rectangle helpers).
  • Updated streaming mode protocol handling to route by port and parse payload offsets per protocol.

Reviewed changes

Copilot reviewed 44 out of 44 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
firmware/src/services/ModesService.cpp Updates mode-switch UI rendering and power-on behavior using new display primitives.
firmware/src/services/DisplayService.cpp Major rendering refactor: new flush logic, orientation mapping, new drawing/fill APIs, reordered callbacks.
firmware/src/services/DeviceService.cpp Adjusts shutdown clear behavior and global instance initialization style.
firmware/src/modes/WeatherMode.cpp Switches to fillFrame(0U) for clearing before drawing.
firmware/src/modes/WaveformMode.cpp Uses fillFrame/fillRow instead of per-pixel loops.
firmware/src/modes/TickerMode.cpp Switches to fillFrame(0U) for clearing before drawing.
firmware/src/modes/StreamMode.cpp Routes UDP packet parsing by protocol/port and updates frame setting logic.
firmware/src/modes/StarsMode.cpp Optimizes star placement using linear indices and new pixel APIs.
firmware/src/modes/SnakeMode.cpp Updates clearing/brightness calls for new pixel API signatures.
firmware/src/modes/ScanMode.cpp Uses fillColumn to reduce per-pixel drawing complexity.
firmware/src/modes/RingMode.cpp Switches to fillFrame(0U) for clearing before drawing.
firmware/src/modes/RainMode.cpp Switches to fillFrame(0U) for clearing.
firmware/src/modes/PixelSequenceMode.cpp Precomputes pixel order mapping and uses index-based pixel API.
firmware/src/modes/PingPongMode.cpp Uses new line helpers for paddles and explicit brightness for pixels.
firmware/src/modes/NoiseMode.cpp Switches to index-based pixels and explicit brightness updates.
firmware/src/modes/LinesMode.cpp Uses fillColumn for faster line animation rendering.
firmware/src/modes/HomeThermometerMode.cpp Uses fillFrame(0U) and tightens integer constants/casts.
firmware/src/modes/GlitterMode.cpp Uses index-based pixel API for random glitter placement.
firmware/src/modes/FliesMode.cpp Simplifies fly storage to a pair and uses new display calls.
firmware/src/modes/FireworkMode.cpp Splits ellipse drawing into outline/solid helpers and updates calls accordingly.
firmware/src/modes/EqualizerMode.cpp Refactors bar structure/looping and uses rectangle/line helpers.
firmware/src/modes/CountdownMode.cpp Switches to fillFrame(0U) for clearing before drawing.
firmware/src/modes/ClockMode.cpp Switches to fillFrame(0U) for clearing before drawing.
firmware/src/modes/CircleMode.cpp Uses new ellipse outline helper.
firmware/src/modes/BrightMode.cpp Uses fillFrame(UINT8_MAX) for full-bright fill.
firmware/src/modes/BreakoutClockMode.cpp Uses fillRows/line helpers for faster block/paddle drawing.
firmware/src/modes/BlinkMode.cpp Simplifies blink toggling using fillFrame.
firmware/src/modes/BlindsMode.cpp Refactors blinds rendering with fillFrame/fillRow and state handling.
firmware/src/modes/BinaryEpochMode.cpp Uses rectangle fill helper instead of per-pixel loops.
firmware/src/modes/ArrowMode.cpp Uses fillFrame(0U) and tightens boundary condition checks.
firmware/src/handlers/ClockHandler.cpp Replaces manual clearing loops with fillRows.
firmware/src/extensions/SignalExtension.cpp Switches to fillFrame(0U) when displaying signals.
firmware/src/extensions/OtaExtension.cpp Ensures display is powered before drawing OTA UI and uses fillFrame(0U).
firmware/src/extensions/MessageExtension.cpp Switches to fillFrame(0U) for message rendering.
firmware/include/services/DisplayService.h Updates public display API surface and adds pixel mapping structures/static pixels.
firmware/include/modes/StreamMode.h Splits stream handlers per protocol and adds <span>.
firmware/include/modes/StarsMode.h Refactors star state from x/y to linear index.
firmware/include/modes/ScanMode.h Renames scan state from column to x.
firmware/include/modes/PixelSequenceMode.h Changes pixel map storage and adds configure() override.
firmware/include/modes/NoiseMode.h Refactors dot state from x/y to linear index.
firmware/include/modes/FliesMode.h Simplifies fly storage and cleans up pending initialization.
firmware/include/modes/EqualizerMode.h Simplifies bar representation to a pair.
firmware/include/modes/BlinkMode.h Adds lit state and modernizes initializers.
extra/Python/ModeGenerator.py Updates generated modes to use Display.fillFrame(0U).
Suppressed comments (7)

firmware/src/services/DisplayService.cpp:101

  • indices is declared as std::pair<uint8_t,uint8_t> but it stores values from pixelsMapped (a PixelMap). This is a type mismatch that will fail to compile.
    firmware/src/services/DisplayService.cpp:116
  • This loop treats indices[idx] as a std::pair and uses .first/.second, but indices should store PixelMap (bit/byte). As written, it won’t compile once indices is corrected.
    firmware/src/services/DisplayService.cpp:189
  • PixelMap has bit/byte fields, but mapPixel assigns to .first/.second, which will not compile.
    firmware/src/modes/StreamMode.cpp:98
  • This static_cast to a fixed-extent mutable std::span is ill-formed and risks UB. Construct the std::span<const uint8_t, N> directly from the packet pointer and expected payload size.
    firmware/src/modes/StreamMode.cpp:103
  • This static_cast to a fixed-extent mutable std::span is ill-formed and risks UB. Construct the std::span<const uint8_t, N> directly from the packet pointer and expected payload size.
    firmware/src/modes/StreamMode.cpp:112
  • This static_cast to a fixed-extent mutable std::span is ill-formed and risks UB. Construct the std::span<const uint8_t, N> directly from the packet pointer and expected payload size.
    firmware/src/modes/StreamMode.cpp:94
  • data.front() is undefined behavior if an empty UDP packet is received. Guard the access so length 0 safely results in time == false.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +344 to +346
const uint8_t margin{
max<uint8_t>(1U, static_cast<int>(GRID_ROWS - height) / static_cast<int>(lines.size() + 1U))};
uint8_t y{max<uint8_t>(0U, (GRID_ROWS - height - ((lines.size() - 1U) * margin)) / 2U)};
Comment on lines +87 to +88
const std::pair<uint8_t, uint8_t> &mapping{pixelsMapped[logical]};
planes[0U][mapping.second] |= static_cast<uint8_t>(mapping.first);
Comment on lines +53 to +57
struct PixelMap
{
uint8_t bit;
uint8_t byte;
};
Comment on lines +445 to +450
const size_t maxX{static_cast<size_t>(minX + columns)};
for (size_t y{static_cast<size_t>(minY + 1U)}; y < maxY; ++y)
{
frame[minX + (y * GRID_COLUMNS)] = _brightness;
frame[maxX + (y * GRID_COLUMNS)] = _brightness;
}
Comment on lines +331 to +332
for (size_t idx{static_cast<size_t>(x + (yMin * GRID_COLUMNS))}; idx < x + (yMax * GRID_COLUMNS);
idx += GRID_COLUMNS)
Comment thread firmware/src/modes/EqualizerMode.cpp
Comment thread firmware/src/modes/StreamMode.cpp Outdated
Comment on lines +86 to +87
Display.setFrame(static_cast<std::span<uint8_t, GRID_COLUMNS * GRID_ROWS>>(
std::span(packet.data(), packet.length()).subspan(18U)));
Comment thread firmware/src/modes/FireworkMode.cpp
Copilot AI review requested due to automatic review settings August 4, 2026 17:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 45 out of 45 changed files in this pull request and generated 4 comments.

Suppressed comments (6)

firmware/src/services/ModesService.cpp:347

  • lines.size() - 1U can underflow when lines is empty (e.g., if the first TextHandler height is >= GRID_ROWS, the loop breaks before pushing any lines). That will make the y calculation wrap and can lead to drawing with an invalid starting Y position.
    firmware/src/modes/StreamMode.cpp:97
  • data.front() is used without guarding against zero-length packets, and the same dynamic-to-fixed std::span cast issue appears here twice. This can be simplified by computing the payload offset and constructing a fixed-extent span from packet.data() + offset when the length matches.
    firmware/src/modes/StreamMode.cpp:113
  • Same dynamic-extent to fixed-extent std::span cast issue as in onArtNet(): construct the fixed-extent span directly from pointer+count.
    firmware/src/services/DisplayService.cpp:60
  • configure() calls setOrientation(Orientation::deg0) on every boot when the orientation is default, which persists to NVS and can cause unnecessary flash wear. You can initialize pixelsMapped (and set render so the splash flushes) without writing the orientation back to NVS.
    firmware/include/services/DisplayService.h:79
  • mapPixel takes uint8_t logical, but the code has an explicit #else branch for displays with GRID_COLUMNS * GRID_ROWS > 256. In that configuration, setOrientation() iterates logical beyond 255, and passing it to mapPixel(uint8_t, …) will wrap and write the mapping into the wrong slots (leaving most of pixelsMapped uninitialized).
    void mapPixel(uint8_t logical, uint8_t physical);

firmware/src/modes/StreamMode.cpp:41

  • begin() starts listening before validating port. If NVS contains an unexpected value, the default: path returns without registering a handler, leaving the UDP socket open but effectively unmanaged.

pending = true;
}

void DisplayService::mapPixel(uint8_t logical, uint8_t physical)
Comment on lines +84 to +88
if (packet.length() == 18U + GRID_COLUMNS * GRID_ROWS)
{
Display.setFrame(static_cast<std::span<const uint8_t, GRID_COLUMNS * GRID_ROWS>>(
std::span(packet.data(), packet.length()).subspan(18U)));
}
Comment on lines +304 to 307
uint8_t DisplayService::getPixel(uint8_t x, uint8_t y) const
{
for (size_t idx{0U}; idx < frame.size(); ++idx)
{
_frame[idx] = frame[pixels[idx]];
}
return frame[static_cast<size_t>(x + (y * GRID_COLUMNS))];
}

void fillColumn(uint8_t x, uint8_t _brightness);

void fillFrame(uint8_t _brightness);
Copilot AI review requested due to automatic review settings August 4, 2026 18:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore This issue or pull request is a maintenance task extra Optional resources firmware C++ related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants