From 315e7e04a8bbf44bbbd0d65987b14bac7f5d4249 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 24 Jan 2025 19:46:33 +0100 Subject: [PATCH] UI: Avoid double scaling of preview images, improve filtering When loading preview images from disk, we'd first scale them to the standard preview image size (in `icon_copy_rect()`) and then scale them again to the drawing size when eventually drawing to screen. The first scaling would happen on the CPU, which is slow, and without filtering. Now the image is stored in its original size and only scaled when drawing, which uses scaling on the GPU with mipmaps and bi-linear filtering. While a bit more blurry, the resulting image has less artifacts and represents the original image better. Keeping the images unscaled means memory footprint is bigger, we could cap the size if necessary. Noticed while working on #131871. Asset shelf previews would have more artifacts than before. See pull request for comparisons. Pull Request: https://projects.blender.org/blender/blender/pulls/133559 --- source/blender/editors/include/ED_render.hh | 6 +++++ .../editors/interface/interface_icons.cc | 10 ++++---- .../blender/editors/render/render_preview.cc | 23 +++++++++++++++---- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/source/blender/editors/include/ED_render.hh b/source/blender/editors/include/ED_render.hh index b0c0d9d67b6..753321eebdc 100644 --- a/source/blender/editors/include/ED_render.hh +++ b/source/blender/editors/include/ED_render.hh @@ -73,6 +73,12 @@ const char *ED_preview_collection_name(ePreviewType pr_type); void ED_preview_ensure_dbase(bool with_gpencil); void ED_preview_free_dbase(); +/** + * For preview icons loaded from disk (deferred loading), use the size of the source image, and + * only scale to the display size when drawing. Then we actually know the final display size + * (so we don't scale twice), and can scale on the GPU while drawing. + */ +bool ED_preview_use_image_size(const PreviewImage *preview, eIconSizes size); /** * Check if \a id is supported by the automatic preview render. */ diff --git a/source/blender/editors/interface/interface_icons.cc b/source/blender/editors/interface/interface_icons.cc index 3dd0bf2b22c..2294b0f9b54 100644 --- a/source/blender/editors/interface/interface_icons.cc +++ b/source/blender/editors/interface/interface_icons.cc @@ -1004,12 +1004,14 @@ static void icon_create_rect(PreviewImage *prv_img, enum eIconSizes size) } } else if (!prv_img->rect[size]) { - prv_img->w[size] = render_size; - prv_img->h[size] = render_size; prv_img->flag[size] |= PRV_CHANGED; prv_img->changed_timestamp[size] = 0; - prv_img->rect[size] = static_cast( - MEM_callocN(render_size * render_size * sizeof(uint), "prv_rect")); + if (!ED_preview_use_image_size(prv_img, size)) { + prv_img->w[size] = render_size; + prv_img->h[size] = render_size; + prv_img->rect[size] = static_cast( + MEM_callocN(render_size * render_size * sizeof(uint), "prv_rect")); + } } } diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc index b9d6628b08c..6a7c6d4dcb2 100644 --- a/source/blender/editors/render/render_preview.cc +++ b/source/blender/editors/render/render_preview.cc @@ -1834,13 +1834,21 @@ void PreviewLoadJob::run_fn(void *customdata, wmJobWorkerStatus *worker_status) IMB_thumb_path_unlock(filepath); if (thumb) { - /* PreviewImage assumes premultiplied alpha... */ + /* PreviewImage assumes premultiplied alpha. */ IMB_premultiply_alpha(thumb); - icon_copy_rect(thumb, - preview->w[request->icon_size], - preview->h[request->icon_size], - preview->rect[request->icon_size]); + if (ED_preview_use_image_size(preview, request->icon_size)) { + preview->w[request->icon_size] = thumb->x; + preview->h[request->icon_size] = thumb->y; + BLI_assert(preview->rect[request->icon_size] == nullptr); + preview->rect[request->icon_size] = (uint *)MEM_dupallocN(thumb->byte_buffer.data); + } + else { + icon_copy_rect(thumb, + preview->w[request->icon_size], + preview->h[request->icon_size], + preview->rect[request->icon_size]); + } IMB_freeImBuf(thumb); } @@ -1915,6 +1923,11 @@ static void icon_preview_free(void *customdata) MEM_freeN(ip); } +bool ED_preview_use_image_size(const PreviewImage *preview, eIconSizes size) +{ + return size == ICON_SIZE_PREVIEW && preview->runtime->deferred_loading_data; +} + bool ED_preview_id_is_supported(const ID *id, const char **r_disabled_hint) { if (id == nullptr) {