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
This commit is contained in:
Julian Eisel
2025-01-24 19:46:33 +01:00
committed by Julian Eisel
parent a3d9bdad6b
commit 315e7e04a8
3 changed files with 30 additions and 9 deletions

View File

@@ -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.
*/

View File

@@ -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<uint *>(
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<uint *>(
MEM_callocN(render_size * render_size * sizeof(uint), "prv_rect"));
}
}
}

View File

@@ -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) {