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:
authorSergey Sharybin <sergey.vfx@gmail.com>2013-01-21 12:49:42 +0400
committerSergey Sharybin <sergey.vfx@gmail.com>2013-01-21 12:49:42 +0400
commit86991fbcb0e8a1c65acff5aed85ce55f8b108baa (patch)
treee39d2b4203e18052fea58691d3920093905f47dc /source/blender/blenkernel/intern/image.c
parent2b9ab8781d95609f529c2d5dcf770c82d23afe17 (diff)
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.
Diffstat (limited to 'source/blender/blenkernel/intern/image.c')
-rw-r--r--source/blender/blenkernel/intern/image.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 5124406b641..90158f8cc70 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -2811,6 +2811,28 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
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 @@ int BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
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;