[Bf-blender-cvs] [0e3ad1ccf4b] asset-browser: Asset Browser: Various changes for previews

Julian Eisel noreply at git.blender.org
Thu Dec 3 01:58:54 CET 2020


Commit: 0e3ad1ccf4b1df1c6426e6c5a49c2bfda9d9ffcd
Author: Julian Eisel
Date:   Wed Dec 2 18:11:11 2020 +0100
Branches: asset-browser
https://developer.blender.org/rB0e3ad1ccf4b1df1c6426e6c5a49c2bfda9d9ffcd

Asset Browser: Various changes for previews

* Operator to set a custom data-block preview. Copies an image from a selected path to the ID's preview buffer.
* Object preview support (threaded). Creates a localized copy of the object, creates a temporary main, scene, view-layer and depsgraph, uses the "Frame Selected" logic to place a camera in front of the object, and renders that offscreen.
* Support defining (not necessarily rendering) icons in threads. Needed so the File Browser can expose file previews with an icon-id to scripts.
** For that, ported the C++ to be able to use scope based mutex locks.
** Also support ImBuf icons.
* Tag previews as "unfinished" while they render in a thread, for the File Browser to dynamically load previews as they get finished.
* Better handle cases where threaded preview generation is requested, but the ID type doesn't support it (fallback to single threaded).

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

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

M	source/blender/blenkernel/BKE_icons.h
M	source/blender/blenkernel/CMakeLists.txt
R074	source/blender/blenkernel/intern/icons.c	source/blender/blenkernel/intern/icons.cc
M	source/blender/blenkernel/intern/object.c
M	source/blender/blenloader/intern/readblenentry.c
M	source/blender/editors/include/ED_util.h
M	source/blender/editors/include/ED_view3d.h
M	source/blender/editors/interface/interface_icons.c
M	source/blender/editors/render/render_preview.c
M	source/blender/editors/screen/screen_ops.c
M	source/blender/editors/space_view3d/view3d_utils.c
M	source/blender/editors/space_view3d/view3d_view.c
M	source/blender/editors/util/ed_util.c
M	source/blender/imbuf/intern/thumbs_blend.c
M	source/blender/makesdna/DNA_ID.h

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

diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 9452717539c..820de84a4aa 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -23,17 +23,26 @@
  * \ingroup bke
  *
  * Resizable Icons for Blender
+ *
+ * There is some thread safety for this API but it is rather weak. Registering or unregistering
+ * icons is thread safe, changing data of icons from multiple threads is not. Practically this
+ * should be fine since only the main thread modifies icons. Should that change, more locks or a
+ * different design need to be introduced.
  */
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#include "BLI_compiler_attrs.h"
+
 typedef void (*DrawInfoFreeFP)(void *drawinfo);
 
 enum {
   /** ID preview: obj is #ID. */
   ICON_DATA_ID = 0,
+  /** Arbitrary Image buffer: obj is #ImBuf */
+  ICON_DATA_IMBUF,
   /** Preview: obj is #PreviewImage */
   ICON_DATA_PREVIEW,
   /** 2D triangles: obj is #Icon_Geom */
@@ -44,6 +53,9 @@ enum {
   ICON_DATA_GPLAYER,
 };
 
+/**
+ * \note See comment at the top regarding thread safety.
+ */
 struct Icon {
   void *drawinfo;
   /**
@@ -93,6 +105,9 @@ int BKE_icon_gplayer_color_ensure(struct bGPDlayer *gpl);
 
 int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
 
+int BKE_icon_imbuf_create(struct ImBuf *ibuf) ATTR_WARN_UNUSED_RESULT;
+struct ImBuf *BKE_icon_imbuf_get_buffer(int icon_id) ATTR_WARN_UNUSED_RESULT;
+
 /* retrieve icon for id */
 struct Icon *BKE_icon_get(const int icon_id);
 
@@ -131,6 +146,9 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
 struct PreviewImage **BKE_previewimg_id_get_p(const struct ID *id);
 struct PreviewImage *BKE_previewimg_id_get(const struct ID *id);
 
+void BKE_previewimg_id_custom_set(struct ID *id, const char *path);
+
+bool BKE_previewimg_id_supports_jobs(const struct ID *id);
 
 /* free the preview image belonging to the id */
 void BKE_previewimg_id_free(struct ID *id);
@@ -148,6 +166,11 @@ struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id);
 
 void BKE_previewimg_ensure(struct PreviewImage *prv, const int size);
 
+struct ImBuf *BKE_previewimg_to_imbuf(struct PreviewImage *prv, const int size);
+
+void BKE_previewimg_finish(struct PreviewImage *prv, const int size);
+bool BKE_previewimg_is_finished(const struct PreviewImage *prv, const int size);
+
 struct PreviewImage *BKE_previewimg_cached_get(const char *name);
 
 struct PreviewImage *BKE_previewimg_cached_ensure(const char *name);
@@ -158,7 +181,8 @@ struct PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
                                                           bool force_update);
 
 void BKE_previewimg_cached_release(const char *name);
