Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Eisel <julian@blender.org>2020-12-14 15:21:58 +0300
committerJulian Eisel <julian@blender.org>2020-12-15 19:03:45 +0300
commit9363132c8601ebca6d89168e09bb10f81d6cb03a (patch)
tree59afa11ef38f56060f1d4c7a35bf23adab31424d /source/blender/blenkernel
parentc25e0310497f5228bd04992d6bcd84481d0b0c5b (diff)
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
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_icons.h25
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/icons.cc (renamed from source/blender/blenkernel/intern/icons.c)249
3 files changed, 203 insertions, 73 deletions
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
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_previewimg_id_ensure(ID *id)
return NULL;
}
-void BKE_previewimg_deferred_release(PreviewImage *prv)
-{
- if (prv) {
- if (prv->tag & PRV_TAG_DEFFERED_RENDERING) {
- /* We cannot delete the preview while it is being loaded in another thread... */
- prv->tag |= PRV_TAG_DEFFERED_DELETE;
- return;
- }
- if (prv->icon_id) {
- BKE_icon_delete(prv->icon_id);
- }
- BKE_previewimg_freefunc(prv);
- }
-}
-
void BKE_previewimg_id_custom_set(ID *id, const char *path)
{
PreviewImage **prv = BKE_previewimg_id_get_p(id);
@@ -420,9 +431,30 @@ void BKE_previewimg_id_custom_set(ID *id, const char *path)
}
}
+bool BKE_previewimg_id_supports_jobs(const ID *id)
+{
+ return ELEM(GS(id->name), ID_OB, ID_MA, ID_TE, ID_LA, ID_WO, ID_IM, ID_BR);
+}
+
+void BKE_previewimg_deferred_release(PreviewImage *prv)
+{
+ if (prv) {
+ if (prv->tag & PRV_TAG_DEFFERED_RENDERING) {
+ /* We cannot delete the preview while it is being loaded in another thread... */
+ prv->tag |= PRV_TAG_DEFFERED_DELETE;
+ return;
+ }
+ if (prv->icon_id) {
+ BKE_icon_delete(prv->icon_id);
+ }
+ BKE_previewimg_freefunc(prv);
+ }
+}
+
PreviewImage *BKE_previewimg_cached_get(const char *name)
{
- return BLI_ghash_lookup(gCachedPreviews, name);
+ BLI_assert(BLI_thread_is_main());
+ return (PreviewImage *)BLI_ghash_lookup(gCachedPreviews, name);
}
/**
@@ -430,6 +462,8 @@ PreviewImage *BKE_previewimg_cached_get(const char *name)
*/
PreviewImage *BKE_previewimg_cached_ensure(const char *name)
{
+ BLI_assert(BLI_thread_is_main());
+
PreviewImage *prv = NULL;
void **key_p, **prv_p;
@@ -437,7 +471,7 @@ PreviewImage *BKE_previewimg_cached_ensure(const char *name)
*key_p = BLI_strdup(name);
*prv_p = BKE_previewimg_create();
}
- prv = *prv_p;
+ prv = *(PreviewImage **)prv_p;
BLI_assert(prv);
return prv;
@@ -445,24 +479,27 @@ PreviewImage *BKE_previewimg_cached_ensure(const char *name)
/**
* Generate a PreviewImage from given file path, using thumbnails management, if not yet existing.
+ * Does not actually generate the preview, #BKE_previewimg_ensure() must be called for that.
*/
PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
const char *path,
const int source,
bool force_update)
{
+ BLI_assert(BLI_thread_is_main());
+
PreviewImage *prv = NULL;
void **prv_p;
prv_p = BLI_ghash_lookup_p(gCachedPreviews, name);
if (prv_p) {
- prv = *prv_p;
+ prv = *(PreviewImage **)prv_p;
BLI_assert(prv);
}
if (prv && force_update) {
- const char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
+ const char *prv_deferred_data = (char *)PRV_DEFERRED_DATA(prv);
if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) {
/* If same path, no need to re-allocate preview, just clear it up. */
BKE_previewimg_clear(prv);
@@ -491,7 +528,9 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
void BKE_previewimg_cached_release(const char *name)
{
- PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
+ BLI_assert(BLI_thread_is_main());
+
+ PreviewImage *prv = (PreviewImage *)BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
BKE_previewimg_deferred_release(prv);
}
@@ -508,12 +547,12 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
if (do_icon || do_preview) {
ImBuf *thumb;
- char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
+ char *prv_deferred_data = (char *)PRV_DEFERRED_DATA(prv);
int source = prv_deferred_data[0];
char *path = &prv_deferred_data[1];
int icon_w, icon_h;
- thumb = IMB_thumb_manage(path, THB_LARGE, source);
+ thumb = IMB_thumb_manage(path, THB_LARGE, (ThumbSource)source);
if (thumb) {
/* PreviewImage assumes premultiplied alhpa... */
@@ -522,8 +561,8 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
if (do_preview) {
prv->w[ICON_SIZE_PREVIEW] = thumb->x;
prv->h[ICON_SIZE_PREVIEW] = thumb->y;
- prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect);
- prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED);
+ prv->rect[ICON_SIZE_PREVIEW] = (uint *)MEM_dupallocN(thumb->rect);
+ prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_UNFINISHED);
}
if (do_icon) {
if (thumb->x > thumb->y) {
@@ -541,8 +580,8 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
IMB_scaleImBuf(thumb, icon_w, icon_h);
prv->w[ICON_SIZE_ICON] = icon_w;
prv->h[ICON_SIZE_ICON] = icon_h;
- prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect);
- prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED);
+ prv->rect[ICON_SIZE_ICON] = (uint *)MEM_dupallocN(thumb->rect);
+ prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_UNFINISHED);
}
IMB_freeImBuf(thumb);
}
@@ -550,6 +589,38 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
}
}
+/**
+ * Create an #ImBuf holding a copy of the preview image buffer in \a prv.
+ * \note The returned image buffer has to be free'd (#IMB_freeImBuf()).
+ */
+ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size)
+{
+ const unsigned int w = prv->w[size];
+ const unsigned int h = prv->h[size];
+ const unsigned int *rect = prv->rect[size];
+
+ ImBuf *ima = NULL;
+
+ if (w > 0 && h > 0 && rect) {
+ /* first allocate imbuf for copying preview into it */
+ ima = IMB_allocImBuf(w, h, 32, IB_rect);
+ memcpy(ima->rect, rect, w * h * sizeof(*ima->rect));
+ }
+
+ return ima;
+}
+
+void BKE_previewimg_finish(PreviewImage *prv, const int size)
+{
+ /* Previews may be calculated on a thread. */
+ atomic_fetch_and_and_int16(&prv->flag[size], ~PRV_UNFINISHED);
+}
+
+bool BKE_previewimg_is_finished(const PreviewImage *prv, const int size)
+{
+ return (prv->flag[size] & PRV_UNFINISHED) == 0;
+}
+
void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
{
/* Note we write previews also for undo steps. It takes up some memory,
@@ -587,6 +658,7 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
BLO_read_data_address(reader, &prv->rect[i]);
}
prv->gputexture[i] = NULL;
+ prv->flag[i] |= PRV_UNFINISHED;
}
prv->icon_id = 0;
prv->tag = 0;
@@ -594,15 +666,13 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
void BKE_icon_changed(const int icon_id)
{
- BLI_assert(BLI_thread_is_main());
-
Icon *icon = NULL;
if (!icon_id || G.background) {
return;
}
- icon = BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id));
+ icon = icon_ghash_lookup(icon_id);
if (icon) {
/* We *only* expect ID-tied icons here, not non-ID icon/preview! */
@@ -617,7 +687,7 @@ void BKE_icon_changed(const int icon_id)
/* If we have previews, they all are now invalid changed. */
if (p_prv && *p_prv) {
for (int i = 0; i < NUM_ICON_SIZES; i++) {
- (*p_prv)->flag[i] |= PRV_CHANGED;
+ (*p_prv)->flag[i] |= (PRV_CHANGED | PRV_UNFINISHED);
(*p_prv)->changed_timestamp[i]++;
}
}
@@ -626,7 +696,7 @@ void BKE_icon_changed(const int icon_id)
static Icon *icon_create(int icon_id, int obj_type, void *obj)
{
- Icon *new_icon = MEM_mallocN(sizeof(Icon), __func__);
+ Icon *new_icon = (Icon *)MEM_mallocN(sizeof(Icon), __func__);
new_icon->obj_type = obj_type;
new_icon->obj = obj;
@@ -637,7 +707,10 @@ static Icon *icon_create(int icon_id, int obj_type, void *obj)
new_icon->drawinfo = NULL;
new_icon->drawinfo_free = NULL;
- BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), new_icon);
+ {
+ std::scoped_lock lock(gIconMutex);
+ BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), new_icon);
+ }
return new_icon;
}
@@ -764,13 +837,43 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
return preview->icon_id;
}
+/**
+ * Create an icon as owner or \a ibuf. The icon-ID is not stored in \a ibuf, it needs to be stored
+ * separately.
+ * \note Transforms ownership of \a ibuf to the newly created icon.
+ */
+int BKE_icon_imbuf_create(ImBuf *ibuf)
+{
+ int icon_id = get_next_free_id();
+
+ Icon *icon = icon_create(icon_id, ICON_DATA_IMBUF, ibuf);
+ icon->flag = ICON_FLAG_MANAGED;
+
+ return icon_id;
+}
+
+ImBuf *BKE_icon_imbuf_get_buffer(int icon_id)
+{
+ Icon *icon = icon_ghash_lookup(icon_id);
+ if (!icon) {
+ CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id);
+ return NULL;
+ }
+ if (icon->obj_type != ICON_DATA_IMBUF) {
+ CLOG_ERROR(&LOG, "icon ID does not refer to an imbuf icon: %d", icon_id);
+ return NULL;
+ }
+
+ return (ImBuf *)icon->obj;
+}
+
Icon *BKE_icon_get(const int icon_id)
{
BLI_assert(BLI_thread_is_main());
Icon *icon = NULL;
- icon = BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id));
+ icon = icon_ghash_lookup(icon_id);
if (!icon) {
CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id);
@@ -782,10 +885,9 @@ Icon *BKE_icon_get(const int icon_id)
void BKE_icon_set(const int icon_id, struct Icon *icon)
{
- BLI_assert(BLI_thread_is_main());
-
void **val_p;
+ std::scoped_lock lock(gIconMutex);
if (BLI_ghash_ensure_p(gIcons, POINTER_FROM_INT(icon_id), &val_p)) {
CLOG_ERROR(&LOG, "icon already set: %d", icon_id);
return;
@@ -796,8 +898,10 @@ void BKE_icon_set(const int icon_id, struct Icon *icon)
static void icon_add_to_deferred_delete_queue(int icon_id)
{
- DeferredIconDeleteNode *node = MEM_mallocN(sizeof(DeferredIconDeleteNode), __func__);
+ DeferredIconDeleteNode *node = (DeferredIconDeleteNode *)MEM_mallocN(
+ sizeof(DeferredIconDeleteNode), __func__);
node->icon_id = icon_id;
+ /* Doesn't need lock. */
BLI_linklist_lockfree_insert(&g_icon_delete_queue, (LockfreeLinkNode *)node);
}
@@ -815,6 +919,7 @@ void BKE_icon_id_delete(struct ID *id)
}
BKE_icons_deferred_free();
+ std::scoped_lock lock(gIconMutex);
BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), NULL, icon_free);
}
@@ -828,8 +933,8 @@ bool BKE_icon_delete(const int icon_id)
return false;
}
- Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
- if (icon) {
+ std::scoped_lock lock(gIconMutex);
+ if (Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL)) {
icon_free_data(icon_id, icon);
icon_free(icon);
return true;
@@ -845,7 +950,9 @@ bool BKE_icon_delete_unmanaged(const int icon_id)
return false;
}
- Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
+ std::scoped_lock lock(gIconMutex);
+
+ Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
if (icon) {
if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) {
BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), icon);
@@ -880,50 +987,50 @@ int BKE_icon_geom_ensure(struct Icon_Geom *geom)
return geom->icon_id;
}
-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)
{
BLI_assert(BLI_thread_is_main());
if (data_len <= 8) {
- goto fail;
+ return nullptr;
}
+ /* Wrapper for RAII early exit cleanups. */
+ std::unique_ptr<uchar> data_wrapper(std::move(data));
+
/* Skip the header. */
data_len -= 8;
const int div = 3 * 2 * 3;
const int coords_len = data_len / div;
if (coords_len * div != data_len) {
- goto fail;
+ return nullptr;
}
const uchar header[4] = {'V', 'C', 'O', 0};
- const uchar *p = data;
+ uchar *p = data_wrapper.get();
if (memcmp(p, header, ARRAY_SIZE(header)) != 0) {
- goto fail;
+ return nullptr;
}
p += 4;
- struct Icon_Geom *geom = MEM_mallocN(sizeof(*geom), __func__);
+ struct Icon_Geom *geom = (struct Icon_Geom *)MEM_mallocN(sizeof(*geom), __func__);
geom->coords_range[0] = (int)*p++;
geom->coords_range[1] = (int)*p++;
/* x, y ignored for now */
p += 2;
geom->coords_len = coords_len;
- geom->coords = (void *)p;
- geom->colors = (void *)(p + (data_len / 3));
+ geom->coords = reinterpret_cast<decltype(geom->coords)>(p);
+ geom->colors = reinterpret_cast<decltype(geom->colors)>(p + (data_len / 3));
geom->icon_id = 0;
- geom->mem = data;
+ /* Move buffer ownership to C buffer. */
+ geom->mem = data_wrapper.release();
return geom;
-
-fail:
- MEM_freeN((void *)data);
- return NULL;
}
struct Icon_Geom *BKE_icon_geom_from_file(const char *filename)
{
BLI_assert(BLI_thread_is_main());
size_t data_len;
- uchar *data = BLI_file_read_binary_as_mem(filename, 0, &data_len);
+ uchar *data = (uchar *)BLI_file_read_binary_as_mem(filename, 0, &data_len);
if (data == NULL) {
return NULL;
}