Skip to content

Conversation

@niklasf
Copy link
Contributor

@niklasf niklasf commented Nov 9, 2025

A flex track containing items with flex grow (without max width) should always be filled completely.

Before, grow_unit is always rounded down, somtimes leaving empty space on flex tracks. Adds a test case to show the issue and fixes it analogously to GRID_FR (#6255).

tests/ref_imgs/flex_grow.png before (note how pixels of the red container are visible at the end of some rows):

flex-grow-before

@github-actions
Copy link
Contributor

github-actions bot commented Nov 9, 2025

Hi 👋, thank you for your PR!

We've run benchmarks in an emulated environment. Here are the results:

ARM Emulated 32b - lv_conf_perf32b

Scene Name Avg CPU (%) Avg FPS Avg Time (ms) Render Time (ms) Flush Time (ms)
All scenes avg. 28 37 7 7 0
Detailed Results Per Scene
Scene Name Avg CPU (%) Avg FPS Avg Time (ms) Render Time (ms) Flush Time (ms)
Empty screen 11 33 0 0 0
Moving wallpaper 2 33 1 1 0
Single rectangle 0 50 0 0 0
Multiple rectangles 0 35 (-2) 0 0 0
Multiple RGB images 0 39 0 0 0
Multiple ARGB images 8 (-3) 43 (+1) 0 (-1) 0 (-1) 0
Rotated ARGB images 54 (-3) 44 15 (+1) 15 (+1) 0
Multiple labels 7 (+4) 33 (-2) 0 0 0
Screen sized text 94 (-3) 47 20 20 0
Multiple arcs 40 (+9) 33 7 7 0
Containers 4 (+3) 37 0 0 0
Containers with overlay 86 (-11) 21 44 44 0
Containers with opa 10 (-7) 35 (-2) 1 (+1) 1 (+1) 0
Containers with opa_layer 21 (+3) 34 (+1) 6 6 0
Containers with scrolling 45 47 (+1) 12 12 0
Widgets demo 67 (-1) 40 16 16 0
All scenes avg. 28 37 7 7 0

ARM Emulated 64b - lv_conf_perf64b

Scene Name Avg CPU (%) Avg FPS Avg Time (ms) Render Time (ms) Flush Time (ms)
All scenes avg. 24 38 6 6 0
Detailed Results Per Scene
Scene Name Avg CPU (%) Avg FPS Avg Time (ms) Render Time (ms) Flush Time (ms)
Empty screen 11 33 0 0 0
Moving wallpaper 1 33 0 0 0
Single rectangle 0 50 0 0 0
Multiple rectangles 0 46 0 0 0
Multiple RGB images 0 39 0 0 0
Multiple ARGB images 1 38 0 0 0
Rotated ARGB images 29 34 9 9 0
Multiple labels 3 40 (+7) 0 0 0
Screen sized text 81 (-1) 45 (-1) 17 (-1) 17 (-1) 0
Multiple arcs 33 (+6) 33 6 (-1) 6 (-1) 0
Containers 5 (+5) 37 0 0 0
Containers with overlay 87 (-12) 23 42 (+1) 42 (+1) 0
Containers with opa 16 38 0 (-1) 0 (-1) 0
Containers with opa_layer 8 (+1) 37 1 1 0
Containers with scrolling 45 46 12 (+1) 12 (+1) 0
Widgets demo 66 (+1) 42 15 15 0
All scenes avg. 24 38 6 6 0

Disclaimer: These benchmarks were run in an emulated environment using QEMU with instruction counting mode.
The timing values represent relative performance metrics within this specific virtualized setup and should
not be interpreted as absolute real-world performance measurements. Values are deterministic and useful for
comparing different LVGL features and configurations, but may not correlate directly with performance on
physical hardware. The measurements are intended for comparative analysis only.


🤖 This comment was automatically generated by a bot.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 16 files

Prompt for AI agents (all 1 issues)

Understand the root cause of the following 1 issues and fix them.


<file name="src/layouts/flex/lv_flex.c">

<violation number="1" location="src/layouts/flex/lv_flex.c:373">
Multiplying grow_max_size by grow_value before dividing can overflow int32_t (e.g., 9,000,000 * 255 &gt; INT32_MAX), leading to undefined behavior and wrong flex sizes when large coordinates are used.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

AndreCostaaa
AndreCostaaa previously approved these changes Nov 10, 2025
Copy link
Collaborator

@AndreCostaaa AndreCostaaa left a comment

Choose a reason for hiding this comment

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

Makes sense to me. Thanks!

Copy link
Contributor

Copilot AI left a comment

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 fixes a rounding issue in flex layout where grow_unit was always rounded down, sometimes leaving empty space on flex tracks. The fix uses rounding to nearest integer instead of truncation, similar to the existing grid FR implementation (#6255).

Key Changes

  • Added div_round_closest helper function for rounding division
  • Changed flex grow size calculation from truncating division to nearest-integer rounding
  • Added test case to verify flex tracks are completely filled with growing items

Reviewed Changes

Copilot reviewed 2 out of 16 changed files in this pull request and generated no comments.

File Description
src/layouts/flex/lv_flex.c Implements rounding fix by replacing truncating division with div_round_closest
tests/src/test_cases/test_flex_grow.c Adds test case for flex grow behavior with various combinations of grow values and fixed sizes
tests/ref_imgs/*.png Updated reference images reflecting the fix

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

@W-Mai
Copy link
Contributor

W-Mai commented Nov 14, 2025

This looks good, but I'm wondering if simply adding rounding operations can really avoid all errors? For example, the current grow is 1:1:1, but the total width is 10. Can the current algorithm solve this?
I'm curious about how it works. Thank you.🚀

@niklasf
Copy link
Contributor Author

niklasf commented Nov 14, 2025

The 10 into 1:1:1 example was working even before. That's because each iteration of the loop only looks at the remaining grow_max_size and grow_value_sum.

grow_max_size grow_value grow_value_sum grow_unit size
10 1 3 10 / 3 = 3 1 * 3 = 3
10 - 3 = 7 1 3 - 1 = 2 7 / 2 = 3 1 * 3 = 3
7 - 3 = 4 1 2 - 1 = 1 4 / 1 = 4 1 * 4 = 4

But lets look at 10 into 4:4:4 for an extreme example, which should be similar. Before:

grow_max_size grow_value grow_value_sum grow_unit size
10 4 12 10 / 12 = 0 4 * 0 = 0
10 - 0 = 10 4 12 - 4 = 8 10 / 8 = 1 4 * 1 = 4
10 - 4 = 6 4 8 - 4 = 4 6 / 4 = 1 4 * 1 = 4

Instead, with the improved rounding, each element is at most 1 off the ideal size, and the last iteration will have no rounding at all:

grow_max_size grow_value grow_value_sum size
10 4 12 div_round_closest(10 * 4, 12) = 3
10 - 3 = 7 4 12 - 4 = 8 div_round_closest(7 * 4, 8) = 4
7 - 4 = 3 4 8 - 4 = 4 div_round_closest(3 * 4, 4) = 3

Rebased to fix conflict in reference images.

@niklasf niklasf force-pushed the defect/flex-grow-rounding branch from 1d58f57 to b633e65 Compare November 14, 2025 09:44
@niklasf niklasf force-pushed the defect/flex-grow-rounding branch from b633e65 to 5713f01 Compare November 14, 2025 09:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants