[Bf-blender-cvs] [731c1be92a2] asset-browser-grid-view: Speedup preview icon loading

Julian Eisel noreply at git.blender.org
Thu Feb 17 21:42:27 CET 2022


Commit: 731c1be92a2e0a8ca4379fe3f588fae864f21d36
Author: Julian Eisel
Date:   Thu Feb 17 21:41:22 2022 +0100
Branches: asset-browser-grid-view
https://developer.blender.org/rB731c1be92a2e0a8ca4379fe3f588fae864f21d36

Speedup preview icon loading

Significantly speeds up loading of previews, not just for assets but also
Python loaded custom previews. Patch will be submitted for master.

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

M	source/blender/editors/include/ED_render.h
M	source/blender/editors/interface/interface_icons.c
M	source/blender/editors/render/render_preview.cc
M	source/blender/windowmanager/WM_api.h

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

diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index e1b6a935d6d..ee40cc75e1e 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -24,6 +24,7 @@ struct Scene;
 struct ScrArea;
 struct bContext;
 struct bScreen;
+struct PreviewImage;
 struct wmWindow;
 struct wmWindowManager;
 
@@ -87,16 +88,13 @@ void ED_preview_shader_job(const struct bContext *C,
                            ePreviewRenderMethod method);
 void ED_preview_icon_render(const struct bContext *C,
                             struct Scene *scene,
+                            struct PreviewImage *prv_img,
                             struct ID *id,
-                            unsigned int *rect,
-                            int sizex,
-                            int sizey);
+                            enum eIconSizes icon_size);
 void ED_preview_icon_job(const struct bContext *C,
-                         void *owner,
+                         struct PreviewImage *prv_img,
                          struct ID *id,
-                         unsigned int *rect,
-                         int sizex,
-                         int sizey,
+                         enum eIconSizes icon_size,
                          bool delay);
 
 void ED_preview_restart_queue_free(void);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index e277aa2e629..7a86b42f70b 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1399,19 +1399,17 @@ static void icon_set_image(const bContext *C,
 
   const bool delay = prv_img->rect[size] != NULL;
   icon_create_rect(prv_img, size);
-  prv_img->flag[size] |= PRV_RENDERING;
 
   if (use_job && (!id || BKE_previewimg_id_supports_jobs(id))) {
     /* Job (background) version */
-    ED_preview_icon_job(
-        C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size], delay);
+    ED_preview_icon_job(C, prv_img, id, size, delay);
   }
   else {
     if (!scene) {
       scene = CTX_data_scene(C);
     }
     /* Immediate version */
-    ED_preview_icon_render(C, scene, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]);
+    ED_preview_icon_render(C, scene, prv_img, id, size);
   }
 }
 
diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc
index 6aaf551a88a..6aa67c4bc49 100644
--- a/source/blender/editors/render/render_preview.cc
+++ b/source/blender/editors/render/render_preview.cc
@@ -10,6 +10,7 @@
 #include <cmath>
 #include <cstdlib>
 #include <cstring>
+#include <list>
 
 #ifndef WIN32
 #  include <unistd.h>
@@ -1370,89 +1371,73 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
   ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
 
   if (sp->pr_method == PR_ICON_DEFERRED) {
-    PreviewImage *prv = static_cast<PreviewImage *>(sp->owner);
-    ImBuf *thumb;
-    char *deferred_data = static_cast<char *>(PRV_DEFERRED_DATA(prv));
-    ThumbSource source = static_cast<ThumbSource>(deferred_data[0]);
-    char *path = &deferred_data[1];
-
-    // printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path);
-
-    thumb = IMB_thumb_manage(path, THB_LARGE, source);
-
-    if (thumb) {
-      /* PreviewImage assumes premultiplied alhpa... */
-      IMB_premultiply_alpha(thumb);
-
-      icon_copy_rect(thumb, sp->sizex, sp->sizey, sp->pr_rect);
-      IMB_freeImBuf(thumb);
-    }
+    BLI_assert_unreachable();
+    return;
   }
-  else {
-    ID *id = sp->id;
-    short idtype = GS(id->name);
 
-    BLI_assert(id != nullptr);
-
-    if (idtype == ID_IM) {
-      Image *ima = (Image *)id;
-      ImBuf *ibuf = nullptr;
-      ImageUser iuser;
-      BKE_imageuser_default(&iuser);
+  ID *id = sp->id;
+  short idtype = GS(id->name);
 
-      if (ima == nullptr) {
-        return;
-      }
+  BLI_assert(id != nullptr);
 
-      /* setup dummy image user */
-      iuser.framenr = 1;
-      iuser.scene = sp->scene;
-
-      /* NOTE(@elubie): this needs to be changed: here image is always loaded if not
-       * already there. Very expensive for large images. Need to find a way to
-       * only get existing `ibuf`. */
-      ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
-      if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
-        BKE_image_release_ibuf(ima, ibuf, nullptr);
-        return;
-      }
+  if (idtype == ID_IM) {
+    Image *ima = (Image *)id;
+    ImBuf *ibuf = nullptr;
+    ImageUser iuser;
+    BKE_imageuser_default(&iuser);
 
-      icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);
+    if (ima == nullptr) {
+      return;
+    }
 
-      *do_update = true;
+    /* setup dummy image user */
+    iuser.framenr = 1;
+    iuser.scene = sp->scene;
 
+    /* NOTE(@elubie): this needs to be changed: here image is always loaded if not
+     * already there. Very expensive for large images. Need to find a way to
+     * only get existing `ibuf`. */
+    ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
+    if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
       BKE_image_release_ibuf(ima, ibuf, nullptr);
+      return;
     }