-void BKE_previewimg_cached_release_pointer(struct PreviewImage *prv);
+
+void BKE_previewimg_deferred_release(struct PreviewImage *prv);
 
 void BKE_previewimg_blend_write(struct BlendWriter *writer, const struct PreviewImage *prv);
 void BKE_previewimg_blend_read(struct BlendDataReader *reader, struct PreviewImage *prv);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index ae79bf43a55..150da8a368a 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -130,7 +130,7 @@ set(SRC
   intern/gpencil_geom.c
   intern/gpencil_modifier.c
   intern/hair.c
-  intern/icons.c
+  intern/icons.cc
   intern/icons_rasterize.c
   intern/idprop.c
   intern/idprop_utils.c
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.cc
similarity index 74%
rename from source/blender/blenkernel/intern/icons.c
rename to source/blender/blenkernel/intern/icons.cc
index 26a113b8b96..c5ca567ba46 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.cc
@@ -1,4 +1,4 @@
-/*
+/*
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
@@ -21,9 +21,10 @@
  * \ingroup bke
  */
 
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <mutex>
 
 #include "CLG_log.h"
 
@@ -46,6 +47,7 @@
 #include "BLI_string.h"
 #include "BLI_threads.h"
 #include "BLI_utildefines.h"
+#include "BLI_vector.hh"
 
 #include "BKE_global.h" /* only for G.background test */
 #include "BKE_icons.h"
@@ -61,6 +63,8 @@
 
 #include "BLO_read_write.h"
 
+#include "atomic_ops.h"
+
 /**
  * Only allow non-managed icons to be removed (by Python for eg).
  * Previews & ID's have their own functions to remove icons.
@@ -73,12 +77,18 @@ enum {
 
 static CLG_LogRef LOG = {"bke.icons"};
 
+/* Protected by gIconMutex. */
 static GHash *gIcons = NULL;
 
+/* Protected by gIconMutex. */
 static int gNextIconId = 1;
 
+/* Protected by gIconMutex. */
 static int gFirstIconId = 1;
 
+std::mutex gIconMutex;
+
+/* Not mutex-protected! */
 static GHash *gCachedPreviews = NULL;
 
 /* Queue of icons for deferred deletion. */
@@ -86,15 +96,16 @@ typedef struct DeferredIconDeleteNode {
   struct DeferredIconDeleteNode *next;
   int icon_id;
 } DeferredIconDeleteNode;
+/* Protected by gIconMutex. */
 static LockfreeLinkList g_icon_delete_queue;
 
 static void icon_free(void *val)
 {
-  Icon *icon = val;
+  Icon *icon = (Icon *)val;
 
   if (icon) {
     if (icon->obj_type == ICON_DATA_GEOM) {
-      struct Icon_Geom *obj = icon->obj;
+      struct Icon_Geom *obj = (struct Icon_Geom *)icon->obj;
       if (obj->mem) {
         /* coords & colors are part of this memory. */
         MEM_freeN((void *)obj->mem);
@@ -121,6 +132,12 @@ static void icon_free_data(int icon_id, Icon *icon)
   if (icon->obj_type == ICON_DATA_ID) {
     ((ID *)(icon->obj))->icon_id = 0;
   }
+  else if (icon->obj_type == ICON_DATA_IMBUF) {
+    ImBuf *imbuf = (ImBuf *)icon->obj;
+    if (imbuf) {
+      IMB_freeImBuf(imbuf);
+    }
+  }
   else if (icon->obj_type == ICON_DATA_PREVIEW) {
     ((PreviewImage *)(icon->obj))->icon_id = 0;
   }
@@ -131,7 +148,7 @@ static void icon_free_data(int icon_id, Icon *icon)
     ((struct Icon_Geom *)(icon->obj))->icon_id = 0;
   }
   else if (icon->obj_type == ICON_DATA_STUDIOLIGHT) {
-    StudioLight *sl = icon->obj;
+    StudioLight *sl = (StudioLight *)icon->obj;
     if (sl != NULL) {
       BKE_studiolight_unset_icon_id(sl, icon_id);
     }
@@ -141,19 +158,27 @@ static void icon_free_data(int icon_id, Icon *icon)
   }
 }
 
+static Icon *icon_ghash_lookup(int icon_id)
+{
+  std::scoped_lock lock(gIconMutex);
+  return (Icon *)BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id));
+}
+
 /* create an id for a new icon and make sure that ids from deleted icons get reused
  * after the integer number range is used up */
 static int get_next_free_id(void)
 {
-  BLI_assert(BLI_thread_is_main());
+  std::scoped_lock lock(gIconMutex);
   int startId = gFirstIconId;
 
   /* if we haven't used up the int number range, we just return the next int */
   if (gNextIconId >= gFirstIconId) {
-    return gNextIconId++;
+    int next_id = gNextIconId++;
+    return next_id;
   }
 
-  /* now we try to find the smallest icon id not stored in the gIcons hash */
+  /* Now we try to find the smallest icon id not stored in the gIcons hash.
+   * Don't use icon_ghash_lookup here, it would lock recursively (dead-lock). */
   while (BLI_ghash_lookup(gIcons, POINTER_FROM_INT(startId)) && startId >= gFirstIconId) {
     startId++;
   }
@@ -203,7 +228,7 @@ void BKE_icons_free(void)
 
 void BKE_icons_deferred_free(void)
 {
-  BLI_assert(BLI_thread_is_main());
+  std::scoped_lock lock(gIconMutex);
 
   for (DeferredIconDeleteNode *node =
            (DeferredIconDeleteNode *)BLI_linklist_lockfree_begin(&g_icon_delete_queue);
@@ -216,7 +241,8 @@ void BKE_icons_deferred_free(void)
 
 static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
 {
-  PreviewImage *prv_img = MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, "img_prv");
+  PreviewImage *prv_img = (PreviewImage *)MEM_mallocN(sizeof(PreviewImage) + deferred_data_size,
+                                                      "img_prv");
   memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
 
   if (deferred_data_size) {
@@ -224,12 +250,26 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
   }
 
   for (int i = 0; i < NUM_ICON_SIZES; i++) {
-    prv_img->flag[i] |= PRV_CHANGED;
+    prv_img->flag[i] |= (PRV_CHANGED | PRV_UNFINISHED);
     prv_img->changed_timestamp[i] = 0;
   }
   return prv_img;
 }
 
+static PreviewImage *previewimg_defered_create(const char *path, int source)
+{
+  /* We pack needed data for lazy loading (source type, in a single char, and path). */
+  const size_t deferred_data_size = strlen(path) + 2;
+  char *deferred_data;
+
+  PreviewImage *prv = previewimg_create_ex(deferred_data_size);
+  deferred_data = (char *)PRV_DEFERRED_DATA(prv);
+  deferred_data[0] = source;
+  memcpy(&deferred_data[1], path, deferred_data_size - 1);
+
+  return prv;
+}
+
 PreviewImage *BKE_previewimg_create(void)
 {
   return previewimg_create_ex(0);
@@ -267,7 +307,7 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
     GPU_texture_free(prv->gputexture[size]);
   }
   prv->h[size] = prv->w[size] = 0;
-  prv->flag[size] |= PRV_CHANGED;
+  prv->flag[size] |= (PRV_CHANGED | PRV_UNFINISHED);
   prv->flag[size] &= ~PRV_USER_EDITED;
   prv->changed_timestamp[size] = 0;
 }
@@ -275,7 +315,7 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
 void BKE_previewimg_clear(struct PreviewImage *prv)
 {
   for (int i = 0; i < NUM_ICON_SIZES; i++) {
-    BKE_previewimg_clear_single(prv, i);
+    BKE_previewimg_clear_single(prv, (eIconSizes)i);
   }
 }
 
@@ -284,10 +324,10 @@ PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
   PreviewImage *prv_img = NULL;
 
   if (prv) {
-    prv_img = MEM_dupallocN(prv);
+    prv_img = (PreviewImage *)MEM_dupallocN(prv);
     for (int i = 0; i < NUM_ICON_SIZES; i++) {
       if (prv->rect[i]) {
-        prv_img->rect[i] = MEM_dupal

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list