[Bf-blender-cvs] [0fd1e6a5f43] master: T90908: Reduce loading times when extracting thumbnails from Blendfiles.

Jeroen Bakker noreply at git.blender.org
Wed Aug 25 15:59:45 CEST 2021


Commit: 0fd1e6a5f43df8b0f5382c07975c0d031bbbb506
Author: Jeroen Bakker
Date:   Wed Aug 25 14:15:57 2021 +0200
Branches: master
https://developer.blender.org/rB0fd1e6a5f43df8b0f5382c07975c0d031bbbb506

T90908: Reduce loading times when extracting thumbnails from Blendfiles.

Previously when loading an thumbnails for an asset the whole file was
read. Reason this was done was perhaps a future idea to load
all thumbnails inside a blendfile in a single go. This was never implemented
and currently unneeded disk and cpu cycles was spend with finding out what
preview to load.

This patch adds an early break when the thumbnail that the caller is
interested in has been found. This improves the thumbnail extraction
when looking into large files.

Reviewed By: mont29

Maniphest Tasks: T90908

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

===================================================================

M	source/blender/blenloader/BLO_readfile.h
M	source/blender/blenloader/intern/readblenentry.c
M	source/blender/imbuf/intern/thumbs_blend.c

===================================================================

diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index dbdb181281a..4b7f29dd7dc 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -172,6 +172,9 @@ struct LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh,
                                                     int ofblocktype,
                                                     int *r_tot_info_items);
 struct LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_tot_prev);
+struct PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh,
+                                                        int ofblocktype,
+                                                        const char *name);
 struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh);
 
 void BLO_blendhandle_close(BlendHandle *bh);
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 44a26b9bf85..f67ff0f7ac7 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -216,6 +216,96 @@ LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh,
   return infos;
 }
 
+/**
+ * Read the preview rects and store in `result`.
+ *
+ * `bhead` should point to the block that sourced the `preview_from_file`
+ *     parameter.
+ * `bhead` parameter is consumed. The correct bhead pointing to the next bhead in the file after
+ * the preview rects is returned by this function.
+ * \param fd: The filedata to read the data from.
+ * \param bhead: should point to the block that sourced the `preview_from_file parameter`.
+ *               bhead is consumed. the new bhead is returned by this function.
+ * \param result: the Preview Image where the preview rect will be stored.
+ * \param preview_from_file: The read PreviewImage where the bhead points to. The rects of this
+ * \return PreviewImage or NULL when no preview Images have been found. Caller owns the returned
+ */
+static BHead *blo_blendhandle_read_preview_rects(FileData *fd,
+                                                 BHead *bhead,
+                                                 PreviewImage *result,
+                                                 const PreviewImage *preview_from_file)
+{
+  for (int preview_index = 0; preview_index < NUM_ICON_SIZES; preview_index++) {
+    if (preview_from_file->rect[preview_index] && preview_from_file->w[preview_index] &&
+        preview_from_file->h[preview_index]) {
+      bhead = blo_bhead_next(fd, bhead);
+      BLI_assert((preview_from_file->w[preview_index] * preview_from_file->h[preview_index] *
+                  sizeof(uint)) == bhead->len);
+      result->rect[preview_index] = BLO_library_read_struct(fd, bhead, "PreviewImage Icon Rect");
+    }
+    else {
+      /* This should not be needed, but can happen in 'broken' .blend files,
+       * better handle this gracefully than crashing. */
+      BLI_assert(preview_from_file->rect[preview_index] == NULL &&
+                 preview_from_file->w[preview_index] == 0 &&
+                 preview_from_file->h[preview_index] == 0);
+      result->rect[preview_index] = NULL;
+      result->w[preview_index] = result->h[preview_index] = 0;
+    }
+    BKE_previewimg_finish(result, preview_index);
+  }
+
+  return bhead;
+}
+
+/**
+ * Get the PreviewImage of a single data block in a file.
+ * (e.g. all the scene previews in a file).
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param name: Name of the block without the ID_ prefix, to read the preview image from.
+ * \return PreviewImage or NULL when no preview Images have been found. Caller owns the returned
+ */
+PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh,
+                                                 int ofblocktype,
+                                                 const char *name)
+{
+  FileData *fd = (FileData *)bh;
+  bool looking = false;
+  const int sdna_preview_image = DNA_struct_find_nr(fd->filesdna, "PreviewImage");
+
+  for (BHead *bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
+    if (bhead->code == DATA) {
+      if (looking && bhead->SDNAnr == sdna_preview_image) {
+        PreviewImage *preview_from_file = BLO_library_read_struct(fd, bhead, "PreviewImage");
+
+        if (preview_from_file == NULL) {
+          break;
+        }
+
+        PreviewImage *result = MEM_dupallocN(preview_from_file);
+        bhead = blo_blendhandle_read_preview_rects(fd, bhead, result, preview_from_file);
+        MEM_freeN(preview_from_file);
+        return result;
+      }
+    }
+    else if (looking || bhead->code == ENDB) {
+      /* We were looking for a preview image, but didn't find any belonging to block. So it doesn't
+       * exist. */
+      break;
+    }
+    else if (bhead->code == ofblocktype) {
+      const char *idname = blo_bhead_id_name(fd, bhead);
+      if (STREQ(&idname[2], name)) {
+        looking = true;
+      }
+    }
+  }
+
+  return NULL;
+}
+
 /**
  * Gets the previews of all the data-blocks in a file of a certain type
  * (e.g. all the scene previews in a file).
@@ -264,33 +354,7 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_
 
           if (prv) {
             memcpy(new_prv, prv, sizeof(PreviewImage));
-            if (prv->rect[0] && prv->w[0] && prv->h[0]) {
-              bhead = blo_bhead_next(fd, bhead);
-              BLI_assert((new_prv->w[0] * new_prv->h[0] * sizeof(uint)) == bhead->len);
-              new_prv->rect[0] = BLO_library_read_struct(fd, bhead, "PreviewImage Icon Rect");
-            }
-            else {
-              /* This should not be needed, but can happen in 'broken' .blend files,
-               * better handle this gracefully than crashing. */
-              BLI_assert(prv->rect[0] == NULL && prv->w[0] == 0 && prv->h[0] == 0);
-              new_prv->rect[0] = NULL;
-              new_prv->w[0] = new_prv->h[0] = 0;
-            }
-            BKE_previewimg_finish(new_prv, 0);
-
-            if (prv->rect[1] && prv->w[1] && prv->h[1]) {
-              bhead = blo_bhead_next(fd, bhead);
-              BLI_assert((new_prv->w[1] * new_prv->h[1] * sizeof(uint)) == bhead->len);
-              new_prv->rect[1] = BLO_library_read_struct(fd, bhead, "PreviewImage Image Rect");
-            }
-            else {
-              /* This should not be needed, but can happen in 'broken' .blend files,
-               * better handle this gracefully than crashing. */
-              BLI_assert(prv->rect[1] == NULL && prv->w[1] == 0 && prv->h[1] == 0);
-              new_prv->rect[1] = NULL;
-              new_prv->w[1] = new_prv->h[1] = 0;
-            }
-            BKE_previewimg_finish(new_prv, 1);
+            bhead = blo_blendhandle_read_preview_rects(fd, bhead, new_prv, prv);
             MEM_freeN(prv);
           }
         }
diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c
index 878aa44f0d9..085620cb785 100644
--- a/source/blender/imbuf/intern/thumbs_blend.c
+++ b/source/blender/imbuf/intern/thumbs_blend.c
@@ -41,53 +41,29 @@
 
 #include "MEM_guardedalloc.h"
 
+/* NOTE: we should handle all previews for a same group at once, would avoid reopening
+ * `.blend` file for each and every ID. However, this adds some complexity,
+ * so keep it for later. */
 static ImBuf *imb_thumb_load_from_blend_id(const char *blen_path,
                                            const char *blen_group,
                                            const char *blen_id)
 {
   ImBuf *ima = NULL;
-  LinkNode *ln, *names, *lp, *previews = NULL;
   BlendFileReadReport bf_reports = {.reports = NULL};
-  struct BlendHandle *libfiledata = BLO_blendhandle_from_file(blen_path, &bf_reports);
-  int idcode = BKE_idtype_idcode_from_name(blen_group);
-  int i, nprevs, nnames;
 
+  struct BlendHandle *libfiledata = BLO_blendhandle_from_file(blen_path, &bf_reports);
   if (libfiledata == NULL) {
     return NULL;
   }
 
-  /* NOTE: we should handle all previews for a same group at once, would avoid reopening
-   * `.blend` file for each and every ID. However, this adds some complexity,
-   * so keep it for later. */
-  names = BLO_blendhandle_get_datablock_names(libfiledata, idcode, false, &nnames);
-  previews = BLO_blendhandle_get_previews(libfiledata, idcode, &nprevs);
-
+  int idcode = BKE_idtype_idcode_from_name(blen_group);
+  PreviewImage *preview = BLO_blendhandle_get_preview_for_id(libfiledata, idcode, blen_id);
   BLO_blendhandle_close(libfiledata);
 
-  if (!previews || (nnames != nprevs)) {
-    if (previews != 0) {
-      /* No previews at all is not a bug! */
-      printf("%s: error, found %d items, %d previews\n", __func__, nnames, nprevs);
-    }
-    BLI_linklist_free(previews, BKE_previewimg_freefunc);
-    BLI_linklist_freeN(names);
-    return NULL;
+  if (preview) {
+    ima = BKE_previewimg_to_imbuf(preview, ICON_SIZE_PREVIEW);
+    BKE_previewimg_freefunc(preview);
   }
-
-  for (i = 0, ln = names, lp = previews; i < nnames; i++, ln = ln->next, lp = lp->next) {
-    const char *blockname = ln->link;
-    PreviewImage *img = lp->link;
-
-    if (STREQ(blockname, blen_id)) {
-      if (img) {
-        ima = BKE_previewimg_to_imbuf(img, ICON_SIZE_PREVIEW);
-      }
-      break;
-    }
-  }
-
-  BLI_linklist_free(previews, BKE_previewimg_freefunc);
-  BLI_linklist_freeN(names);
   return ima;
 }



More information about the Bf-blender-cvs mailing list