[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [53946] trunk/blender/source/blender: Fixed render time regression in Blender Internal

Sergey Sharybin sergey.vfx at gmail.com
Mon Jan 21 09:49:48 CET 2013


Revision: 53946
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=53946
Author:   nazgul
Date:     2013-01-21 08:49:42 +0000 (Mon, 21 Jan 2013)
Log Message:
-----------
Fixed render time regression in Blender Internal

It was caused by image threading safe commit and it was noticeable
only on really multi-core CPU (like dual-socket Xeon stations), was
not visible on core i7 machine.

The reason of slowdown was spinlock around image buffer referencing,
which lead to lots of cores waiting for single core and using image
buffer after it was referenced was not so much longer than doing
reference itself.

The most clear solution here seemed to be introducing Image Pool
which will contain list of loaded and referenced image buffers, so
all threads could skip lock if the pool is used for reading only.
Lock only needed in cases when buffer for requested image user is
missing in the pool. This lock will happen only once per image so
overall amount of locks is much less that it was before.

To operate with pool:
- BKE_image_pool_new() creates new pool
- BKE_image_pool_free() destroys pool and dereferences all image
  buffers which were loaded to it
- BKE_image_pool_acquire_ibuf() returns image buffer for given
  image and user. Pool could be NULL and in this case fallback to
  BKE_image_acquire_ibuf will happen.

  This helps to avoid lots to if(poll) checks in image sampling
  code.

- BKE_image_pool_release_ibuf releases image buffer. In fact, it
  will only do something if pool is NULL, in all other case it'll
  equal to DoNothing operation.

Modified Paths:
--------------
    trunk/blender/source/blender/blenkernel/BKE_image.h
    trunk/blender/source/blender/blenkernel/BKE_paint.h
    trunk/blender/source/blender/blenkernel/intern/dynamicpaint.c
    trunk/blender/source/blender/blenkernel/intern/effect.c
    trunk/blender/source/blender/blenkernel/intern/image.c
    trunk/blender/source/blender/blenkernel/intern/object.c
    trunk/blender/source/blender/blenkernel/intern/smoke.c
    trunk/blender/source/blender/compositor/operations/COM_TextureOperation.cpp
    trunk/blender/source/blender/compositor/operations/COM_TextureOperation.h
    trunk/blender/source/blender/editors/sculpt_paint/paint_cursor.c
    trunk/blender/source/blender/editors/sculpt_paint/paint_image_2d.c
    trunk/blender/source/blender/editors/sculpt_paint/paint_intern.h
    trunk/blender/source/blender/editors/sculpt_paint/paint_utils.c
    trunk/blender/source/blender/editors/sculpt_paint/sculpt.c
    trunk/blender/source/blender/makesrna/intern/rna_texture_api.c
    trunk/blender/source/blender/modifiers/intern/MOD_util.c
    trunk/blender/source/blender/nodes/shader/nodes/node_shader_texture.c
    trunk/blender/source/blender/nodes/texture/nodes/node_texture_proc.c
    trunk/blender/source/blender/nodes/texture/nodes/node_texture_texture.c
    trunk/blender/source/blender/render/extern/include/RE_shader_ext.h
    trunk/blender/source/blender/render/intern/include/envmap.h
    trunk/blender/source/blender/render/intern/include/pixelshading.h
    trunk/blender/source/blender/render/intern/include/render_types.h
    trunk/blender/source/blender/render/intern/include/texture.h
    trunk/blender/source/blender/render/intern/source/convertblender.c
    trunk/blender/source/blender/render/intern/source/envmap.c
    trunk/blender/source/blender/render/intern/source/imagetexture.c
    trunk/blender/source/blender/render/intern/source/pipeline.c
    trunk/blender/source/blender/render/intern/source/render_texture.c
    trunk/blender/source/blender/render/intern/source/renderdatabase.c

Modified: trunk/blender/source/blender/blenkernel/BKE_image.h
===================================================================
--- trunk/blender/source/blender/blenkernel/BKE_image.h	2013-01-21 08:08:20 UTC (rev 53945)
+++ trunk/blender/source/blender/blenkernel/BKE_image.h	2013-01-21 08:49:42 UTC (rev 53946)
@@ -44,6 +44,7 @@
 struct Scene;
 struct Object;
 struct ImageFormatData;
+struct ImagePool;
 struct Main;
 
 #define IMA_MAX_SPACE       64
@@ -146,6 +147,11 @@
 struct ImBuf *BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **lock_r);
 void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock);
 
