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:
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
Reference in New Issue
Block a user