File Browser: Fix slowdown with non-existing ID previews in big files

When the File (or Asset) Browser would display data-blocks without
previews in a heavy .blend file, there would be a drastic slowdown.

See patch for details and comparison videos.

Differential Revision: https://developer.blender.org/D16273

Reviewed by: Bastien Montagne
This commit is contained in:
Julian Eisel
2022-10-18 15:05:53 +02:00
parent c2fe387244
commit 489260198e
4 changed files with 47 additions and 4 deletions

View File

@@ -182,6 +182,11 @@ void BLO_blendfiledata_free(BlendFileData *bfd);
typedef struct BLODataBlockInfo {
char name[64]; /* MAX_NAME */
struct AssetMetaData *asset_data;
/* Optimization: Tag data-blocks for which we know there is no preview.
* Knowing this can be used to skip the (potentially expensive) preview loading process. If this
* is set to true it means we looked for a preview and couldn't find one. False may mean that
* either no preview was found, or that it wasn't looked for in the first place. */
bool no_preview_found;
} BLODataBlockInfo;
/**

View File

@@ -138,11 +138,15 @@ LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh,
BHead *bhead;
int tot = 0;
const int sdna_nr_preview_image = DNA_struct_find_nr(fd->filesdna, "PreviewImage");
for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
if (bhead->code == ENDB) {
break;
}
if (bhead->code == ofblocktype) {
BHead *id_bhead = bhead;
const char *name = blo_bhead_id_name(fd, bhead) + 2;
AssetMetaData *asset_meta_data = blo_bhead_id_asset_data_address(fd, bhead);
@@ -165,6 +169,17 @@ LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh,
STRNCPY(info->name, name);
info->asset_data = asset_meta_data;
bool has_preview = false;
/* See if we can find a preview in the data of this ID. */
for (BHead *data_bhead = blo_bhead_next(fd, id_bhead); data_bhead->code == DATA;
data_bhead = blo_bhead_next(fd, data_bhead)) {
if (data_bhead->SDNAnr == sdna_nr_preview_image) {
has_preview = true;
break;
}
}
info->no_preview_found = !has_preview;
BLI_linklist_prepend(&infos, info);
tot++;
}

View File

@@ -115,6 +115,9 @@ struct FileListInternEntry {
* Owning pointer. */
AssetMetaData *imported_asset_data;
/* See #FILE_ENTRY_BLENDERLIB_NO_PREVIEW. */
bool blenderlib_has_no_preview;
/** Defined in BLI_fileops.h */
eFileAttributes attributes;
BLI_stat_t st;
@@ -1575,6 +1578,14 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
return;
}
/* If we know this is an external ID without a preview, skip loading the preview. Can save quite
* some time in heavy files, because otherwise for each missing preview and for each preview
* reload, we'd reopen the .blend to look for the preview. */
if ((entry->typeflag & FILE_TYPE_BLENDERLIB) &&
(entry->flags & FILE_ENTRY_BLENDERLIB_NO_PREVIEW)) {
return;
}
FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
PreviewImage *preview_in_memory = intern_entry->local_data.preview_image;
if (preview_in_memory && !BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW)) {
@@ -2042,6 +2053,9 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in
ret->preview_icon_id = BKE_icon_imbuf_create(ibuf);
}
}
if (entry->blenderlib_has_no_preview) {
ret->flags |= FILE_ENTRY_BLENDERLIB_NO_PREVIEW;
}
BLI_addtail(&cache->cached_entries, ret);
return ret;
}
@@ -2995,10 +3009,15 @@ static void filelist_readjob_list_lib_add_datablock(ListBase *entries,
entry->relpath = BLI_strdup(datablock_info->name);
}
entry->typeflag |= FILE_TYPE_BLENDERLIB;
if (datablock_info && datablock_info->asset_data) {
entry->typeflag |= FILE_TYPE_ASSET;
/* Moves ownership! */
entry->imported_asset_data = datablock_info->asset_data;
if (datablock_info) {
entry->blenderlib_has_no_preview = datablock_info->no_preview_found;
if (datablock_info->asset_data) {
entry->typeflag |= FILE_TYPE_ASSET;
/* Moves ownership! */
entry->imported_asset_data = datablock_info->asset_data;
}
}
entry->blentype = idcode;
BLI_addtail(entries, entry);

View File

@@ -1169,6 +1169,10 @@ enum {
FILE_ENTRY_NAME_FREE = 1 << 1,
/* The preview for this entry is being loaded on another thread. */
FILE_ENTRY_PREVIEW_LOADING = 1 << 2,
/** For #FILE_TYPE_BLENDERLIB only: Denotes that the ID is known to not have a preview (none was
* found in the .blend). Stored so we don't keep trying to find non-existent previews every time
* we reload previews. When dealing with heavy files this can have quite an impact. */
FILE_ENTRY_BLENDERLIB_NO_PREVIEW = 1 << 3,
};
/** \} */