-    else if (idtype == ID_BR) {
-      Brush *br = (Brush *)id;
 
-      br->icon_imbuf = icon_preview_imbuf_from_brush(br);
+    icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);
 
-      memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(uint));
+    *do_update = true;
 
-      if (!(br->icon_imbuf) || !(br->icon_imbuf->rect)) {
-        return;
-      }
+    BKE_image_release_ibuf(ima, ibuf, nullptr);
+  }
+  else if (idtype == ID_BR) {
+    Brush *br = (Brush *)id;
 
-      icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect);
+    br->icon_imbuf = icon_preview_imbuf_from_brush(br);
 
-      *do_update = true;
-    }
-    else if (idtype == ID_SCR) {
-      bScreen *screen = (bScreen *)id;
+    memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(uint));
 
-      ED_screen_preview_render(screen, sp->sizex, sp->sizey, sp->pr_rect);
-      *do_update = true;
+    if (!(br->icon_imbuf) || !(br->icon_imbuf->rect)) {
+      return;
     }
-    else {
-      /* re-use shader job */
-      shader_preview_startjob(customdata, stop, do_update);
 
-      /* world is rendered with alpha=0, so it wasn't displayed
-       * this could be render option for sky to, for later */
-      if (idtype == ID_WO) {
-        set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
-      }
+    icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect);
+
+    *do_update = true;
+  }
+  else if (idtype == ID_SCR) {
+    bScreen *screen = (bScreen *)id;
+
+    ED_screen_preview_render(screen, sp->sizex, sp->sizey, sp->pr_rect);
+    *do_update = true;
+  }
+  else {
+    /* re-use shader job */
+    shader_preview_startjob(customdata, stop, do_update);
+
+    /* world is rendered with alpha=0, so it wasn't displayed
+     * this could be render option for sky to, for later */
+    if (idtype == ID_WO) {
+      set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
     }
   }
 }
@@ -1670,6 +1655,198 @@ static void icon_preview_endjob(void *customdata)
   }
 }
 
+/**
+ * Background job to manage requests for deferred loading of previews from the hard drive.
+ *
+ * Launches a single job to manage all incoming preview requests as tasks (so possibly using
+ * further threads). The job is kept running until all preview requests are done loading (or it's
+ * otherwise aborted, e.g. by closing Blender).
+ *
+ * Note that this will use the OS thumbnail cache, i.e. load a preview from there or add it if not
+ * there yet. These to cases may lead to different performance.
+ */
+class PreviewLoadJob {
+  struct RequestedPreview {
+    PreviewImage *preview;
+    /** Requested size. */
+    eIconSizes icon_size;
+  };
+
+  /** The previews that are still to be loaded. */
+  ThreadQueue *todo_queue_; /* RequestedPreview * */
+  /** All unfinished preview requests, #update_fn() calls #finish_preview_request() on loaded
+   * previews and removes them from this list. Only access from the main thread! */
+  std::list<struct RequestedPreview> requested_previews_;
+
+ public:
+  PreviewLoadJob();
+  ~PreviewLoadJob();
+
+  static PreviewLoadJob &ensure_job(wmWindowManager *, wmWindow *);
+  static void load_jobless(PreviewImage *, eIconSizes);
+
+  void push_load_request(PreviewImage *, eIconSizes);
+
+ private:
+  static void run_fn(void *, short *, short *, float *);
+  static void update_fn(void *);
+  static void end_fn(void *);
+  static void free_fn(void *);
+
+  /** Mark a single requested preview as being done, remove the request. */
+  static void finish_request(RequestedPreview &);
+};
+
+PreviewLoadJob::PreviewLoadJob() : todo_queue_(BLI_thread_queue_init())
+{
+}
+
+PreviewLoadJob::~PreviewLoadJob()
+{
+  BLI_thread_queue_free(todo_queue_);
+}
+
+PreviewLoadJob &PreviewLoadJob::ensure_job(wmWindowManager *wm, wmWindow *win)
+{
+  wmJob *wm_job = WM_jobs_get(wm, win, nullptr, "Load Previews", 0, WM_JOB_TYPE_LOAD_PREVIEW);
+
+  if (!WM_jobs_is_running(wm_job)) {
+    PreviewLoadJob *job_data = MEM_new<PreviewLoadJob>("PreviewLoadJobData");
+
+    WM_jobs_customdata_set(wm_job, job_data, free_fn);
+    WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
+    WM_jobs_callbacks(wm_job, run_fn, nullptr, update_fn, end_fn);
+
+    WM_jobs_start(wm, wm_job);
+  }
+
+  return *reinterpret_cast<PreviewLoadJob *>(WM_jobs_customdata_get(wm_job));
+}
+
+void PreviewLoadJob::load_jobless(PreviewImage *preview, const eIconSizes icon_size)
+{
+  PreviewLoadJob job_data{};
+
+  job_data.push_load_request(preview, icon_size);
+
+  short stop = 0, do_update = 0;
+  float progress = 0;
+  run_fn(&job_data, &stop, &do_update, &progress);
+  update_fn(&job_data);
+  end_fn(&job_data);
+}
+
+void PreviewLoadJob::push_load_request(PreviewImage *preview, const eIconSizes icon_size)
+{
+  BLI_assert(preview->tag & PRV_TAG_DEFFERED);
+  RequestedPreview requested_preview{};
+  reques

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list