[Bf-blender-cvs] [9363132c860] master: Asset System: Various changes to previews in preparation for Asset Browser

Julian Eisel noreply at git.blender.org
Tue Dec 15 17:04:34 CET 2020


Commit: 9363132c8601ebca6d89168e09bb10f81d6cb03a
Author: Julian Eisel
Date:   Mon Dec 14 13:21:58 2020 +0100
Branches: master
https://developer.blender.org/rB9363132c8601ebca6d89168e09bb10f81d6cb03a

Asset System: Various changes to previews in preparation for Asset Browser

* 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 `icons.c` to C++, to be able to use scope based mutex locks
   (cleaner & safer code). Had to do some cleanups and minor refactoring for
   that.
* Added support for ImBuf icons, as a decent way for icons to hold the file
  preview buffers.
* 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). This is for general
  sanity of the code (as in, safety and cleanness)
* Enabled asset notifier for custom preview loading operator, was just disabled
  because `NC_ASSET` wasn't defined in master yet.

Part of the first Asset Browser milestone. Check the #asset_browser_milestone_1
project milestone on developer.blender.org.

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

Reviewed by: Bastien Montagne, Brecht Van Lommel

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

M	source/blender/blenkernel/BKE_icons.h
M	source/blender/blenkernel/CMakeLists.txt
R079	source/blender/blenkernel/intern/icons.c	source/blender/blenkernel/intern/icons.cc
M	source/blender/blenloader/intern/readblenentry.c
M	source/blender/editors/interface/interface_icons.c
M	source/blender/editors/render/render_preview.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 cb2755d8706..5ceba4c717f 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);
 
 /* Trigger deferred loading of a custom image file into the preview buffer. */
 void BKE_previewimg_id_custom_set(struct ID *id, const char *path);
@@ -151,6 +169,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);
@@ -168,7 +191,7 @@ void BKE_previewimg_blend_write(struct BlendWriter *writer, const struct Preview
 void BKE_previewimg_blend_read(struct BlendDataReader *reader, struct PreviewImage *prv);
 
 int BKE_icon_geom_ensure(struct Icon_Geom *geom);
-struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len);
+struct Icon_Geom *BKE_icon_geom_from_memory(uchar *data, size_t data_len);
 struct Icon_Geom *BKE_icon_geom_from_file(const char *filename);
 
 struct ImBuf *BKE_icon_geom_rasterize(const struct Icon_Geom *geom,
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 156d731d4a7..23ba4eb4235 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -133,7 +133,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 79%
rename from source/blender/blenkernel/intern/icons.c
rename to source/blender/blenkernel/intern/icons.cc
index 0abf5d7279b..b92b2259eeb 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,7 +250,7 @@ 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;
@@ -281,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;
 }
@@ -289,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);
   }
 }
 
@@ -298,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_dupallocN(prv->rect[i]);
+        prv_img->rect[i] = (uint *)MEM_dupallocN(prv->rect[i]);
       }
       prv_img->gputexture[i] = NULL;
     }
@@ -344,7 +370,7 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id)
     ID_PRV_CASE(ID_LA, Light);
     ID_PRV_CASE(ID_IM, Image);
     ID_PRV_CASE(ID_BR, Brush);
-    // ID_PRV_CASE(ID_OB, Object);
+    ID_PRV_CASE(ID_OB, Object);
     ID_PRV_CASE(ID_GR, Collection);
     ID_PRV_CASE(ID_SCE, Scene);
     ID_PRV_CASE(ID_SCR, bScreen);
@@ -384,21 +410,6 @@ PreviewImage *BKE_previewim

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list