48
48
* back to the global cache every pixel, but not to big to keep too many tiles
49
49
* locked and using memory. */
51
#define IB_THREAD_CACHE_SIZE 100
51
#define IB_THREAD_CACHE_SIZE 100
53
53
typedef struct ImGlobalTile {
54
54
struct ImGlobalTile *next, *prev;
97
97
static unsigned int imb_global_tile_hash(const void *gtile_p)
99
const ImGlobalTile *gtile= gtile_p;
99
const ImGlobalTile *gtile = gtile_p;
101
return ((unsigned int)(intptr_t)gtile->ibuf)*769 + gtile->tx*53 + gtile->ty*97;
101
return ((unsigned int)(intptr_t)gtile->ibuf) * 769 + gtile->tx * 53 + gtile->ty * 97;
104
104
static int imb_global_tile_cmp(const void *a_p, const void *b_p)
106
const ImGlobalTile *a= a_p;
107
const ImGlobalTile *b= b_p;
106
const ImGlobalTile *a = a_p;
107
const ImGlobalTile *b = b_p;
109
109
if (a->ibuf == b->ibuf && a->tx == b->tx && a->ty == b->ty) return 0;
110
110
else if (a->ibuf < b->ibuf || a->tx < b->tx || a->ty < b->ty) return -1;
114
114
static unsigned int imb_thread_tile_hash(const void *ttile_p)
116
const ImThreadTile *ttile= ttile_p;
116
const ImThreadTile *ttile = ttile_p;
118
return ((unsigned int)(intptr_t)ttile->ibuf)*769 + ttile->tx*53 + ttile->ty*97;
118
return ((unsigned int)(intptr_t)ttile->ibuf) * 769 + ttile->tx * 53 + ttile->ty * 97;
121
121
static int imb_thread_tile_cmp(const void *a_p, const void *b_p)
123
const ImThreadTile *a= a_p;
124
const ImThreadTile *b= b_p;
123
const ImThreadTile *a = a_p;
124
const ImThreadTile *b = b_p;
126
126
if (a->ibuf == b->ibuf && a->tx == b->tx && a->ty == b->ty) return 0;
127
127
else if (a->ibuf < b->ibuf || a->tx < b->tx || a->ty < b->ty) return -1;
133
133
static void imb_global_cache_tile_load(ImGlobalTile *gtile)
135
ImBuf *ibuf= gtile->ibuf;
136
int toffs= ibuf->xtiles*gtile->ty + gtile->tx;
135
ImBuf *ibuf = gtile->ibuf;
136
int toffs = ibuf->xtiles * gtile->ty + gtile->tx;
137
137
unsigned int *rect;
139
rect = MEM_callocN(sizeof(unsigned int)*ibuf->tilex*ibuf->tiley, "imb_tile");
139
rect = MEM_callocN(sizeof(unsigned int) * ibuf->tilex * ibuf->tiley, "imb_tile");
140
140
imb_loadtile(ibuf, gtile->tx, gtile->ty, rect);
141
ibuf->tiles[toffs]= rect;
141
ibuf->tiles[toffs] = rect;
144
144
static void imb_global_cache_tile_unload(ImGlobalTile *gtile)
146
ImBuf *ibuf= gtile->ibuf;
147
int toffs= ibuf->xtiles*gtile->ty + gtile->tx;
146
ImBuf *ibuf = gtile->ibuf;
147
int toffs = ibuf->xtiles * gtile->ty + gtile->tx;
149
149
MEM_freeN(ibuf->tiles[toffs]);
150
ibuf->tiles[toffs]= NULL;
150
ibuf->tiles[toffs] = NULL;
152
GLOBAL_CACHE.totmem -= sizeof(unsigned int)*ibuf->tilex*ibuf->tiley;
152
GLOBAL_CACHE.totmem -= sizeof(unsigned int) * ibuf->tilex * ibuf->tiley;
155
155
/* external free */
187
187
memset(cache, 0, sizeof(ImThreadTileCache));
189
cache->tilehash= BLI_ghash_new(imb_thread_tile_hash, imb_thread_tile_cmp, "imb_thread_cache_init gh");
189
cache->tilehash = BLI_ghash_new(imb_thread_tile_hash, imb_thread_tile_cmp, "imb_thread_cache_init gh");
191
191
/* pre-allocate all thread local tiles in unused list */
192
for (a=0; a<IB_THREAD_CACHE_SIZE; a++) {
193
ttile= BLI_memarena_alloc(GLOBAL_CACHE.memarena, sizeof(ImThreadTile));
192
for (a = 0; a < IB_THREAD_CACHE_SIZE; a++) {
193
ttile = BLI_memarena_alloc(GLOBAL_CACHE.memarena, sizeof(ImThreadTile));
194
194
BLI_addtail(&cache->unused, ttile);
221
221
if (GLOBAL_CACHE.initialized) {
222
for (gtile=GLOBAL_CACHE.tiles.first; gtile; gtile=gtile->next)
222
for (gtile = GLOBAL_CACHE.tiles.first; gtile; gtile = gtile->next)
223
223
imb_global_cache_tile_unload(gtile);
225
for (a=0; a<GLOBAL_CACHE.totthread; a++)
225
for (a = 0; a < GLOBAL_CACHE.totthread; a++)
226
226
imb_thread_cache_exit(&GLOBAL_CACHE.thread_cache[a]);
228
228
if (GLOBAL_CACHE.memarena)
254
254
memset(&GLOBAL_CACHE, 0, sizeof(ImGlobalTileCache));
256
GLOBAL_CACHE.tilehash= BLI_ghash_new(imb_global_tile_hash, imb_global_tile_cmp, "tile_cache_params gh");
256
GLOBAL_CACHE.tilehash = BLI_ghash_new(imb_global_tile_hash, imb_global_tile_cmp, "tile_cache_params gh");
258
GLOBAL_CACHE.memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "ImTileCache arena");
258
GLOBAL_CACHE.memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "ImTileCache arena");
259
259
BLI_memarena_use_calloc(GLOBAL_CACHE.memarena);
261
GLOBAL_CACHE.maxmem= maxmem*1024*1024;
261
GLOBAL_CACHE.maxmem = maxmem * 1024 * 1024;
263
GLOBAL_CACHE.totthread= totthread;
264
for (a=0; a<totthread; a++)
263
GLOBAL_CACHE.totthread = totthread;
264
for (a = 0; a < totthread; a++)
265
265
imb_thread_cache_init(&GLOBAL_CACHE.thread_cache[a]);
267
267
BLI_mutex_init(&GLOBAL_CACHE.mutex);
301
301
/* first check if we hit the memory limit */
302
302
if (GLOBAL_CACHE.maxmem && GLOBAL_CACHE.totmem > GLOBAL_CACHE.maxmem) {
303
303
/* find an existing tile to unload */
304
for (gtile=GLOBAL_CACHE.tiles.last; gtile; gtile=gtile->prev)
304
for (gtile = GLOBAL_CACHE.tiles.last; gtile; gtile = gtile->prev)
305
305
if (gtile->refcount == 0 && gtile->loading == 0)
316
316
/* allocate a new tile or reuse unused */
317
317
if (GLOBAL_CACHE.unused.first) {
318
gtile= GLOBAL_CACHE.unused.first;
318
gtile = GLOBAL_CACHE.unused.first;
319
319
BLI_remlink(&GLOBAL_CACHE.unused, gtile);
322
gtile= BLI_memarena_alloc(GLOBAL_CACHE.memarena, sizeof(ImGlobalTile));
322
gtile = BLI_memarena_alloc(GLOBAL_CACHE.memarena, sizeof(ImGlobalTile));
325
325
/* setup new tile */
332
332
BLI_ghash_insert(GLOBAL_CACHE.tilehash, gtile, gtile);
333
333
BLI_addhead(&GLOBAL_CACHE.tiles, gtile);
335
335
/* mark as being loaded and unlock to allow other threads to load too */
336
GLOBAL_CACHE.totmem += sizeof(unsigned int)*ibuf->tilex*ibuf->tiley;
336
GLOBAL_CACHE.totmem += sizeof(unsigned int) * ibuf->tilex * ibuf->tiley;
338
338
BLI_mutex_unlock(&GLOBAL_CACHE.mutex);
354
354
ImThreadTile *ttile, lookuptile;
355
355
ImGlobalTile *gtile, *replacetile;
356
int toffs= ibuf->xtiles*ty + tx;
356
int toffs = ibuf->xtiles * ty + tx;
358
358
/* test if it is already in our thread local cache */
359
if ((ttile=cache->tiles.first)) {
359
if ((ttile = cache->tiles.first)) {
360
360
/* check last used tile before going to hash */
361
361
if (ttile->ibuf == ibuf && ttile->tx == tx && ttile->ty == ty)
362
362
return ibuf->tiles[toffs];
366
366
lookuptile.tx = tx;
367
367
lookuptile.ty = ty;
369
if ((ttile=BLI_ghash_lookup(cache->tilehash, &lookuptile))) {
369
if ((ttile = BLI_ghash_lookup(cache->tilehash, &lookuptile))) {
370
370
BLI_remlink(&cache->tiles, ttile);
371
371
BLI_addhead(&cache->tiles, ttile);
377
377
/* not found, have to do slow lookup in global cache */
378
378
if (cache->unused.first == NULL) {
379
ttile= cache->tiles.last;
380
replacetile= ttile->global;
379
ttile = cache->tiles.last;
380
replacetile = ttile->global;
381
381
BLI_remlink(&cache->tiles, ttile);
382
382
BLI_ghash_remove(cache->tilehash, ttile, NULL, NULL);
385
ttile= cache->unused.first;
385
ttile = cache->unused.first;
387
387
BLI_remlink(&cache->unused, ttile);
390
390
BLI_addhead(&cache->tiles, ttile);
391
391
BLI_ghash_insert(cache->tilehash, ttile, ttile);
393
gtile= imb_global_cache_get_tile(ibuf, tx, ty, replacetile);
393
gtile = imb_global_cache_get_tile(ibuf, tx, ty, replacetile);
395
ttile->ibuf= gtile->ibuf;
396
ttile->tx= gtile->tx;
397
ttile->ty= gtile->ty;
398
ttile->global= gtile;
395
ttile->ibuf = gtile->ibuf;
396
ttile->tx = gtile->tx;
397
ttile->ty = gtile->ty;
398
ttile->global = gtile;
400
400
return ibuf->tiles[toffs];
403
403
unsigned int *IMB_gettile(ImBuf *ibuf, int tx, int ty, int thread)
405
return imb_thread_cache_get_tile(&GLOBAL_CACHE.thread_cache[thread+1], ibuf, tx, ty);
405
return imb_thread_cache_get_tile(&GLOBAL_CACHE.thread_cache[thread + 1], ibuf, tx, ty);
408
408
void IMB_tiles_to_rect(ImBuf *ibuf)
412
412
unsigned int *to, *from;
413
413
int a, tx, ty, y, w, h;
415
for (a=0; a<ibuf->miptot; a++) {
416
mipbuf= IMB_getmipmap(ibuf, a);
415
for (a = 0; a < ibuf->miptot; a++) {
416
mipbuf = IMB_getmipmap(ibuf, a);
418
418
/* don't call imb_addrectImBuf, it frees all mipmaps */
419
419
if (!mipbuf->rect) {
420
if ((mipbuf->rect = MEM_mapallocN(ibuf->x*ibuf->y*sizeof(unsigned int), "imb_addrectImBuf"))) {
420
if ((mipbuf->rect = MEM_mapallocN(ibuf->x * ibuf->y * sizeof(unsigned int), "imb_addrectImBuf"))) {
421
421
mipbuf->mall |= IB_rect;
422
422
mipbuf->flags |= IB_rect;
428
for (ty=0; ty<mipbuf->ytiles; ty++) {
429
for (tx=0; tx<mipbuf->xtiles; tx++) {
428
for (ty = 0; ty < mipbuf->ytiles; ty++) {
429
for (tx = 0; tx < mipbuf->xtiles; tx++) {
430
430
/* acquire tile through cache, this assumes cache is initialized,
431
431
* which it is always now but it's a weak assumption ... */
432
gtile= imb_global_cache_get_tile(mipbuf, tx, ty, NULL);
432
gtile = imb_global_cache_get_tile(mipbuf, tx, ty, NULL);
434
434
/* setup pointers */
435
from= mipbuf->tiles[mipbuf->xtiles*ty + tx];
436
to= mipbuf->rect + mipbuf->x*ty*mipbuf->tiley + tx*mipbuf->tilex;
435
from = mipbuf->tiles[mipbuf->xtiles * ty + tx];
436
to = mipbuf->rect + mipbuf->x * ty * mipbuf->tiley + tx * mipbuf->tilex;
438
438
/* exception in tile width/height for tiles at end of image */
439
w= (tx == mipbuf->xtiles-1)? mipbuf->x - tx*mipbuf->tilex: mipbuf->tilex;
440
h= (ty == mipbuf->ytiles-1)? mipbuf->y - ty*mipbuf->tiley: mipbuf->tiley;
439
w = (tx == mipbuf->xtiles - 1) ? mipbuf->x - tx * mipbuf->tilex : mipbuf->tilex;
440
h = (ty == mipbuf->ytiles - 1) ? mipbuf->y - ty * mipbuf->tiley : mipbuf->tiley;
442
for (y=0; y<h; y++) {
443
memcpy(to, from, sizeof(unsigned int)*w);
442
for (y = 0; y < h; y++) {
443
memcpy(to, from, sizeof(unsigned int) * w);
444
444
from += mipbuf->tilex;