Skip to content

fix(draw/opengles): cache compare image src by content#10020

Open
borgeuz wants to merge 3 commits into
lvgl:masterfrom
borgeuz:fix/9903-opengles-texture-cache-file-src
Open

fix(draw/opengles): cache compare image src by content#10020
borgeuz wants to merge 3 commits into
lvgl:masterfrom
borgeuz:fix/9903-opengles-texture-cache-file-src

Conversation

@borgeuz
Copy link
Copy Markdown
Contributor

@borgeuz borgeuz commented Apr 24, 2026

Summary

Fixes #9903.

The OpenGL ES texture cache used lv_memcmp on the entire lv_draw_image_dsc_t, which compared the bytes of the src pointer instead of the file path it points at. Because
lv_image_set_src() lv_strdups the path per widget, two widgets pointing at the same file ended up with different pointers and produced a cache miss on every screen recreation,
even though the underlying texture was identical.

Changes (src/draw/opengles/lv_draw_opengles.c)

  • Added task_type to cache_data_t; the compare callback now partitions the RB tree by it before dispatching, so image_dsc_compare only ever runs on two image descriptors and
    the ordering stays symmetric.
  • New image_dsc_compare does a field-by-field comparison for LV_DRAW_TASK_TYPE_IMAGE. src is resolved via lv_image_src_get_type: lv_strcmp for FILE/SYMBOL, pointer
    compare for VARIABLE. All other task types keep the existing lv_memcmp path.
  • The cache now owns the file path: lv_strdup on insert (draw_to_texture), lv_free on eviction (opengles_texture_cache_free_cb). Without this, lv_strcmp would
    dereference a path the widget had already freed — swapping the cache miss for a use-after-free.
  • Moved colorkey from content compare to pointer compare. The cache doesn't own the colorkey struct, so dereferencing it would create the same UAF class as src. Same policy
    already used for bitmap_mask_src. Comments aligned.
  • sup is intentionally skipped (decoder-derived, would always miss); bitmap_mask_src keeps pointer compare. Behaviour unchanged.

Copy link
Copy Markdown
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 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/draw/opengles/lv_draw_opengles.c">

<violation number="1" location="src/draw/opengles/lv_draw_opengles.c:283">
P2: Cache comparator uses relational ordering on unrelated pointers, making key ordering non-portable/undefined in C.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/draw/opengles/lv_draw_opengles.c Outdated
The OpenGL ES texture cache compared draw descriptors with lv_memcmp,
which compared the bytes of the `src` pointer instead of the file path
content. Because lv_image_set_src() lv_strdup()s the path per widget,
two widgets pointing at the same file produced different src pointers,
causing a cache miss on every screen recreation. Reported in lvgl#9903.

- Add `task_type` to cache_data_t; partition the cache by it before
dispatching the compare, so image-dsc compares are isolated and the
RB tree ordering stays symmetric.
- Replace lv_memcmp for IMAGE tasks with image_dsc_compare, which
better resolves lv_draw_image_dsc_t fields to avoid comparing raw pointers.
- lv_strdup the path on insert and lv_free it on eviction so the
cache owns the dereferenced memory; otherwise lv_strcmp would
trade the cache miss for a use-after-free when the widget frees
its src buffer.
- Move `colorkey` to pointer compare, consistent with the existing
`bitmap_mask_src` policy: fields the cache doesn't own are never
dereferenced.

Closes lvgl#9903

Signed-off-by: Borgeuzz <mmam2407@gmail.com>
@borgeuz borgeuz force-pushed the fix/9903-opengles-texture-cache-file-src branch from 9d6ee1a to 8bf4c2f Compare April 25, 2026 12:11
@github-actions
Copy link
Copy Markdown
Contributor

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. 27 (-1) 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 33 (-1) 0 0 0
Multiple RGB images 0 39 0 0 0
Multiple ARGB images 11 (-5) 40 (+2) 3 (-1) 3 (-1) 0
Rotated ARGB images 55 (-4) 44 15 15 0
Multiple labels 6 (+3) 35 (+2) 0 0 0
Screen sized text 81 45 17 17 0
Multiple arcs 40 (+1) 33 7 7 0
Containers 4 (+1) 37 (-1) 0 0 0
Containers with overlay 86 (-4) 21 44 44 0
Containers with opa 17 (+3) 37 1 1 0
Containers with opa_layer 18 34 5 5 0
Containers with scrolling 44 45 12 12 0
Widgets demo 71 39 (-1) 17 17 0
All scenes avg. 27 (-1) 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. 25 37 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 35 0 0 0
Multiple RGB images 0 39 0 0 0
Multiple ARGB images 11 42 0 0 0
Rotated ARGB images 29 33 9 9 0
Multiple labels 2 35 0 0 0
Screen sized text 85 46 18 18 0
Multiple arcs 33 33 6 6 0
Containers 4 37 (-1) 0 0 0
Containers with overlay 98 (+1) 22 41 41 0
Containers with opa 16 (+1) 37 (-1) 0 0 0
Containers with opa_layer 8 (+1) 35 (-1) 2 (+1) 2 (+1) 0
Containers with scrolling 47 (-1) 48 (-1) 12 12 0
Widgets demo 67 40 15 15 0
All scenes avg. 25 37 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
Copy Markdown
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

Fixes OpenGL ES texture cache misses for file/symbol-backed images by comparing image sources by content (path/symbol string) rather than by pointer value, addressing #9903.

Changes:

  • Added task_type to cache keys and used it to partition comparisons so different task descriptors are never compared with mismatched logic.
  • Implemented an image-specific descriptor comparator that compares src by string content for FILE/SYMBOL and by pointer for VARIABLE, while keeping other task types on the existing lv_memcmp path.
  • Made the texture cache own duplicated FILE/SYMBOL src strings (strdup on insert, free on eviction) to avoid use-after-free.

Comment thread src/draw/opengles/lv_draw_opengles.c
Comment on lines +443 to +448
lv_draw_image_dsc_t * img_dsc = (lv_draw_image_dsc_t *)cache_data->draw_dsc;
if(img_dsc->src != NULL) {
lv_image_src_t src_type = lv_image_src_get_type(img_dsc->src);
if(src_type == LV_IMAGE_SRC_FILE || src_type == LV_IMAGE_SRC_SYMBOL) {
img_dsc->src = lv_strdup((const char *)img_dsc->src);
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

addressed in commit 00509d

@AndreCostaaa
Copy link
Copy Markdown
Collaborator

Hi. Thank you for the PR

Please address Copilot's remarks

borgeuz and others added 2 commits May 7, 2026 18:34
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenGL texture cache fails for images loaded from file

3 participants