Let UI do lazy-loading of previews, rather than file-list cache

This is an important step to decouple the asset-views from the file browser
backend. One downside is that the UI preview loading is much slower than the
file browser one, however, I'm pretty sure I know how to address this.
This commit is contained in:
Julian Eisel 2022-02-16 17:59:27 +01:00
parent ef58467594
commit 39eab45c8e
11 changed files with 124 additions and 87 deletions

View File

@ -27,7 +27,6 @@ const char *ED_asset_handle_get_identifier(const struct AssetHandle *asset);
struct AssetMetaData *ED_asset_handle_get_metadata(const struct AssetHandle *asset);
struct ID *ED_asset_handle_get_local_id(const struct AssetHandle *asset);
ID_Type ED_asset_handle_get_id_type(const struct AssetHandle *asset);
int ED_asset_handle_get_preview_icon_id(const struct AssetHandle *asset);
void ED_asset_handle_get_full_library_path(const struct bContext *C,
const struct AssetLibraryReference *asset_library_ref,
const struct AssetHandle *asset,

View File

@ -51,6 +51,10 @@ void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new);
*/
void ED_assetlist_storage_exit(void);
struct PreviewImage *ED_assetlist_asset_preview_request(
const struct AssetLibraryReference *library_reference, AssetHandle *asset_handle);
int ED_assetlist_asset_preview_icon_id_request(const AssetLibraryReference *library_reference,
AssetHandle *asset_handle);
struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle);
const char *ED_assetlist_library_path(const struct AssetLibraryReference *library_reference);

View File

