59#define _cache_print(channel, ...) \
61 if(_verbose) dt_print((channel), __VA_ARGS__); \
139 fprintf(stderr,
"%s\n %s\n", message, item);
141 fprintf(stderr,
"%s\n", message);
155 return g_strdup_printf(_(
"The pipeline cache is full while allocating\n"
156 "`%s` (module `%s`).\n"
157 "Either your RAM settings are too frugal or your RAM is too small."),
160 return g_strdup_printf(_(
"The pipeline cache is full while allocating\n"
162 "Either your RAM settings are too frugal or your RAM is too small."),
165 return g_strdup_printf(_(
"The pipeline cache is full while processing module\n"
167 "Either your RAM settings are too frugal or your RAM is too small."),
169 return g_strdup(_(
"The pipeline cache is full.\n"
170 "Either your RAM settings are too frugal or your RAM is too small."));
184 item = g_strdup_printf(_(
"`%s` (module `%s`)"),
name, module);
186 item = g_strdup_printf(_(
"module `%s`"), module);
188 item = g_strdup(
name);
189 gchar *message = g_strdup_printf(
"%s\n%s",
190 _(
"The pipeline cache is full.\n"
191 "Either your RAM settings are too frugal or your RAM is too small."),
192 _(
"The module fails and the image is not updated: what is shown stays "
193 "the last complete rendering, until the next change tries again."));
240 void *data,
void *cl_mem_output,
const int preferred_devid,
const gboolean verbose)
246 "[pixelpipe_cache] exact-hit %s req=%" PRIu64
" entry=%" PRIu64
"/%" PRIu64
247 " data=%p cl=%p refs=%i auto=%i dev=%i module=%s name=%s\n",
249 cache_entry ? cache_entry->
serial : 0, data, cl_mem_output,
252 (cache_entry && cache_entry->
name) ? cache_entry->
name :
"-");
295 const char *message);
301 const char *
name,
const int id);
303 const char *
name,
const int id,
308 gboolean prefer_device_payload);
375 if(!cache || !data)
return NULL;
383 g_hash_table_iter_init(&iter, cache->
entries);
384 while(g_hash_table_iter_next(&iter, &
key, &
value))
387 if(entry && entry->
data == data)
397 while(g_hash_table_iter_next(&iter, &
key, &
value))
400 if(entry && entry->
data == data)
415 return cache_entry->
size / (1024 * 1024);
424 "[pixelpipe] cache entry %" PRIu64
"/%" PRIu64
": %s (data=%p - %" G_GSIZE_FORMAT
" MiB - age %" PRId64
425 " - hits %i - refs %i - auto %i - ext %i - id %i - stale %i - module %s) %s\n",
427 cache_entry->
name ? cache_entry->
name :
"-", cache_entry->
data,
469 const size_t found_size = found ? cache_entry->
size : 0;
487 gboolean found =
FALSE;
488 size_t found_size = 0;
511 found_size = cache_entry->
size;
540 if(!used && (!locked || force))
543 g_hash_table_remove(table, &cache_entry->
hash);
560 gboolean prefer_device_payload)
574 for(GList *l = g_list_first(entry->
cl_mem_list); l; l = g_list_next(l))
583 if(mem_devid != preferred_devid)
continue;
585 const gboolean host_backed = (c->host_ptr == entry->
data);
586 const gboolean device_only = (
IS_NULL_PTR(c->host_ptr));
587 if(!host_backed && !device_only)
continue;
590 if(!prefer_device_payload)
592 if(host_backed && (preferred_devid < 0 || mem_devid == preferred_devid))
594 else if(device_only && preferred_devid >= 0 && mem_devid == preferred_devid)
603 if(device_only && preferred_devid >= 0 && mem_devid == preferred_devid)
607 else if(host_backed && (preferred_devid < 0 || mem_devid == preferred_devid))
650 gboolean prefer_device_payload)
652 (
void)preferred_devid;
653 (
void)prefer_device_payload;
665 gboolean use_host_ptr =
TRUE;
669 use_host_ptr =
FALSE;
682 gboolean found =
FALSE;
684 for(GList *l = g_list_first(entry->
cl_mem_list); l; l = g_list_next(l))
706 gboolean flushed =
FALSE;
709 for(GList *l = g_list_first(entry->
cl_mem_list); l;)
711 GList *next = g_list_next(l);
756 if(devid < 0)
return;
768 g_hash_table_iter_init(&iter, cache->
entries);
769 while(g_hash_table_iter_next(&iter, &
key, &
value))
789 "[dt_dev_pixelpipe_cache_flush_clmem] entry %" PRIu64
" is in use (refcount=%i locked=%i), "
796 "[dt_dev_pixelpipe_cache_flush_clmem] trying to flush vRAM for entry %" PRIu64
" on device %d...\n",
805 g_hash_table_iter_remove(&iter);
866 if(age < lru->max_age)
868 gboolean used =
FALSE;
886 size_t *evictable = (
size_t *)user_data;
887 gboolean used =
FALSE;
890 evictable[0] += cache_entry->
size;
908 lru->
max_age = g_get_monotonic_time();
952 "[_pixel_cache_clmem_get] %u output entries in %" PRIu64
"\n",
955 for(GList *l = g_list_first(entry->
cl_mem_list); l;)
957 GList *next = g_list_next(l);
1001 for(GList *l = g_list_first(entry->
cl_mem_list); l; l = g_list_next(l))
1030 for(GList *l = entry->
cl_mem_list; l; l = g_list_next(l))
1033 if(c && c->mem == mem)
1035 if(c->refs > 0) c->refs--;
1059 cl_mem clmem = (cl_mem)mem;
1063 for(GList *l = g_list_first(entry->
cl_mem_list); l; l = g_list_next(l))
1075 if(c->refs > 0)
continue;
1079 c->host_ptr = host_ptr;
1094 c->host_ptr = host_ptr;
1108 GList *next = g_list_next(l);
1110 if(c && c->mem == mem)
1126 GList *next = g_list_next(l);
1146 gboolean *out_reused)
1150 if(devid < 0 ||
width <= 0 ||
height <= 0 ||
bpp <= 0)
return NULL;
1156 if(!use_pinned)
flags &= ~CL_MEM_USE_HOST_PTR;
1182 gboolean synced =
FALSE;
1267 if(mem) *mem = NULL;
1290 const char *message)
1292 return module && message && bpp == 4 * sizeof(uint8_t) && strcmp(module->op, "gamma") == 0
1293 && strcmp(message, "output") == 0;
1308 gboolean *out_reused,
void *keep)
1311 void *cl_mem_input = NULL;
1312 gboolean reused_from_cache =
FALSE;
1318 if(out_reused) *out_reused =
FALSE;
1322 const int flags = CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR;
1348 (
int)
bpp, CL_MEM_READ_WRITE);
1366 else if(reused_from_cache)
1372 "[dev_pixelpipe] reused GPU buffer from cache (hits=%d, misses=%d) for module %s %s\n",
1373 hits, misses, module->name(), message);
1380 if(out_reused) *out_reused = reused_from_cache;
1381 return cl_mem_input;
1407 void *host_ptr,
const gboolean cache_device)
1411 cl_mem mem = *cl_mem_buffer;
1421 *cl_mem_buffer = NULL;
1460 const cl_mem mem = (cl_mem)cl_mem_buffer;
1469 "[dev_pixelpipe] successfully synced image %s via map/unmap for module %s (%s)\n",
1470 (cl_mode == CL_MAP_WRITE) ?
"host to device" :
"device to host",
1471 (module) ? module->
op :
"base buffer", message);
1477 cl_int err = CL_SUCCESS;
1478 if(cl_mode == CL_MAP_WRITE)
1480 else if(cl_mode == CL_MAP_READ)
1485 if(err != CL_SUCCESS)
1488 (cl_mode == CL_MAP_WRITE) ?
"host to device" :
"device to host",
1489 (module) ? module->
op :
"base buffer", message);
1494 (cl_mode == CL_MAP_WRITE) ?
"host to device" :
"device to host",
1495 (module) ? module->
op :
"base buffer", message);
1516 const char *message)
1522 CL_MAP_READ, in_bpp, module, message);
1525 return fail ? NULL : input;
1556 float *input,
void **cl_mem_input,
1562 *locked_input_entry = NULL;
1571 const cl_mem mem = (cl_mem)*cl_mem_input;
1575 *locked_input_entry = input_entry;
1589 gboolean input_reused_from_cache =
FALSE;
1591 "input", input_entry,
1592 &input_reused_from_cache, keep);
1598 gboolean keep_lock =
FALSE;
1600 if(!fail && *cl_mem_input)
1602 mem = (cl_mem)*cl_mem_input;
1610 if(!fail && mem && !keep_lock && !input_reused_from_cache)
1614 if(err != CL_SUCCESS)
1617 (module) ? module->
op :
"base buffer",
"cache to input");
1623 (module) ? module->
op :
"base buffer",
"cache to input");
1631 *locked_input_entry = input_entry;
1635 return fail ? 1 : 0;
1641 gboolean *out_reused,
void *keep)
1651 if(out_reused) *out_reused =
FALSE;
1657 const char *message,
void *keep)
1669 void *host_ptr, gboolean cache_device)
1674 if(cl_mem_buffer) *cl_mem_buffer = NULL;
1683 (
void)cl_mem_buffer;
1696 const char *message)
1709 float *input,
void **cl_mem_input,
1722 (
void)locked_input_entry;
1746#define DT_PIXELPIPE_CACHE_PRESSURE_EXEMPT_SIZE ((size_t)1024 * 1024)
1749#define DT_PIXELPIPE_CACHE_PRESSURE_ALERT_PERIOD_US ((gint64)10 * G_USEC_PER_SEC)
1781 if(pressure_floor == 0)
return TRUE;
1785 gint64 now = g_get_monotonic_time();
1786 const gint64 PROBE_PERIOD_US = 100000;
1806 const size_t deficit = request_size + pressure_floor - cache->
sys_available_est;
1810 while(freed < deficit && g_hash_table_size(cache->
entries) > 0)
1833 if(freed || !negligible)
1844 "[pixelpipe_cache] system memory pressure: shed %" G_GSIZE_FORMAT
" MiB of cache "
1845 "(%" G_GSIZE_FORMAT
" MiB available after trim, floor %" G_GSIZE_FORMAT
" MiB)\n",
1847 pressure_floor / (1024 * 1024));
1870 const gboolean allowed = negligible
1890 const char *
module = dt_pixelpipe_cache_current_module;
1893 gchar *who = g_strdup_printf(
"%s\n%s", module ? module :
"", image ? image :
"");
1900 gint64 *when = g_new(gint64, 1);
1909 const double request_mib = (
double)request_size / (1024 * 1024);
1910 const double left_mib
1914 item = g_strdup_printf(_(
"%.2f MiB: only %.2f MiB available"), request_mib, left_mib);
1916 item = g_strdup_printf(_(
"%.2f MiB for module `%s`: only %.2f MiB available"), request_mib, module,
1919 item = g_strdup_printf(_(
"%.2f MiB for module `%s` on %s: only %.2f MiB available"),
1920 request_mib, module, image, left_mib);
1921 _alert_user(_(
"Your system is running out of memory:\n"
1922 "A module could not get the memory it needs, "
1923 "so it fails and the image is not updated.\n\n"
1924 "Close other applications or add more RAM to your system."),
1929 "[pixelpipe_cache] refusing to allocate %" G_GSIZE_FORMAT
" MiB: the system has only "
1930 "%" G_GSIZE_FORMAT
" MiB of available RAM left (pressure floor: %" G_GSIZE_FORMAT
" MiB)\n",
1932 pressure_floor / (1024 * 1024));
1943 size_t *actual_size, gboolean *system_refused)
1948 if(*system_refused)
return NULL;
1953 uint32_t pages_needed = 0;
1957 uint32_t total_free_pages = 0, largest_free_run_pages = 0;
1960 while(largest_free_run_pages < pages_needed && g_hash_table_size(cache->
entries) > 0)
1972 uint32_t *largest_pages,
size_t *total_bytes,
size_t *largest_bytes)
1976 if(total_bytes) *total_bytes = (size_t)(*total_pages) * page_size;
1977 if(largest_bytes) *largest_bytes = (size_t)(*largest_pages) * page_size;
1989 uint32_t total_pages = 0, largest_pages = 0;
1990 size_t total_bytes = 0, largest_bytes = 0;
1992 _arena_stats_bytes(cache, &total_pages, &largest_pages, &total_bytes, &largest_bytes);
1994 return largest_bytes;
1998 const char *entry_name,
const char *module,
uint64_t hash,
1999 gboolean name_is_file, gboolean system_refused)
2003 uint32_t total_free_pages = 0, largest_free_run_pages = 0;
2004 size_t total_free_bytes = 0, largest_free_bytes = 0;
2005 _arena_stats_bytes(cache, &total_free_pages, &largest_free_run_pages, &total_free_bytes, &largest_free_bytes);
2009 "[pixelpipe_cache] failed to allocate %" G_GSIZE_FORMAT
" bytes for entry %" PRIu64
" (%s, module=%s) "
2010 "[arena largest=%" G_GSIZE_FORMAT
" MiB, total=%" G_GSIZE_FORMAT
" MiB, cache=%" G_GSIZE_FORMAT
"/%" G_GSIZE_FORMAT
" MiB]\n",
2011 request_size,
hash, entry_name, module ? module :
"unknown",
2012 largest_free_bytes / (1024 * 1024), total_free_bytes / (1024 * 1024),
2016 "[pixelpipe_cache] failed to allocate %" G_GSIZE_FORMAT
" bytes for entry %" PRIu64
" (module=%s) "
2017 "[arena largest=%" G_GSIZE_FORMAT
" MiB, total=%" G_GSIZE_FORMAT
" MiB, cache=%" G_GSIZE_FORMAT
"/%" G_GSIZE_FORMAT
" MiB]\n",
2018 request_size,
hash, module ? module :
"unknown",
2019 largest_free_bytes / (1024 * 1024), total_free_bytes / (1024 * 1024),
2044 for(GList *l = g_list_first(entry->
cl_mem_list); l;)
2046 GList *next = g_list_next(l);
2057 gboolean referenced = c->refs > 0;
2060 if(referenced || not_ours)
2066 "[dt_dev_pixelpipe_cache_flush_clmem] for entry %" PRIu64
": couldn't flush %p "
2067 "(referenced=%i not ours=%i)\n",
2068 entry->
hash, c->mem, referenced, not_ours);
2083 const gboolean empty
2101 gboolean system_refused =
FALSE;
2106 const char *
module = dt_pixelpipe_cache_current_module;
2108 cache_entry->
hash,
FALSE, system_refused);
2112 return cache_entry->
data;
2132 return entry ? entry->
size : 0;
2212 const char *
module = dt_pixelpipe_cache_current_module;
2213 const gboolean name_is_file = (!
IS_NULL_PTR(
name)) && (strchr(
name,
'/') != NULL) && (strchr(
name,
':') != NULL);
2217 fprintf(stdout,
"[pixelpipe] cache is full, cannot allocate new entry %" PRIu64
" (%s)\n",
hash,
name);
2219 fprintf(stdout,
"[pixelpipe] cache is full, cannot allocate new entry (%s)\n",
name);
2252 if(
error)
return NULL;
2255 size_t page_size = 0;
2256 gboolean system_refused =
FALSE;
2285 cache_entry->
data = aligned;
2303 fprintf(stdout,
"error while freeing cache entry: no entry found but we have a buffer, %s.\n", message);
2318 const char *
name,
const int id,
2322 uint32_t pages_needed = 0;
2323 size_t rounded_size = 0;
2326 fprintf(stderr,
"[pixelpipe] invalid cache entry size %" G_GSIZE_FORMAT
" for %s\n",
size,
name);
2331 if(
error)
return NULL;
2337 cache_entry->
size = rounded_size;
2342 cache_entry->
hits = 0;
2345 cache_entry->
id = id;
2350 cache_entry->
data = NULL;
2351 cache_entry->
cache = cache;
2366 cache_entry->
name = g_strdup(
name);
2379 g_hash_table_insert(table,
key, cache_entry);
2407 fprintf(stderr,
"[pixelpipe] cache entry %p has a corrupted back-reference (%p, expected %p); "
2408 "skipping arena free to avoid a crash\n",
2413 if(cache_entry->
data && cache)
2417 for(GList *l = cache_entry->
cl_mem_list; l; l = g_list_next(l))
2455 cache_entry->
data = NULL;
2467 const gboolean verbose_detail)
2500 g_hash_table_destroy(cache->
entries);
2545 g_hash_table_destroy(cache->
entries);
2556 const char *
name,
const int id)
2578 if(reuse_hint->
size <
size)
return NULL;
2582 if(cache_entry->
serial != reuse_hint->
serial)
return NULL;
2584 if(cache_entry->
size <
size)
return NULL;
2616 for(GList *l = cache_entry->
cl_mem_list; l; l = g_list_next(l))
2619 if(c && c->refs > 0)
2631 gpointer stolen_key = NULL;
2632 gpointer stolen_value = NULL;
2633 if(!g_hash_table_steal_extended(cache->
entries, &old_hash, &stolen_key, &stolen_value)
2634 || stolen_value != cache_entry)
2636 if(stolen_key && stolen_value) g_hash_table_insert(cache->
entries, stolen_key, stolen_value);
2643 *(
uint64_t *)stolen_key = new_hash;
2644 cache_entry->
hash = new_hash;
2648 g_hash_table_insert(cache->
entries, stolen_key, cache_entry);
2653 "[pixelpipe_cache] writable rekey old=%" PRIu64
" new=%" PRIu64
" entry=%" PRIu64
"/%" PRIu64
2654 " refs=%i auto=%i data=%p module=%s\n",
2655 old_hash, new_hash, cache_entry->
hash, cache_entry->
serial,
2663 const size_t size,
const char *
name,
const int id,
2664 const gboolean alloc,
void **data,
2672 if(data) *data = NULL;
2673 if(entry) *entry = NULL;
2692 cache_entry->
hits++;
2705 if(entry) *entry = cache_entry;
2717 if(entry) *entry = NULL;
2731 if(entry) *entry = cache_entry;
2737 const size_t size,
const char *
name,
const int id,
2738 const gboolean alloc,
const gboolean allow_rekey_reuse,
2747 if(data) *data = NULL;
2748 if(entry) *entry = NULL;
2770 cache_entry->
hits++;
2780 if(allow_rekey_reuse)
2794 if(entry) *entry = cache_entry;
2803 if(data) *data = NULL;
2804 if(entry) *entry = NULL;
2812 if(entry) *entry = cache_entry;
2824 const size_t hit_size = hit ? cache_entry->
size : 0;
2828 cache_entry->
hits++;
2841 const int preferred_devid,
void **cl_mem_output)
2849 GList *next = g_list_next(l);
2855 *cl_mem_output = c->mem;
2868 const int preferred_devid,
void **cl_mem_output)
2875 const int preferred_devid,
void **data)
2878 if(data) *data = NULL;
2898 void **cl_mem_output)
2901 if(data) *data = NULL;
2902 if(entry) *entry = NULL;
2903 if(cl_mem_output) *cl_mem_output = NULL;
2920 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2921 if(data) *data = NULL;
2928 if(entry) *entry = cache_entry;
2938 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2939 if(data) *data = NULL;
2949 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2950 if(entry) *entry = cache_entry;
2959 if(preferred_devid < 0)
2968 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2969 if(entry) *entry = cache_entry;
2976 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2977 if(entry) *entry = cache_entry;
2982 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2984 "[pixelpipe] cache entry %" PRIu64
" has no authoritative RAM nor vRAM payload and will be removed\n",
2993 if(data) *data = NULL;
3001 const int id = GPOINTER_TO_INT(user_data);
3013 return (cache_entry->
id ==
id ||
id == -1) && !used && !locked;
3035 for(
size_t k = 0;
k < count;
k++)
3059 int64_t *newest = (int64_t *)user_data;
3061 if(age > *newest) *newest = age;
3069 const int64_t cutoff = *(
const int64_t *)user_data;
3083 return too_old && !used && !locked;
3105 int64_t newest = INT64_MIN;
3107 if(newest != INT64_MIN)
3110 const int64_t ten_min = 10 * 60 * 1000 * 1000;
3111 int64_t cutoff = newest - ten_min;
3124 if(available > 0 && pressure_floor > 0 && available < 2 * pressure_floor)
3126 return G_SOURCE_CONTINUE;
3146 if(pressure_floor == 0)
return G_SOURCE_CONTINUE;
3149 if(available == 0 || available >= pressure_floor)
return G_SOURCE_CONTINUE;
3155 const size_t deficit = pressure_floor - available;
3158 while(freed < deficit && g_hash_table_size(cache->
entries) > 0)
3177 "[pixelpipe_cache] system memory pressure while idle: %" G_GSIZE_FORMAT
" MiB available "
3178 "under the %" G_GSIZE_FORMAT
" MiB floor — shed %" G_GSIZE_FORMAT
" MiB of cache, "
3179 "returned %" G_GSIZE_FORMAT
" MiB to the OS, now %" G_GSIZE_FORMAT
" MiB available\n",
3180 available / (1024 * 1024), pressure_floor / (1024 * 1024), freed / (1024 * 1024),
3181 trimmed / (1024 * 1024), available_after / (1024 * 1024));
3182 return G_SOURCE_CONTINUE;
3316 if(old_hash == new_hash)
return 0;
3324 "[pixelpipe_cache] rekey miss old=%" PRIu64
" new=%" PRIu64
" module=%s\n",
3331 if(conflict && conflict != entry)
3334 "[pixelpipe_cache] rekey conflict old=%" PRIu64
" new=%" PRIu64
3335 " entry=%" PRIu64
"/%" PRIu64
" conflict=%" PRIu64
"/%" PRIu64
" module=%s\n",
3342 gpointer stolen_key = NULL;
3343 gpointer stolen_value = NULL;
3344 if(!g_hash_table_steal_extended(cache->
entries, &old_hash, &stolen_key, &stolen_value))
3347 "[pixelpipe_cache] rekey steal-miss old=%" PRIu64
" new=%" PRIu64
3348 " entry=%" PRIu64
"/%" PRIu64
" module=%s\n",
3354 if(stolen_value != entry)
3357 "[pixelpipe_cache] rekey stolen-entry mismatch old=%" PRIu64
" new=%" PRIu64
3358 " expected=%" PRIu64
"/%" PRIu64
" got=%" PRIu64
"/%" PRIu64
" module=%s\n",
3359 old_hash, new_hash, entry->
hash, entry->
serial,
3362 g_hash_table_insert(cache->
entries, stolen_key, stolen_value);
3371 for(GList *l = entry->
cl_mem_list; l; l = g_list_next(l))
3374 if(c && c->refs > 0)
3377 g_hash_table_insert(cache->
entries, stolen_key, stolen_value);
3385 *(
uint64_t *)stolen_key = new_hash;
3386 entry->
hash = new_hash;
3387 g_hash_table_insert(cache->
entries, stolen_key, stolen_value);
3389 "[pixelpipe_cache] rekey old=%" PRIu64
" new=%" PRIu64
" entry=%" PRIu64
"/%" PRIu64
3390 " refs=%i auto=%i data=%p module=%s\n",
3406 _cache_print(
DT_DEBUG_PIPECACHE,
"[pixelpipe] cache hit rate so far: %.3f%% - size: %" G_GSIZE_FORMAT
" MiB over %" G_GSIZE_FORMAT
" MiB - %i items\n",
3409 g_hash_table_size(cache->
entries));
3415 if(current) *current = 0;
3429 size_t evictable[2] = { 0, 0 };
3441 if(sys_available == 0)
return budget_room;
3444 const size_t sys_room
3445 = ((sys_available > pressure_floor) ? sys_available - pressure_floor : 0) + evictable[1];
3446 return MIN(budget_room, sys_room);
3464 const int64_t now,
const int num_devices)
3468 g_hash_table_iter_init(&it, table);
3469 while(g_hash_table_iter_next(&it, &
key, &
value))
3487 const char *src = (allocations && e->
name) ? g_strrstr(e->
name,
"/src/") : NULL;
3496 for(GList *l = e->
cl_mem_list; l; l = g_list_next(l))
3512 if(devid >= 0 && devid < num_devices)
3522 g_array_append_val(
out, s);
3534 const int64_t now = g_get_monotonic_time();
static void error(char *msg)
void dt_atomic_set_int(dt_atomic_int *var, int value)
int dt_atomic_get_int(dt_atomic_int *var)
uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
int dt_atomic_sub_int(dt_atomic_int *var, int decr)
int dt_atomic_add_int(dt_atomic_int *var, int incr)
void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_invalidate_system_available_mem(void)
size_t dt_get_system_available_mem(void)
size_t dt_get_memory_pressure_floor(void)
static int dt_pthread_rwlock_wrlock(dt_pthread_rwlock_t *rwlock) ACQUIRE(rwlock) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_rwlock_trywrlock(dt_pthread_rwlock_t *rwlock) TRY_ACQUIRE(0
static int dt_pthread_rwlock_unlock(dt_pthread_rwlock_t *rwlock) RELEASE_GENERIC(rwlock) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_rwlock_rdlock(dt_pthread_rwlock_t *rwlock) ACQUIRE_SHARED(rwlock) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Initialise a mutex. With mutexattr NULL – which is how 54 of the 56 call sites in this tree spell it ...
static int dt_pthread_rwlock_destroy(dt_pthread_rwlock_t *lock)
static int dt_pthread_rwlock_tryrdlock(dt_pthread_rwlock_t *rwlock) TRY_ACQUIRE_SHARED(0
static int dt_pthread_mutex_trylock(dt_pthread_mutex_t *mutex) TRY_ACQUIRE(0
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
static int dt_pthread_rwlock_init(dt_pthread_rwlock_t *lock, const pthread_rwlockattr_t *attr)
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
static const dt_dev_pixelpipe_t * pipe
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
#define DT_CACHELINE_BYTES
void dt_cache_arena_stats(dt_cache_arena_t *a, uint32_t *out_total_free_pages, uint32_t *out_largest_free_run_pages)
void dt_cache_arena_cleanup(dt_cache_arena_t *a)
gboolean dt_cache_arena_calc(const dt_cache_arena_t *a, size_t size, uint32_t *out_pages, size_t *out_size)
int dt_cache_arena_init(dt_cache_arena_t *a, size_t total_size)
void dt_cache_arena_free(dt_cache_arena_t *a, void *ptr, size_t size)
void * dt_cache_arena_alloc(dt_cache_arena_t *a, size_t size, size_t *out_size)
size_t dt_cache_arena_trim(dt_cache_arena_t *a)
dt_mipmap_buffer_dsc_flags flags
void * dt_opencl_alloc_device_use_host_pointer(const int devid, const int width, const int height, const int bpp, void *host, const int flags)
size_t dt_opencl_get_mem_object_size(cl_mem mem)
gboolean dt_opencl_is_pinned_memory(cl_mem mem)
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
int dt_opencl_is_inited(void)
int dt_opencl_get_mem_context_id(cl_mem mem)
int dt_opencl_get_image_height(cl_mem mem)
void dt_opencl_reserve_device_by_id(const int devid)
Reserve a device the caller has already identified, blocking until it is free.
int dt_opencl_try_reserve_device_by_id(const int devid)
Reserve a device only if it is free right now.
int dt_opencl_unmap_mem_object(const int devid, cl_mem mem_object, void *mapped_ptr)
gboolean dt_opencl_use_pinned_memory(const int devid)
int dt_opencl_get_image_width(cl_mem mem)
void * dt_opencl_map_image(const int devid, cl_mem buffer, const int blocking, const int flags, size_t width, size_t height, int bpp)
gboolean dt_opencl_finish(const int devid)
void dt_opencl_events_wait_for(const int devid)
int dt_opencl_read_host_from_device(const int devid, void *host, void *device, const int width, const int height, const int bpp)
void dt_opencl_release_device(const int devid)
Release a device reserved by either reserve function.
void dt_opencl_release_mem_object(cl_mem mem)
int dt_opencl_get_image_element_size(cl_mem mem)
int dt_opencl_get_num_devices(void)
Number of usable OpenCL devices; 0 when OpenCL is unavailable.
gboolean dt_opencl_get_mem_record(cl_mem mem, int *devid, size_t *size)
int dt_opencl_write_host_to_device(const int devid, void *host, void *device, const int width, const int height, const int bpp)
#define DT_OPENCL_BPP_ENCODE_RGBA8(bpp)
static __thread const char * dt_pixelpipe_cache_current_module
void dt_dev_pixelpipe_cache_wrlock_entry(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the write lock on the entry.
static const char * _cache_debug_module_name(void)
static size_t _pressure_held(void *user)
static void _trace_exact_hit(const char *phase, const uint64_t hash, dt_pixel_cache_entry_t *cache_entry, void *data, void *cl_mem_output, const int preferred_devid, const gboolean verbose)
void * dt_dev_pixelpipe_cache_borrow_cl_payload(dt_pixel_cache_entry_t *entry, int devid, int width, int height, int bpp)
Borrow a cached OpenCL payload attached to a cache entry.
static void _pressure_wake(void *user)
GArray * dt_dev_pixelpipe_cache_get_entries_stats(void)
static void _observe_rekey(uint64_t old_hash, uint64_t new_hash)
static int _free_space_to_alloc(dt_dev_pixelpipe_cache_t *cache, const size_t size, const uint64_t hash, const char *name)
static gboolean _cache_entry_clmem_flush_device(dt_pixel_cache_entry_t *entry, const int devid)
int dt_dev_pixelpipe_cache_invalidate_hashes(const uint64_t *hashes, const size_t count)
Invalidate cache lines matching an explicit list of hashes.
void * dt_dev_pixelpipe_cache_get_pinned_image(void *host_ptr, dt_pixel_cache_entry_t *entry_hint, int devid, int width, int height, int bpp, int flags, gboolean *out_reused)
Acquire a pinned OpenCL image for a host buffer tracked by the pixelpipe cache.
static void _cache_get_newest(gpointer key, gpointer value, gpointer user_data)
static void _arena_stats_bytes(dt_dev_pixelpipe_cache_t *cache, uint32_t *total_pages, uint32_t *largest_pages, size_t *total_bytes, size_t *largest_bytes)
void dt_dev_pixelpipe_cache_unref_entry(dt_pixel_cache_entry_t *entry)
Release one reference held on entry, by POINTER.
const char * dt_pixelpipe_cache_set_current_image(const char *image)
Set the image the current module runs on, for the message that reports a refused allocation (thread-l...
size_t dt_dev_pixelpipe_cache_get_available(void)
static int pressure_shedding
static void _alert_user(const char *message, const char *item)
static void _log_arena_allocation_failure(dt_dev_pixelpipe_cache_t *cache, size_t request_size, const char *entry_name, const char *module, uint64_t hash, gboolean name_is_file, gboolean system_refused)
static __thread uint32_t dt_pixelpipe_cache_alloc_refusals
void dt_dev_pixelpipe_cache_cleanup(void)
Release everything dt_dev_pixelpipe_cache_init() created, the instance included. Only after a success...
void dt_dev_pixelpipe_cache_set_alert_handler(dt_pixelpipe_cache_alert_handler_t alert)
Install the alert handler. The GUI installs it, once it exists, apart from the others: without a GUI ...
static int garbage_collection
void * dt_pixelpipe_cache_alloc_align_cache_impl(size_t size, int id, const char *name)
Allocate aligned memory tracked by the pixelpipe cache. This allows LRU cache entries to be evicted i...
void * dt_pixel_cache_entry_get_data(dt_pixel_cache_entry_t *entry)
Peek the host pixels a cache entry holds for its current hash, without allocating.
static int dt_dev_pixelpipe_cache_flush_old(dt_dev_pixelpipe_cache_t *cache)
static void _stats_entry_clear(gpointer data)
static void _pixel_cache_clmem_remove(dt_pixel_cache_entry_t *entry, void *mem)
void dt_dev_pixelpipe_cache_ref_count_entry(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Take or release one reference on a cache line. A referenced line is never evicted,...
gboolean dt_dev_pixelpipe_cache_peek(const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry, const int preferred_devid, void **cl_mem_output)
Non-owning lookup of an existing cache line.
static dt_pixel_cache_entry_t * _cache_entry_for_host_ptr_locked(dt_dev_pixelpipe_cache_t *cache, void *host_ptr)
void dt_dev_pixelpipe_cache_flush_clmem(const int devid)
Release cached OpenCL buffers for a single device.
static void _cache_get_oldest(gpointer key, gpointer value, gpointer user_data)
int dt_dev_pixel_pipe_cache_remove_lru(void)
#define _cache_print(channel,...)
static dt_pixel_cache_entry_t * _pixelpipe_cache_create_entry_locked(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const size_t size, const char *name, const int id)
static void _print_cache_lines(gpointer key, gpointer value, gpointer user_data)
static void * _arena_alloc_with_defrag(dt_dev_pixelpipe_cache_t *cache, size_t request_size, size_t *actual_size, gboolean *system_refused)
static int64_t _pixel_cache_get_age(dt_pixel_cache_entry_t *cache_entry)
static void _observe_delete(uint64_t hash, size_t size, int owner_pipe_id, const char *name)
size_t dt_dev_pixelpipe_cache_get_max_memory(void)
static gchar * _cache_full_sentence(const char *name, const char *module)
static gboolean _cache_entry_clmem_has_host_pinned_locked(dt_pixel_cache_entry_t *entry, void *host_ptr, int devid)
static gboolean _for_each_remove(gpointer key, gpointer value, gpointer user_data)
void dt_dev_pixelpipe_cache_rdlock_entry(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
void dt_dev_pixelpipe_cache_flush_clmem_for_pipe(const int devid)
Like dt_dev_pixelpipe_cache_flush_clmem(), for callers that do not hold the device lock (dt_opencl_re...
void dt_dev_pixelpipe_cache_release_cl_buffer(void **cl_mem_buffer, dt_pixel_cache_entry_t *cache_entry, void *host_ptr, const gboolean cache_device)
Release or cache an OpenCL image associated with a host cache line.
static int _non_thread_safe_pixel_pipe_cache_remove_lru(dt_dev_pixelpipe_cache_t *cache, const gboolean host_only)
static gboolean _pressure_alert_expired(gpointer key __attribute__((unused)), gpointer value, gpointer user_data)
void dt_dev_pixelpipe_cache_flush(const int id)
Remove cache lines matching id. Entries locked in read/write or having reference count greater than 0...
static gboolean _entry_evictable(dt_pixel_cache_entry_t *cache_entry, gboolean *used)
void dt_dev_pixelpipe_cache_print(void)
static void _pressure_react_locked(dt_dev_pixelpipe_cache_t *cache)
void dt_dev_pixelpipe_cache_flush_entry_clmem(dt_pixel_cache_entry_t *entry)
Flush all reusable OpenCL payloads cached on one cache entry.
static dt_pixel_cache_entry_t * _cache_try_rekey_reuse_locked(dt_dev_pixelpipe_cache_t *cache, const uint64_t new_hash, const size_t size, const dt_pixel_cache_entry_t *reuse_hint)
size_t dt_pixelpipe_cache_get_largest_free_run(void)
static const dt_pixelpipe_cache_observer_t * _observer
static dt_pixel_cache_entry_t * _cache_lookup_existing(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, void **data)
void dt_dev_pixelpipe_cache_put_pinned_image(void *host_ptr, dt_pixel_cache_entry_t *entry_hint, void **mem)
Release or cache a pinned OpenCL image acquired with dt_dev_pixelpipe_cache_get_pinned_image().
gboolean dt_dev_pixelpipe_cache_restore_host_payload(dt_pixel_cache_entry_t *cache_entry, const int preferred_devid, void **data)
Materialize a host payload for a live cache entry from its cached device payload.
void * dt_dev_pixelpipe_cache_get_cl_buffer(int devid, void *const host_ptr, const dt_iop_roi_t *roi, const size_t bpp, dt_iop_module_t *module, const char *message, dt_pixel_cache_entry_t *cache_entry, gboolean *out_reused, void *keep)
static int _pixel_cache_clmem_put(dt_pixel_cache_entry_t *entry, void *host_ptr, void *mem)
gboolean dt_dev_pixelpipe_cache_flush_host_pinned_image(void *host_ptr, dt_pixel_cache_entry_t *entry_hint, int devid)
Drop cached pinned OpenCL images associated with a given host buffer.
int dt_dev_pixelpipe_cache_rekey(const uint64_t old_hash, const uint64_t new_hash, dt_pixel_cache_entry_t *entry)
Change the hash/key of an existing cache line in place, without freeing, reallocating or invalidating...
dt_pixel_cache_materialize_source_rank_t
@ DT_PIXEL_CACHE_MATERIALIZE_SOURCE_SECONDARY_PREFERRED
@ DT_PIXEL_CACHE_MATERIALIZE_SOURCE_PRIMARY_ANY
@ DT_PIXEL_CACHE_MATERIALIZE_SOURCE_SECONDARY_ANY
@ DT_PIXEL_CACHE_MATERIALIZE_SOURCE_NONE
@ DT_PIXEL_CACHE_MATERIALIZE_SOURCE_PRIMARY_PREFERRED
dt_pixel_cache_entry_t * dt_dev_pixelpipe_cache_get_entry_by_data(void *data)
static size_t _pixel_cache_get_size(dt_pixel_cache_entry_t *cache_entry)
static dt_pixelpipe_cache_pressure_sink_t _pressure_sink(dt_dev_pixelpipe_cache_t *cache)
void * dt_pixel_cache_alloc(dt_pixel_cache_entry_t *cache_entry)
Actually allocate the memory buffer attached to the cache entry once you create it with dt_dev_pixelp...
static dt_pixelpipe_cache_warn_handler_t _warn_handler
static gboolean _cache_entry_clmem_flush_host_pinned_locked(dt_pixel_cache_entry_t *entry, void *host_ptr, int devid)
static __thread const char * dt_pixelpipe_cache_current_image
static void _free_cache_entry(dt_pixel_cache_entry_t *cache_entry)
void * dt_dev_pixelpipe_cache_alloc_cl_device_buffer(int devid, const dt_iop_roi_t *roi, const size_t bpp, const dt_iop_module_t *module, const char *message, void *keep)
void * dt_pixel_cache_entry_get_buffer(dt_pixel_cache_entry_t *entry)
The host buffer of a cache entry, whatever hash its content describes.
static void _observe_read(uint64_t hash, size_t size)
static gboolean _system_memory_pressure_valve(dt_dev_pixelpipe_cache_t *cache, size_t request_size)
void dt_dev_pixelpipe_cache_get_usage(size_t *current, size_t *max)
int dt_dev_pixelpipe_cache_get(const uint64_t hash, const size_t size, const char *name, const int id, const gboolean alloc, void **data, dt_pixel_cache_entry_t **entry)
Get a cache line from the cache.
dt_pixel_cache_entry_t * dt_dev_pixelpipe_cache_get_entry(const uint64_t hash)
Get an internal reference to the cache entry matching hash. If you are going to access this entry mor...
static gboolean _observed(void)
static void _non_threadsafe_stats_append(GArray *out, GHashTable *table, const gboolean allocations, const int64_t now, const int num_devices)
int dt_dev_pixelpipe_cache_prepare_cl_input(dt_dev_pixelpipe_t *pipe, dt_iop_module_t *module, float *input, void **cl_mem_input, const dt_iop_roi_t *roi_in, const size_t in_bpp, dt_pixel_cache_entry_t *input_entry, dt_pixel_cache_entry_t **locked_input_entry, void *keep)
Prepare/obtain the OpenCL input image for a module.
static gboolean _for_each_remove_old(gpointer key, gpointer value, gpointer user_data)
static int _memory_pressure_shedder(dt_dev_pixelpipe_cache_t *cache)
#define DT_PIXELPIPE_CACHE_PRESSURE_EXEMPT_SIZE
static gboolean _is_gamma_rgba8_output(const dt_iop_module_t *module, const size_t bpp, const char *message)
gboolean dt_dev_pixelpipe_cache_init(size_t max_memory, const gboolean verbose, const gboolean verbose_detail)
Reserve the cache's arena and start it.
static void _pixelpipe_cache_finalize_entry(dt_pixel_cache_entry_t *cache_entry, void **data, const char *message)
int dt_dev_pixelpipe_cache_sync_cl_buffer(const int devid, void *host_ptr, void *cl_mem_buffer, const dt_iop_roi_t *roi, int cl_mode, size_t bpp, dt_iop_module_t *module, const char *message)
Synchronize between host memory and a pinned OpenCL image.
void dt_dev_pixelpipe_cache_return_cl_payload(dt_pixel_cache_entry_t *entry, void *mem)
Return a borrowed cached OpenCL payload to its cache entry.
static gboolean _verbose_detail
static size_t _cache_budget_locked(const dt_dev_pixelpipe_cache_t *cache)
static void _alert_cache_refused(const char *name, const char *module)
static size_t _pressure_shed(void *user, const size_t target, size_t *given_back)
void dt_dev_pixelpipe_cache_unref_hash(const uint64_t hash)
Find the entry matching hash, and decrease its ref_count if found.
static void _cache_sum_evictable(__attribute__((unused)) gpointer key, gpointer value, gpointer user_data)
size_t dt_pixel_cache_entry_get_size(const dt_pixel_cache_entry_t *entry)
void dt_pixelpipe_cache_free_align_cache(void **mem, const char *message)
Free aligned memory allocated with dt_pixelpipe_cache_alloc_align_cache.
int _non_thread_safe_cache_remove(dt_dev_pixelpipe_cache_t *cache, const gboolean force, dt_pixel_cache_entry_t *cache_entry, GHashTable *table)
static gboolean _cache_try_restore_device_payload(dt_pixel_cache_entry_t *cache_entry, const int preferred_devid, void **cl_mem_output)
static void _pixel_cache_message(dt_pixel_cache_entry_t *cache_entry, const char *message, gboolean verbose)
static void * _pixel_cache_clmem_get(dt_pixel_cache_entry_t *entry, void *host_ptr, int devid, int width, int height, int bpp, int flags)
static dt_pixel_cache_entry_t * _non_threadsafe_cache_get_entry(dt_dev_pixelpipe_cache_t *cache, GHashTable *table, const uint64_t key)
void dt_dev_pixelpipe_cache_flag_host_written(dt_pixel_cache_entry_t *entry)
Record that the host buffer of entry now holds the pixels of its current hash.
static dt_pixelpipe_cache_ready_handler_t _ready_handler
static gboolean _cache_entry_materialize_host_data(dt_dev_pixelpipe_cache_t *cache, int preferred_devid, dt_pixel_cache_entry_t *entry)
dt_pixel_cache_entry_t * dt_dev_pixelpipe_cache_ref_entry_for_host_ptr(void *host_ptr)
Resolve and retain the cache entry owning a host pointer.
#define DT_PIXELPIPE_CACHE_PRESSURE_ALERT_PERIOD_US
static dt_dev_pixelpipe_cache_t * _pixelpipe_cache
static gboolean _cache_entry_materialize_host_data_locked(dt_pixel_cache_entry_t *entry, int preferred_devid, gboolean prefer_device_payload)
gboolean dt_dev_pixelpipe_cache_ref_entry_by_hash(const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry)
Resolve and retain an existing cache entry by hash.
static void _pixel_cache_touch(dt_pixel_cache_entry_t *cache_entry)
void dt_dev_pixelpipe_cache_flag_auto_destroy(dt_pixel_cache_entry_t *cache_entry)
Flag a cache line as disposable (auto_destroy), for short-lived lines nothing will need again: the re...
static void _warn_user(const char *message)
void dt_dev_pixelpipe_cache_set_handlers(dt_pixelpipe_cache_warn_handler_t warn, dt_pixelpipe_cache_ready_handler_t ready, const dt_pixelpipe_cache_observer_t *observer)
Install the handlers. Call once, from the orchestrator, before any pipe runs.
static dt_pixel_cache_entry_t * dt_pixel_cache_new_entry(const uint64_t hash, const size_t size, const char *name, const int id, dt_dev_pixelpipe_cache_t *cache, gboolean alloc, GHashTable *table)
void _non_thread_safe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
static dt_pixelpipe_cache_alert_handler_t _alert_handler
dt_dev_pixelpipe_cache_writable_status_t dt_dev_pixelpipe_cache_get_writable(const uint64_t hash, const size_t size, const char *name, const int id, const gboolean alloc, const gboolean allow_rekey_reuse, const dt_pixel_cache_entry_t *reuse_hint, const dt_pixel_cache_entry_t *reuse_hint_prev, void **data, dt_pixel_cache_entry_t **entry)
float * dt_dev_pixelpipe_cache_restore_cl_buffer(dt_dev_pixelpipe_t *pipe, float *input, void *cl_mem_input, const dt_iop_roi_t *roi_in, dt_iop_module_t *module, const size_t in_bpp, dt_pixel_cache_entry_t *input_entry, const char *message)
Force device → host resynchronization of the pixelpipe input cache line.
gboolean dt_dev_pixelpipe_cache_ref_host_entry_by_hash(const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry)
Resolve and retain an existing cacheline that already holds HOST pixels.
const char * dt_pixelpipe_cache_set_current_module(const char *module)
Set the current module name for cache diagnostics (thread-local).
uint32_t dt_pixelpipe_cache_get_alloc_refusals(void)
Count the allocations the cache refused to the calling thread for lack of memory (thread-local).
gboolean dt_dev_pixelpipe_cache_is_ready(void)
Has the pixelpipe cache been initialised? Callers that run before dt_dev_pixelpipe_cache_init() succe...
Pixelpipe cache for storing intermediate results in the pixelpipe.
#define DT_PIXELPIPE_CACHE_HASH_INVALID
void(* dt_pixelpipe_cache_warn_handler_t)(const char *message)
Tell the user something that is fine to miss: the cache went over its budget, but the allocation went...
void(* dt_pixelpipe_cache_alert_handler_t)(const char *message, const char *item)
Tell the user something that must not go unseen: what it says stays true after a toast would have gon...
void(* dt_pixelpipe_cache_ready_handler_t)(uint64_t hash, uint64_t producer_node_key)
A cacheline finished and is readable.
dt_dev_pixelpipe_cache_writable_status_t
@ DT_DEV_PIXELPIPE_CACHE_WRITABLE_REKEYED
@ DT_DEV_PIXELPIPE_CACHE_WRITABLE_ERROR
@ DT_DEV_PIXELPIPE_CACHE_WRITABLE_CREATED
@ DT_DEV_PIXELPIPE_CACHE_WRITABLE_EXACT_HIT
void dt_pixelpipe_cache_pressure_monitor_init(dt_pixelpipe_cache_pressure_monitor_t *m, const size_t plan)
void dt_pixelpipe_cache_pressure_triggered(dt_pixelpipe_cache_pressure_monitor_t *m, const dt_pixelpipe_cache_pressure_sink_t *sink)
void dt_pixelpipe_cache_pressure_watch_start(dt_pixelpipe_cache_pressure_monitor_t *m, void(*wake)(void *user), void *user)
size_t dt_pixelpipe_cache_pressure_react(dt_pixelpipe_cache_pressure_monitor_t *m, const dt_pixelpipe_cache_pressure_sink_t *sink)
void dt_pixelpipe_cache_pressure_watch_stop(dt_pixelpipe_cache_pressure_monitor_t *m)
static size_t dt_pixelpipe_cache_pressure_reported(const dt_pixelpipe_cache_pressure_t *p, const size_t current)
static size_t dt_pixelpipe_cache_pressure_budget(const dt_pixelpipe_cache_pressure_t *p)
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
static const dt_aligned_pixel_simd_t value
const float uint32_t state[4]
unsigned __int64 uint64_t
dt_pixel_cache_entry_t * cache_entry
GHashTable * pressure_alerts
GHashTable * external_entries
dt_pixelpipe_cache_pressure_monitor_t psi
Region of interest passed through the pixelpipe.
dt_dev_pixelpipe_cache_t * cache
dt_pthread_mutex_t cl_mem_lock
uint64_t producer_node_key
dt_pixel_cache_stats_device_t * devices
The supervisor's view of the cache. All four may be NULL; active gates the other three so the cache p...
void(* cacheline_delete)(uint64_t hash, size_t size, int owner_pipe_id, const char *name)
void(* cacheline_read)(uint64_t hash, size_t size)
void(* rekey)(uint64_t old_hash, uint64_t new_hash)
dt_pixelpipe_cache_pressure_t budget
size_t(* held)(void *user)
typedef double((*spd)(unsigned long int wavelength, double TempK))