+struct ImagePool *BKE_image_pool_new(void);
+void BKE_image_pool_free(struct ImagePool *pool);
+struct ImBuf *BKE_image_pool_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, struct ImagePool *pool);
+void BKE_image_pool_release_ibuf(struct Image *ima, struct ImBuf *ibuf, struct ImagePool *pool);
+
 /* returns a new image or NULL if it can't load */
 struct Image *BKE_image_load(const char *filepath);
 /* returns existing Image when filename/type is same (frame optional) */

Modified: trunk/blender/source/blender/blenkernel/BKE_paint.h
===================================================================
--- trunk/blender/source/blender/blenkernel/BKE_paint.h	2013-01-21 08:08:20 UTC (rev 53945)
+++ trunk/blender/source/blender/blenkernel/BKE_paint.h	2013-01-21 08:49:42 UTC (rev 53946)
@@ -47,6 +47,7 @@
 struct PBVH;
 struct Scene;
 struct StrokeCache;
+struct ImagePool;
 
 extern const char PAINT_CURSOR_SCULPT[3];
 extern const char PAINT_CURSOR_VERTEX_PAINT[3];
@@ -116,6 +117,7 @@
 	
 	/* Used to cache the render of the active texture */
 	unsigned int texcache_side, *texcache, texcache_actual;
+	struct ImagePool *tex_pool;
 
 	/* Layer brush persistence between strokes */
 	float (*layer_co)[3]; /* Copy of the mesh vertices' locations */

Modified: trunk/blender/source/blender/blenkernel/intern/dynamicpaint.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/dynamicpaint.c	2013-01-21 08:08:20 UTC (rev 53945)
+++ trunk/blender/source/blender/blenkernel/intern/dynamicpaint.c	2013-01-21 08:49:42 UTC (rev 53946)
@@ -1483,7 +1483,9 @@
 		/* for vertex surface loop through tfaces and find uv color
 		 *  that provides highest alpha */
 		if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
-			#pragma omp parallel for schedule(static)
+			struct ImagePool *pool = BKE_image_pool_new();
+
+			#pragma omp parallel for schedule(static) shared(pool)
 			for (i = 0; i < numOfFaces; i++) {
 				int numOfVert = (mface[i].v4) ? 4 : 3;
 				float uv[3] = {0.0f};
@@ -1496,7 +1498,7 @@
 					uv[0] = tface[i].uv[j][0] * 2.0f - 1.0f;
 					uv[1] = tface[i].uv[j][1] * 2.0f - 1.0f;
 
-					multitex_ext_safe(tex, uv, &texres);
+					multitex_ext_safe(tex, uv, &texres, pool);
 
 					if (texres.tin > pPoint[*vert].alpha) {
 						copy_v3_v3(pPoint[*vert].color, &texres.tr);
@@ -1504,6 +1506,7 @@
 					}
 				}
 			}
+			BKE_image_pool_free(pool);
 		}
 		else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
 			ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
@@ -1529,7 +1532,7 @@
 				uv_final[0] = uv_final[0] * 2.0f - 1.0f;
 				uv_final[1] = uv_final[1] * 2.0f - 1.0f;
 					
-				multitex_ext_safe(tex, uv_final, &texres);
+				multitex_ext_safe(tex, uv_final, &texres, NULL);
 
 				/* apply color */
 				copy_v3_v3(pPoint[i].color, &texres.tr);

