Fix: UI: Many unneeded assets in file-list cache for asset UIs

Partial fix for #129267.

Avoid creating an entry in the file list cache for every asset when iterating
over the available assets. For this, allow passing a pre-filter function to the
asset iterator, to filter based on `AssetRepresentation` data. The asset shelf
can then pre-filter based on asset type and the active catalog.

Really, the cached file entry is only needed to access the preview image of the
asset, so it can be avoided most of the time.

While this should still be solved properly as outlined in #122439, this is
a general improvement and fix the mentioned report in a minimal way.

Was hoping this would be sufficient to fix #129267, but the whole of
!130105 will be needed.

Pull Request: https://projects.blender.org/blender/blender/pulls/130166
This commit is contained in:
Julian Eisel
2024-11-13 14:13:45 +01:00
committed by Julian Eisel
parent 5f52c5ce46
commit 0f8e4b3516
3 changed files with 61 additions and 37 deletions

View File

@@ -46,8 +46,18 @@ using AssetListIterFn = FunctionRef<bool(asset_system::AssetRepresentation &)>;
/**
* \warning Never keep the asset handle passed to \a fn outside of \a fn's scope. While iterating,
* the file data wrapped by the asset handle can be freed, since the file cache has a maximum size.
* \note It is recommended to prefilter assets using \a prefilter_fn, which avoids populating the
* file cache with files that will not end up being relevant. With 1000s of assets that can make a
* difference, since often only a small subset needs to be displayed.
*/
void iterate(const AssetLibraryReference &library_reference,
AssetListHandleIterFn fn,
FunctionRef<bool(asset_system::AssetRepresentation &)> prefilter_fn = nullptr);
/**
* \note This override avoids the file caching system, so it's more performant and avoids pitfals
* from the other override. Prefer this when access to #AssetRepresentation is enough, and no
* #AssetHandle is needed.
*/
void iterate(const AssetLibraryReference &library_reference, AssetListHandleIterFn fn);
void iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn);
/**

View File

@@ -123,7 +123,8 @@ class AssetList : NonCopyable {
bool is_loaded() const;
bool is_asset_preview_loading(const AssetHandle &asset) const;
asset_system::AssetLibrary *asset_library() const;
void iterate(AssetListHandleIterFn fn) const;
void iterate(AssetListHandleIterFn fn,
FunctionRef<bool(asset_system::AssetRepresentation &)> prefilter_fn) const;
void iterate(AssetListIterFn fn) const;
int size() const;
void tag_main_data_dirty() const;
@@ -204,17 +205,24 @@ asset_system::AssetLibrary *AssetList::asset_library() const
return reinterpret_cast<asset_system::AssetLibrary *>(filelist_asset_library(filelist_));
}
void AssetList::iterate(AssetListHandleIterFn fn) const
void AssetList::iterate(AssetListHandleIterFn fn,
FunctionRef<bool(asset_system::AssetRepresentation &)> prefilter_fn) const
{
FileList *files = filelist_;
int numfiles = filelist_files_ensure(files);
for (int i = 0; i < numfiles; i++) {
FileDirEntry *file = filelist_file(files, i);
if ((file->typeflag & FILE_TYPE_ASSET) == 0) {
asset_system::AssetRepresentation *asset = filelist_entry_get_asset_representation(files, i);
if (!asset) {
continue;
}
if (prefilter_fn && !prefilter_fn(*asset)) {
continue;
}
FileDirEntry *file = filelist_file(files, i);
AssetHandle asset_handle = {file};
if (!fn(asset_handle)) {
/* If the callback returns false, we stop iterating. */
@@ -495,11 +503,13 @@ bool storage_has_list_for_library(const AssetLibraryReference *library_reference
return lookup_list(*library_reference) != nullptr;
}
void iterate(const AssetLibraryReference &library_reference, AssetListHandleIterFn fn)
void iterate(const AssetLibraryReference &library_reference,
AssetListHandleIterFn fn,
FunctionRef<bool(asset_system::AssetRepresentation &)> prefilter_fn)
{
AssetList *list = lookup_list(library_reference);
if (list) {
list->iterate(fn);
list->iterate(fn, prefilter_fn);
}
}

View File

@@ -104,41 +104,45 @@ void AssetView::build_items()
return;
}
list::iterate(library_ref_, [&](AssetHandle asset_handle) {
const asset_system::AssetRepresentation *asset = handle_get_representation(&asset_handle);
list::iterate(
library_ref_,
[&](AssetHandle asset_handle) {
const asset_system::AssetRepresentation *asset = handle_get_representation(&asset_handle);
const bool show_names = (shelf_.settings.display_flag & ASSETSHELF_SHOW_NAMES);
if (shelf_.type->asset_poll && !shelf_.type->asset_poll(shelf_.type, asset)) {
return true;
}
const StringRef identifier = asset->library_relative_identifier();
const int preview_id = [&]() -> int {
if (list::asset_image_is_loading(&library_ref_, &asset_handle)) {
return ICON_TEMP;
}
return handle_get_preview_or_type_icon_id(&asset_handle);
}();
const AssetMetaData &asset_data = asset->get_metadata();
AssetViewItem &item = this->add_item<AssetViewItem>(
asset_handle, identifier, asset->get_name(), preview_id);
if (!show_names) {
item.hide_label();
}
if (shelf_.type->flag & ASSET_SHELF_TYPE_FLAG_NO_ASSET_DRAG) {
item.disable_asset_drag();
}
if (catalog_filter_ && !catalog_filter_->contains(asset_data.catalog_id)) {
/* Skip this asset. */
return true;
}
return true;
},
const bool show_names = (shelf_.settings.display_flag & ASSETSHELF_SHOW_NAMES);
/* prefilter_fn=*/
[&](asset_system::AssetRepresentation &asset) {
if (shelf_.type->asset_poll && !shelf_.type->asset_poll(shelf_.type, &asset)) {
return false;
}
const StringRef identifier = asset->library_relative_identifier();
const int preview_id = [&]() -> int {
if (list::asset_image_is_loading(&library_ref_, &asset_handle)) {
return ICON_TEMP;
}
return handle_get_preview_or_type_icon_id(&asset_handle);
}();
AssetViewItem &item = this->add_item<AssetViewItem>(
asset_handle, identifier, asset->get_name(), preview_id);
if (!show_names) {
item.hide_label();
}
if (shelf_.type->flag & ASSET_SHELF_TYPE_FLAG_NO_ASSET_DRAG) {
item.disable_asset_drag();
}
return true;
});
const AssetMetaData &asset_data = asset.get_metadata();
if (catalog_filter_ && !catalog_filter_->contains(asset_data.catalog_id)) {
/* Skip this asset. */
return false;
}
return true;
});
}
bool AssetView::begin_filtering(const bContext &C) const