@ -38,11 +38,6 @@ ID_Type ED_asset_handle_get_id_type(const AssetHandle *asset)
return static_cast<ID_Type>(asset->file_data->blentype);
}
int ED_asset_handle_get_preview_icon_id(const AssetHandle *asset)
{
return asset->file_data->preview_icon_id;
}
void ED_asset_handle_get_full_library_path(const bContext *C,
const AssetLibraryReference *asset_library_ref,
const AssetHandle *asset,

View File

@ -20,6 +20,7 @@
#include "DNA_space_types.h"
#include "BKE_icons.h"
#include "BKE_preferences.h"
#include "ED_fileselect.h"
@ -99,8 +100,10 @@ class PreviewTimer {
class AssetList : NonCopyable {
FileListWrapper filelist_;
/** Storage for asset handles, items are lazy-created on request. */
mutable Map<const FileDirEntry *, AssetHandle> asset_handle_map_;
/** Storage for asset handles, items are lazy-created on request.
* Asset handles are stored as a pointer here, to ensure a consistent memory address (address
* inside the map changes as the map changes). */
mutable Map<const FileDirEntry *, std::unique_ptr<AssetHandle>> asset_handle_map_;
AssetLibraryReference library_ref_;
PreviewTimer previews_timer_;
@ -207,7 +210,8 @@ bool AssetList::needsRefetch() const
AssetHandle &AssetList::asset_handle_from_file(const FileDirEntry &file) const
{
return asset_handle_map_.lookup_or_add(&file, AssetHandle{&file});
return *asset_handle_map_.lookup_or_add(&file,
std::make_unique<AssetHandle>(AssetHandle{&file}));
}
void AssetList::iterate(AssetListIterFn fn) const
@ -529,6 +533,37 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C,
return path;
}
PreviewImage *ED_assetlist_asset_preview_request(const AssetLibraryReference *library_reference,
AssetHandle *asset_handle)
{
if (asset_handle->preview) {
return asset_handle->preview;
}
if (ID *local_id = ED_asset_handle_get_local_id(asset_handle)) {
asset_handle->preview = BKE_previewimg_id_get(local_id);
}
else {
const char *asset_identifier = ED_asset_handle_get_identifier(asset_handle);
const int source = filelist_preview_source_get(asset_handle->file_data->typeflag);
const std::string asset_path = ED_assetlist_asset_filepath_get(
nullptr, *library_reference, *asset_handle);
asset_handle->preview = BKE_previewimg_cached_thumbnail_read(
asset_identifier, asset_path.c_str(), source, false);
}
return asset_handle->preview;
}
int ED_assetlist_asset_preview_icon_id_request(const AssetLibraryReference *library_reference,
AssetHandle *asset_handle)
{
PreviewImage *preview = ED_assetlist_asset_preview_request(library_reference, asset_handle);
ID *local_id = ED_asset_handle_get_local_id(asset_handle);
return BKE_icon_preview_ensure(local_id, preview);
}
ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle)
{
ImBuf *imbuf = filelist_file_getimage(asset_handle->file_data);

View File

@ -459,21 +459,21 @@ void PreviewGridItem::build_grid_tile(uiLayout &layout) const
{
const GridViewStyle &style = get_view().get_style();
uiBlock *block = uiLayoutGetBlock(&layout);
uiBut *but = uiDefIconTextBut(block,
UI_BTYPE_PREVIEW_TILE,
0,
preview_icon_id,
label_.c_str(),
0,
0,
style.tile_width,
style.tile_height,
nullptr,
0,
0,
0,
0,
"");
uiBut *but = uiDefBut(block,
UI_BTYPE_PREVIEW_TILE,
0,
label_.c_str(),
0,
0,
style.tile_width,
style.tile_height,
nullptr,
0,
0,
0,
0,
"");
ui_def_but_icon(but,
preview_icon_id,
/* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */

View File

@ -53,14 +53,15 @@ static void asset_view_item_but_drag_set(uiBut *but,
if (blend_path[0]) {
ImBuf *imbuf = ED_assetlist_asset_image_get(asset_handle);
UI_but_drag_set_asset(but,
asset_handle,
BLI_strdup(blend_path),
ED_asset_handle_get_metadata(asset_handle),
FILE_ASSET_IMPORT_APPEND,
ED_asset_handle_get_preview_icon_id(asset_handle),
imbuf,
1.0f);
UI_but_drag_set_asset(
but,
asset_handle,
BLI_strdup(blend_path),
ED_asset_handle_get_metadata(asset_handle),
FILE_ASSET_IMPORT_APPEND,
ED_assetlist_asset_preview_icon_id_request(&list_data->asset_library_ref, asset_handle),
imbuf,
1.0f);
}
}
@ -86,25 +87,27 @@ static void asset_view_draw_item(uiList *ui_list,
const bool show_names = list_data->show_names;
const int size_x = UI_preview_tile_size_x();
const int size_y = show_names ? UI_preview_tile_size_y() : UI_preview_tile_size_y_no_label();
uiBut *but = uiDefIconTextBut(block,
UI_BTYPE_PREVIEW_TILE,
0,
ED_asset_handle_get_preview_icon_id(asset_handle),
show_names ? ED_asset_handle_get_name(asset_handle) : "",
0,
0,
size_x,
size_y,
nullptr,
0,
0,
0,
0,
"");
ui_def_but_icon(but,
ED_asset_handle_get_preview_icon_id(asset_handle),
/* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
uiBut *but = uiDefIconTextBut(
block,
UI_BTYPE_PREVIEW_TILE,
0,
ED_assetlist_asset_preview_icon_id_request(&list_data->asset_library_ref, asset_handle),
show_names ? ED_asset_handle_get_name(asset_handle) : "",
0,
0,
size_x,
size_y,
nullptr,
0,
0,
0,
0,
"");
ui_def_but_icon(
but,
ED_assetlist_asset_preview_icon_id_request(&list_data->asset_library_ref, asset_handle),
/* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
if (!ui_list->dyn_data->custom_drag_optype) {
asset_view_item_but_drag_set(but, list_data, asset_handle);
}

View File

@ -19,8 +19,6 @@
*/
#include "BKE_context.h"
#include <iostream>
#include "DNA_asset_types.h"
#include "RNA_access.h"
@ -52,7 +50,7 @@ void AssetGridView::build_items()
{
int idx = 0;
ED_assetlist_iterate(asset_library_ref_, [this, &idx](AssetHandle &asset) {
AssetGridViewItem &item = add_item<AssetGridViewItem>(asset);
AssetGridViewItem &item = add_item<AssetGridViewItem>(asset_library_ref_, asset);
item.set_is_active_fn([this, idx]() -> bool {
return idx == RNA_property_int_get(&active_asset_idx_owner_, &active_asset_idx_prop_);
@ -74,18 +72,19 @@ bool AssetGridView::listen(const wmNotifier &notifier) const
/* ---------------------------------------------------------------------- */
AssetGridViewItem::AssetGridViewItem(AssetHandle &asset)
AssetGridViewItem::AssetGridViewItem(const AssetLibraryReference &asset_library_ref,
AssetHandle &asset)
: ui::PreviewGridItem(ED_asset_handle_get_name(&asset),
ED_asset_handle_get_preview_icon_id(&asset)),
asset_(asset),
asset_identifier(ED_asset_handle_get_identifier(&asset))
ED_assetlist_asset_preview_icon_id_request(&asset_library_ref, &asset)),
asset_(asset)
{
}
bool AssetGridViewItem::matches(const ui::AbstractGridViewItem &other) const
{
const AssetGridViewItem &other_item = dynamic_cast<const AssetGridViewItem &>(other);
return StringRef(asset_identifier) == StringRef(other_item.asset_identifier);
return StringRef(ED_asset_handle_get_identifier(&asset_)) ==
StringRef(ED_asset_handle_get_identifier(&other_item.asset_));
}
AssetHandle &AssetGridViewItem::get_asset()

View File

@ -54,10 +54,9 @@ class AssetGridView : public blender::ui::AbstractGridView {
class AssetGridViewItem : public ui::PreviewGridItem {
AssetHandle &asset_;
std::string asset_identifier;
public:
AssetGridViewItem(AssetHandle &);
AssetGridViewItem(const AssetLibraryReference &asset_library_ref, AssetHandle &);
bool matches(const AbstractGridViewItem &other) const override;

View File

@ -1159,10 +1159,9 @@ void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
filelist->indexer = indexer;
}
void filelist_set_asset_catalog_filter_options(
FileList *filelist,
AssetCatalogFilterMode catalog_visibility,
const bUUID *catalog_id)
void filelist_set_asset_catalog_filter_options(FileList *filelist,
AssetCatalogFilterMode catalog_visibility,
const bUUID *catalog_id)
{
if (!filelist->filter_data.asset_catalog_filter) {
/* There's no filter data yet. */
@ -1594,34 +1593,37 @@ static int filelist_intern_free_main_files(FileListIntern *filelist_intern)
return removed_counter;
}
int /* ThumbSource */ filelist_preview_source_get(int /* eFileSel_File_Types */ file_type)
{
if (file_type & FILE_TYPE_IMAGE) {
return THB_SOURCE_IMAGE;
}
else if (file_type & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
return THB_SOURCE_BLEND;
}
else if (file_type & FILE_TYPE_MOVIE) {
return THB_SOURCE_MOVIE;
}
else if (file_type & FILE_TYPE_FTFONT) {
return THB_SOURCE_FONT;
}
else {
BLI_assert_unreachable();
return 0;
}
}
static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata)
{
FileListEntryCache *cache = BLI_task_pool_user_data(pool);
FileListEntryPreviewTaskData *preview_taskdata = taskdata;
FileListEntryPreview *preview = preview_taskdata->preview;
ThumbSource source = 0;
ThumbSource source = filelist_preview_source_get(preview->flags);
// printf("%s: Start (%d)...\n", __func__, threadid);
// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
BLI_assert(preview->flags &
(FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER |
FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
if (preview->flags & FILE_TYPE_IMAGE) {
source = THB_SOURCE_IMAGE;
}
else if (preview->flags &
(FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
source = THB_SOURCE_BLEND;
}
else if (preview->flags & FILE_TYPE_MOVIE) {
source = THB_SOURCE_MOVIE;
}
else if (preview->flags & FILE_TYPE_FTFONT) {
source = THB_SOURCE_FONT;
}
IMB_thumb_path_lock(preview->path);
/* Always generate biggest preview size for now, it's simpler and avoids having to re-generate

View File

@ -68,10 +68,9 @@ void filelist_setindexer(struct FileList *filelist, const struct FileIndexerType
* \param catalog_id: The catalog that should be filtered by if \a catalog_visibility is
* #ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG. May be NULL otherwise.
*/
void filelist_set_asset_catalog_filter_options(
struct FileList *filelist,
AssetCatalogFilterMode catalog_visibility,
const struct bUUID *catalog_id);
void filelist_set_asset_catalog_filter_options(struct FileList *filelist,
AssetCatalogFilterMode catalog_visibility,
const struct bUUID *catalog_id);
void filelist_tag_needs_filtering(struct FileList *filelist);
void filelist_filter(struct FileList *filelist);
/**
@ -87,6 +86,7 @@ struct ImBuf *filelist_file_getimage(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image_ex(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image(struct FileList *filelist, int index);
int filelist_geticon(struct FileList *filelist, int index, bool is_main);
int /* ThumbSource */ filelist_preview_source_get(int /* eFileSel_File_Types */ file_type);
struct FileList *filelist_new(short type);
void filelist_settype(struct FileList *filelist, short type);

View File

@ -122,6 +122,7 @@ typedef struct AssetLibraryReference {
#
typedef struct AssetHandle {
const struct FileDirEntry *file_data;
struct PreviewImage *preview;
} AssetHandle;
#ifdef __cplusplus