Modified: trunk/blender/source/blender/blenkernel/intern/effect.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/effect.c	2013-01-21 08:08:20 UTC (rev 53945)
+++ trunk/blender/source/blender/blenkernel/intern/effect.c	2013-01-21 08:49:42 UTC (rev 53946)
@@ -769,7 +769,7 @@
 		mul_m4_v3(eff->ob->imat, tex_co);
 	}
 
-	hasrgb = multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result);
+	hasrgb = multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result, NULL);
 
 	if (hasrgb && mode==PFIELD_TEX_RGB) {
 		force[0] = (0.5f - result->tr) * strength;
@@ -780,15 +780,15 @@
 		strength/=nabla;
 
 		tex_co[0] += nabla;
-		multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+1);
+		multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+1, NULL);
 
 		tex_co[0] -= nabla;
 		tex_co[1] += nabla;
-		multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+2);
+		multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+2, NULL);
 
 		tex_co[1] -= nabla;
 		tex_co[2] += nabla;
-		multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+3);
+		multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+3, NULL);
 
 		if (mode == PFIELD_TEX_GRAD || !hasrgb) { /* if we don't have rgb fall back to grad */
 			/* generate intensity if texture only has rgb value */

Modified: trunk/blender/source/blender/blenkernel/intern/image.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/image.c	2013-01-21 08:08:20 UTC (rev 53945)
+++ trunk/blender/source/blender/blenkernel/intern/image.c	2013-01-21 08:49:42 UTC (rev 53946)
@@ -2811,6 +2811,28 @@
 	return ibuf;
 }
 
+static void image_get_fame_and_index(Image *ima, ImageUser *iuser, int *frame_r, int *index_r)
+{
+	int frame = 0, index = 0;
+
+	/* see if we already have an appropriate ibuf, with image source and type */
+	if (ima->source == IMA_SRC_MOVIE) {
+		frame = iuser ? iuser->framenr : ima->lastframe;
+	}
+	else if (ima->source == IMA_SRC_SEQUENCE) {
+		if (ima->type == IMA_TYPE_IMAGE) {
+			frame = iuser ? iuser->framenr : ima->lastframe;
+		}
+		else if (ima->type == IMA_TYPE_MULTILAYER) {
+			frame = iuser ? iuser->framenr : ima->lastframe;
+			index = iuser ? iuser->multi_index : IMA_NO_INDEX;
+		}
+	}
+
+	*frame_r = frame;
+	*index_r = index;
+}
+
 static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame_r, int *index_r)
 {
 	ImBuf *ibuf = NULL;
@@ -3037,6 +3059,119 @@
 	return ibuf != NULL;
 }
 
