[Bf-blender-cvs] [1931cca] ui-preview-buttons: Deferred loading for PreviewImage and icons based on them.

Bastien Montagne noreply at git.blender.org
Fri May 8 19:54:38 CEST 2015


Commit: 1931cca4a60347c30efcb0a1867ec3446d4352a2
Author: Bastien Montagne
Date:   Fri May 8 19:40:29 2015 +0200
Branches: ui-preview-buttons
https://developer.blender.org/rB1931cca4a60347c30efcb0a1867ec3446d4352a2

Deferred loading for PreviewImage and icons based on them.

This only works with thumbnails/filepath currently, but later we may extend it with
other 'generated' ways...

When requesting a PreviewImage from path thumbnail, only path (and thumb type) are stored
in over-allocated fashion at end of PreviewImage struct.

Then, calling `BKE_previewimg_ensure()` will take care of loading actual data if needed.
This is only used from RNA currently, however, since we do not want to do that from
main thread in draw icon code.

For drawing code itself, tweaked system already existing for ID previews to also
handle deferred (thumbnails) ones.

Side Note: current job-based preview generation seems really bad to me:
  * It is not thread-safe - not at all! Reading **and writing** data from job thread
    (IDs, preview's rect, ...), without any protection of course.
  * It is badly used and adds a huge overweight (one job **per preview**!!!).
This has to be completely rewriten imho, probably in a similar way as what is done
for filebrowser previews in asset-experiments branch, i.e. using much lighter BLI_task,
and being much stricter about not sharing memory between worker and main threads,
but this is outside of scope for this patch.

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

M	source/blender/blenkernel/BKE_icons.h
M	source/blender/blenkernel/intern/icons.c
M	source/blender/editors/include/ED_render.h
M	source/blender/editors/interface/interface.c
M	source/blender/editors/interface/interface_icons.c
M	source/blender/editors/interface/interface_intern.h
M	source/blender/editors/interface/interface_templates.c
M	source/blender/editors/render/render_preview.c
M	source/blender/makesdna/DNA_ID.h
M	source/blender/makesrna/intern/rna_ID.c

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

diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index f92a52a..729406d 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -96,6 +96,8 @@ struct PreviewImage *BKE_previewimg_copy(struct PreviewImage *prv);
 /* retrieve existing or create new preview image */
 struct PreviewImage *BKE_previewimg_id_get(struct ID *id);
 
+void BKE_previewimg_ensure(struct PreviewImage *prv, const int size);
+
 struct PreviewImage *BKE_previewimg_cached_get(const char *name);
 
 struct PreviewImage *BKE_previewimg_cached_thumbnail_get(
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index f1d4ac3..3f6dce8 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -131,20 +131,32 @@ void BKE_icons_free(void)
 	}
 }
 
-PreviewImage *BKE_previewimg_create(void)
+static PreviewImage *previewimg_create_ex(void *deferred_data, size_t deferred_data_size)
 {
 	PreviewImage *prv_img = NULL;
+	size_t overalloc = (deferred_data_size > sizeof(prv_img->deferred_data)) ?
+	                       deferred_data_size - sizeof(prv_img->deferred_data) : 0;
 	int i;
 
-	prv_img = MEM_callocN(sizeof(PreviewImage), "img_prv");
+	prv_img = MEM_callocN(sizeof(PreviewImage) + overalloc, "img_prv");
+
+	if (deferred_data) {
+		memcpy(prv_img->deferred_data, deferred_data, deferred_data_size);
+		prv_img->use_deferred = true;
+	}
 
 	for (i = 0; i < NUM_ICON_SIZES; ++i) {
-		prv_img->flag[i] |= CHANGED;
+		prv_img->flag[i] |= PRV_CHANGED;
 		prv_img->changed_timestamp[i] = 0;
 	}
 	return prv_img;
 }
 
+PreviewImage *BKE_previewimg_create(void)
+{
+	return previewimg_create_ex(NULL, 0);
+}
+
 void BKE_previewimg_freefunc(void *link)
 {
 	PreviewImage *prv = (PreviewImage *)link;
@@ -182,7 +194,7 @@ void BKE_previewimg_clear(struct PreviewImage *prv, enum eIconSizes size)
 		GPU_texture_free(prv->gputexture[size]);
 	}
 	prv->h[size] = prv->w[size] = 0;
-	prv->flag[size] |= CHANGED;
+	prv->flag[size] |= PRV_CHANGED;
 	prv->changed_timestamp[size] = 0;
 }
 
