From 99714afc4c4a5729d900a3b08abd71784bd029ae Mon Sep 17 00:00:00 2001 From: Lam Wei Lun Date: Fri, 16 Oct 2026 17:49:35 +0800 Subject: [PATCH] Keep picker thumbnails from retaining full-size texture decodes The thumbnail is downscaled on upload, but the full decode it was made from stayed in the decode cache for as long as the library entry lived. Thumbnail decodes now skip the cache, so only the 128 px thumbnail is kept per library texture. --- src/libslic3r/TextureDisplacement.cpp | 18 ++++++++++-------- src/libslic3r/TextureDisplacement.hpp | 5 +++-- .../GUI/Gizmos/GLGizmoTextureDisplacement.cpp | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/TextureDisplacement.cpp b/src/libslic3r/TextureDisplacement.cpp index ab63a75c70..26e8726a72 100644 --- a/src/libslic3r/TextureDisplacement.cpp +++ b/src/libslic3r/TextureDisplacement.cpp @@ -283,7 +283,7 @@ bool height_texture_has_color(const TextureDisplacementLayer &layer) return decode_height_texture(layer).has_color(); } -DecodedHeightTexture decode_height_texture(const TextureDisplacementLayer &layer) +DecodedHeightTexture decode_height_texture(const TextureDisplacementLayer &layer, bool keep_decoded) { DecodedHeightTexture result; if (layer.empty()) @@ -351,13 +351,15 @@ DecodedHeightTexture decode_height_texture(const TextureDisplacementLayer &layer } } - std::lock_guard lock(g_decoded_texture_cache.mutex); - // Opportunistically drop entries for image_data that no longer exists anywhere, so the - // cache doesn't grow without bound across many add/remove-texture cycles in a long session. - auto &entries = g_decoded_texture_cache.entries; - for (auto it = entries.begin(); it != entries.end();) - it = it->second.first.expired() ? entries.erase(it) : std::next(it); - entries[key] = { std::weak_ptr>(layer.image_data), result }; + if (keep_decoded) { + std::lock_guard lock(g_decoded_texture_cache.mutex); + // Opportunistically drop entries for image_data that no longer exists anywhere, so the + // cache doesn't grow without bound across many add/remove-texture cycles in a long session. + auto &entries = g_decoded_texture_cache.entries; + for (auto it = entries.begin(); it != entries.end();) + it = it->second.first.expired() ? entries.erase(it) : std::next(it); + entries[key] = { std::weak_ptr>(layer.image_data), result }; + } } // The image-adjustment panel's live edits, on top of the decode and before the smoothing. Before, diff --git a/src/libslic3r/TextureDisplacement.hpp b/src/libslic3r/TextureDisplacement.hpp index 6bd5d1ea33..919dfad654 100644 --- a/src/libslic3r/TextureDisplacement.hpp +++ b/src/libslic3r/TextureDisplacement.hpp @@ -599,8 +599,9 @@ DecodedHeightTexture downscale_height_texture(const DecodedHeightTexture &src, i // colour PNGs are accepted; for a colour source the height is its luminance, using the same // coefficients wxImage::ConvertToGreyscale() uses, so a texture imported as colour displaces exactly // as it did when the importer flattened it to grey on the way in. Returns an empty -// DecodedHeightTexture if image_data is empty or is not a PNG at all. -DecodedHeightTexture decode_height_texture(const TextureDisplacementLayer &layer); +// DecodedHeightTexture if image_data is empty or is not a PNG at all. keep_decoded = false leaves the +// result out of the decode cache, for one-off reads such as a picker thumbnail that must not hold full-size pixels. +DecodedHeightTexture decode_height_texture(const TextureDisplacementLayer &layer, bool keep_decoded = true); // decode_height_texture(layer).has_color(), answered from the decode cache rather than from a copy of the // texture - cheap enough to ask every frame. Smoothing does not change it, so the raw decode is what is read. diff --git a/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp b/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp index be1f72e520..646a23912a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp @@ -4122,7 +4122,7 @@ const GLGizmoTextureDisplacement::LibraryTexture *GLGizmoTextureDisplacement::ge if (entry.image_data) { TextureDisplacementLayer probe; probe.image_data = entry.image_data; - entry.thumbnail = upload_height_thumbnail(decode_height_texture(probe)); + entry.thumbnail = upload_height_thumbnail(decode_height_texture(probe, /* keep_decoded */ false)); if (!entry.thumbnail) entry.image_data.reset(); // decoded to nothing usable - treat it as a failed load } else {