+/* ******** Pool for image buffers ********  */
+
+typedef struct ImagePoolEntry {
+	struct ImagePoolEntry *next, *prev;
+	Image *image;
+	ImBuf *ibuf;
+	int index;
+	int frame;
+} ImagePoolEntry;
+
+typedef struct ImagePool {
+	ListBase image_buffers;
+} ImagePool;
+
+ImagePool *BKE_image_pool_new(void)
+{
+	ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool");
+
+	return pool;
+}
+
+void BKE_image_pool_free(ImagePool *pool)
+{
+	ImagePoolEntry *entry, *next_entry;
+
+	/* use single lock to dereference all the image buffers */
+	BLI_spin_lock(&image_spin);
+
+	for (entry = pool->image_buffers.first; entry; entry = next_entry) {
+		next_entry = entry->next;
+
+		if (entry->ibuf)
+			IMB_freeImBuf(entry->ibuf);
+
+		MEM_freeN(entry);
+	}
+
+	BLI_spin_unlock(&image_spin);
+
+	MEM_freeN(pool);
+}
+
+BLI_INLINE ImBuf *image_pool_find_entry(ImagePool *pool, Image *image, int frame, int index, int *found)
+{
+	ImagePoolEntry *entry;
+
+	*found = FALSE;
+
+	for (entry = pool->image_buffers.first; entry; entry = entry->next) {
+		if (entry->image == image && entry->frame == frame && entry->index == index) {
+			*found = TRUE;
+			return entry->ibuf;
+		}
+	}
+
+	return NULL;
+}
+
+ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool)
+{
+	ImBuf *ibuf;
+	int index, frame, found;
+
+	if (pool == NULL) {
+		/* pool could be NULL, in this case use general acquire function */
+		return BKE_image_acquire_ibuf(ima, iuser, NULL);
+	}
+
+	image_get_fame_and_index(ima, iuser, &frame, &index);
+
+	ibuf = image_pool_find_entry(pool, ima, frame, index, &found);
+	if (found)
+		return ibuf;
+
+	BLI_spin_lock(&image_spin);
+
+	ibuf = image_pool_find_entry(pool, ima, frame, index, &found);
+
+	/* will also create entry even in cases image buffer failed to load,
+	 * prevents trying to load the same buggy file multiple times
+	 */
+	if (!found) {
+		ImagePoolEntry *entry;
+
+		ibuf = image_acquire_ibuf(ima, iuser, NULL);
+
+		if (ibuf)
+			IMB_refImBuf(ibuf);
+
+		entry = MEM_callocN(sizeof(ImagePoolEntry), "Image Pool Entry");
+		entry->image = ima;
+		entry->frame = frame;
+		entry->index = index;
+		entry->ibuf = ibuf;
+
+		BLI_addtail(&pool->image_buffers, entry);
+	}
+
+	BLI_spin_unlock(&image_spin);
+
+	return ibuf;
+}
+
+void BKE_image_pool_release_ibuf(Image *ima, ImBuf *ibuf, ImagePool *pool)
+{
+	/* if pool wasn't actually used, use general release stuff,
+	 * for pools image buffers will be dereferenced on pool free
+	 */
+	if (pool == NULL) {
+		BKE_image_release_ibuf(ima, ibuf, NULL);
+	}
+}
+
 int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, short *r_is_in_range)
 {
 	const int len = (iuser->fie_ima * iuser->frames) / 2;

Modified: trunk/blender/source/blender/blenkernel/intern/object.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/object.c	2013-01-21 08:08:20 UTC (rev 53945)
+++ trunk/blender/source/blender/blenkernel/intern/object.c	2013-01-21 08:49:42 UTC (rev 53946)
@@ -83,6 +83,7 @@
 #include "BKE_fcurve.h"
 #include "BKE_group.h"
 #include "BKE_icons.h"
+#include "BKE_image.h"
 #include "BKE_key.h"
 #include "BKE_lamp.h"
 #include "BKE_lattice.h"
@@ -308,6 +309,9 @@
 		if (ss->texcache)
 			MEM_freeN(ss->texcache);
 
+		if (ss->tex_pool)
+			BKE_image_pool_free(ss->tex_pool);
+
 		if (ss->layer_co)
 			MEM_freeN(ss->layer_co);
 

Modified: trunk/blender/source/blender/blenkernel/intern/smoke.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/smoke.c	2013-01-21 08:08:20 UTC (rev 53945)
+++ trunk/blender/source/blender/blenkernel/intern/smoke.c	2013-01-21 08:49:42 UTC (rev 53946)
@@ -1060,7 +1060,7 @@
 	int result_type;
 
 	/* no node textures for now */
-	result_type = multitex_ext_safe(texture, tex_co, texres);
+	result_type = multitex_ext_safe(texture, tex_co, texres, NULL);
 
 	/* if the texture gave an RGB value, we assume it didn't give a valid
 	 * intensity, since this is in the context of modifiers don't use perceptual color conversion.

Modified: trunk/blender/source/blender/compositor/operations/COM_TextureOperation.cpp
===================================================================
--- trunk/blender/source/blender/compositor/operations/COM_TextureOperation.cpp	2013-01-21 08:08:20 UTC (rev 53945)

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list