@@ -197,9 +209,6 @@ PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
 			if (prv->rect[i]) {
 				prv_img->rect[i] = MEM_dupallocN(prv->rect[i]);
 			}
-			else {
-				prv_img->rect[i] = NULL;
-			}
 			prv_img->gputexture[i] = NULL;
 		}
 	}
@@ -309,7 +318,6 @@ PreviewImage *BKE_previewimg_cached_thumbnail_get(
 {
 	PreviewImage *prv = NULL;
 	void **prv_v;
-	int icon_w, icon_h;
 
 	prv_v = BLI_ghash_lookup_p(gCachedPreviews, name);
 
@@ -319,44 +327,31 @@ PreviewImage *BKE_previewimg_cached_thumbnail_get(
 	}
 
 	if (prv && force_update) {
-		BKE_previewimg_clear(prv, ICON_SIZE_ICON);
-		BKE_previewimg_clear(prv, ICON_SIZE_PREVIEW);
-	}
-	else if (!prv) {
-		prv = BKE_previewimg_create();
-		force_update = true;
+		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, ICON_SIZE_ICON);
+			BKE_previewimg_clear(prv, ICON_SIZE_PREVIEW);
+		}
+		else {
+			BKE_previewimg_free(&prv);
+		}
 	}
 
-	if (force_update) {
-		ImBuf *thumb = IMB_thumb_manage(path, THB_LARGE, source);
-
-		if (thumb) {
-			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] &= ~(CHANGED | USER_EDITED);
+	if (!prv) {
+		/* We pack needed data for lazy loading (source type, in a single char, and path). */
+		size_t defdata_size = strlen(path) + 2;
+		char *defdata = MEM_mallocN(sizeof(defdata) * defdata_size, __func__);
 
-			if (thumb->x > thumb->y) {
-				icon_w = ICON_RENDER_DEFAULT_HEIGHT;
-				icon_h = (thumb->y * icon_w) / thumb->x + 1;
-			}
-			else if (thumb->x < thumb->y) {
-				icon_h = ICON_RENDER_DEFAULT_HEIGHT;
-				icon_w = (thumb->x * icon_h) / thumb->y + 1;
-			}
-			else {
-				icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT;
-			}
+		defdata[0] = (char)source;
+		strcpy(&defdata[1], path);
 
-			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] &= ~(CHANGED | USER_EDITED);
+		prv = previewimg_create_ex((void *)defdata, defdata_size);
+		force_update = true;
 
-			IMB_freeImBuf(thumb);
-		}
+		MEM_freeN(defdata);
+	}
 
+	if (force_update) {
 		if (prv_v) {
 			*prv_v = prv;
 		}
@@ -380,6 +375,54 @@ void BKE_previewimg_cached_release(const char *name)
 	}
 }
 
+/** Handle deferred (lazy) loading/generation of preview image, if needed.
+ * For now, only used with file thumbnails. */
+void BKE_previewimg_ensure(PreviewImage *prv, const int size)
+{
+	if (prv->use_deferred) {
+		const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]);
+		const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]);
+
+		if (do_icon || do_preview) {
+			ImBuf *thumb;
+			int source = (int)prv->deferred_data[0];
+			char *path = &prv->deferred_data[1];
+			int icon_w, icon_h;
+
+			thumb = IMB_thumb_manage(path, THB_LARGE, source);
+
+			if (thumb) {
+				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);
+				}
+				if (do_icon) {
+					if (thumb->x > thumb->y) {
+						icon_w = ICON_RENDER_DEFAULT_HEIGHT;
+						icon_h = (thumb->y * icon_w) / thumb->x + 1;
+					}
+					else if (thumb->x < thumb->y) {
+						icon_h = ICON_RENDER_DEFAULT_HEIGHT;
+						icon_w = (thumb->x * icon_h) / thumb->y + 1;
+					}
+					else {
+						icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT;
+					}
+
+					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);
+				}
+				IMB_freeImBuf(thumb);
+			}
+		}
+	}
+}
+
 void BKE_icon_changed(int id)
 {
 	Icon *icon = NULL;
@@ -395,7 +438,7 @@ void BKE_icon_changed(int id)
 		if (prv) {
 			int i;
 			for (i = 0; i < NUM_ICON_SIZES; ++i) {
-				prv->flag[i] |= CHANGED;
+				prv->flag[i] |= PRV_CHANGED;
 				prv->changed_timestamp[i]++;
 			}
 		}
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 2bc0566..414126c 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -60,11 +60,15 @@ struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
  * - PR_BUTS_RENDER: preview is rendered for buttons window
  * - PR_ICON_RENDER: preview is rendered for icons. hopefully fast enough for at least 32x32
  * - PR_NODE_RENDER: preview is rendered for node editor
+ * - PR_ICON_DEFERRED: No render, we just ensure deferred icon data gets generated.
  */
 
-#define PR_BUTS_RENDER  0
-#define PR_ICON_RENDER  1
-#define PR_NODE_RENDER  2
+enum {
+	PR_BUTS_RENDER   = 0,
+	PR_ICON_RENDER   = 1,
+	PR_NODE_RENDER   = 2,
+	PR_ICON_DEFERRED = 3,
+};
 
 void ED_preview_init_dbase(void);
 void ED_preview_free_dbase(void);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index b63871f..8aabc74 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -3237,6 +3237,18 @@ static uiBut *ui_def_but(
 	return but;
 }
 
+void ui_def_but_icon(uiBut *but, const int icon, const int flag) {
+	if (icon) {
+		ui_icon_ensure_deferred(but->block->evil_C, icon, (flag & UI_BUT_ICON_PREVIEW) != 0);
+	}
+	but->icon = (BIFIconID)icon;
+	but->flag |= flag;
+
+	if (but->str) {
+		but->drawflag |= UI_BUT_ICON_LEFT;
+	}
+}
+
 static void ui_def_but_rna__disable(uiBut *but)
 {
 	but->flag |= UI_BUT_DISABLED;
@@ -3500,11 +3512,7 @@ static uiBut *ui_def_but_rna(
 		but->rnaindex = 0;
 
 	if (icon) {
-		but->icon = (BIFIconID)icon;
-		but->flag |= UI_HAS_ICON;
-		if (str[0]) {
-			but->drawflag |= UI_BUT_ICON_LEFT;
-		}
+		ui_def_but_icon(but, icon, UI_HAS_ICON);
 	}
 	
 	if ((type == UI_BTYPE_MENU) && (but->dt == UI_EMBOSS_PULLDOWN)) {
@@ -3691,8 +3699,7 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
 static void ui_but_update_and_icon_set(uiBut *but, int icon)
 {
 	if (icon) {
-		but->icon = (BIFIconID) icon;
-		but->flag |= UI_HAS_ICON;
+		ui_def_but_icon(but, icon, UI_HAS_ICON);
 	}
 
 	ui_but_update(but);
@@ -4066,7 +4073,7 @@ void UI_but_drag_set_value(uiBut *but)
 void UI_but_drag_set_image(uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale)
 {
 	but->dragtype = WM_DRAG_PATH;
-	but->icon = icon; /* no flag UI_HAS_ICON, so icon doesnt draw in button */
+	ui_def_but_icon(but, icon, 0);  /* no flag UI_HAS_ICON, so icon doesnt draw in button */
 	but->dragpoin = (void *)path;
 	but->imb = imb;
 	but->imb_scale = scale;
@@ -4220,8 +4227,7 @@ uiBut *uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, in
 {
 	uiBut *but = ui_def_but(block, UI_BTYPE_PULLDOWN, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
 
-	but->icon = (BIFIconID) icon;
-	but->flag |= UI_HAS_ICON;
+	ui_def_but_icon(but, icon, UI_HAS_ICON);
 
 	but->drawflag |= UI_BUT_ICON_LEFT;
 	but->flag |= UI_BUT_ICON_SUBMENU;
@@ -4236,8 +4242,7 @@ uiBut *uiDefIconMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int ic
 {
 	uiBut *but = ui_def_but(block, UI_BTYPE_PULLDOWN, 0, "", x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
 
-	but->icon = (BIFIconID) icon;
-	but->flag |= UI_HAS_ICON;
+	ui_def_but_icon(but, icon, UI_HAS_ICON);
 	but->drawflag &= ~UI_BUT_ICON_LEFT;
 
 	but->menu_create_func = func;
@@ -4253,7 +4258,7 @@ uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg,
 	
 	/* XXX temp, old menu calls pass on icon arrow, which is now UI_BUT_ICON_SUBMENU flag */
 	if (icon != ICON_RIGHTARROW_THIN) {
-		but->icon = (BIFIconID) icon;
+		ui_def_but_icon(but, icon, 0);
 		but->drawflag |= UI_BUT_ICON_LEF

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list