64 void *data,
void *cl_mem_output,
const int preferred_devid,
const gboolean verbose)
70 "[pixelpipe_cache] exact-hit %s req=%" PRIu64
" entry=%" PRIu64
"/%" PRIu64
71 " data=%p cl=%p refs=%i auto=%i dev=%i module=%s name=%s\n",
73 cache_entry ? cache_entry->
serial : 0, data, cl_mem_output,
76 (cache_entry && cache_entry->
name) ? cache_entry->
name :
"-");
107 const char *message);
113 const char *
name,
const int id);
115 const char *
name,
const int id,
120 gboolean prefer_device_payload);
157 if(!cache || !data)
return NULL;
165 g_hash_table_iter_init(&iter, cache->
entries);
166 while(g_hash_table_iter_next(&iter, &
key, &
value))
169 if(entry && entry->
data == data)
178 while(g_hash_table_iter_next(&iter, &
key, &
value))
181 if(entry && entry->
data == data)
195 return cache_entry->
size / (1024 * 1024);
204 "[pixelpipe] cache entry %" PRIu64
"/%" PRIu64
": %s (data=%p - %" G_GSIZE_FORMAT
" MiB - age %" PRId64
205 " - hits %i - refs %i - auto %i - ext %i - id %i - module %s) %s\n",
207 cache_entry->
name ? cache_entry->
name :
"-", cache_entry->
data,
216 cache_entry->
age = g_get_monotonic_time();
245 const size_t found_size = found ? cache_entry->
size : 0;
273 if(!used && (!locked || force))
276 g_hash_table_remove(table, &cache_entry->
hash);
303 gboolean prefer_device_payload)
317 for(GList *l = g_list_first(entry->
cl_mem_list); l; l = g_list_next(l))
326 if(mem_devid != preferred_devid)
continue;
328 const gboolean host_backed = (c->host_ptr == entry->
data);
329 const gboolean device_only = (
IS_NULL_PTR(c->host_ptr));
330 if(!host_backed && !device_only)
continue;
333 if(!prefer_device_payload)
335 if(host_backed && (preferred_devid < 0 || mem_devid == preferred_devid))
337 else if(device_only && preferred_devid >= 0 && mem_devid == preferred_devid)
346 if(device_only && preferred_devid >= 0 && mem_devid == preferred_devid)
350 else if(host_backed && (preferred_devid < 0 || mem_devid == preferred_devid))
390 gboolean prefer_device_payload)
392 (
void)preferred_devid;
393 (
void)prefer_device_payload;
405 gboolean use_host_ptr =
TRUE;
409 use_host_ptr =
FALSE;
422 gboolean found =
FALSE;
424 for(GList *l = g_list_first(entry->
cl_mem_list); l; l = g_list_next(l))
446 gboolean flushed =
FALSE;
449 for(GList *l = g_list_first(entry->
cl_mem_list); l;)
451 GList *next = g_list_next(l);
495 if(devid < 0)
return;
507 g_hash_table_iter_init(&iter, cache->
entries);
508 while(g_hash_table_iter_next(&iter, &
key, &
value))
528 "[dt_dev_pixelpipe_cache_flush_clmem] entry %" PRIu64
" is in use (refcount=%i locked=%i), "
535 "[dt_dev_pixelpipe_cache_flush_clmem] trying to flush vRAM for entry %" PRIu64
" on device %d...\n",
544 g_hash_table_iter_remove(&iter);
626 lru->
max_age = g_get_monotonic_time();
668 "[_pixel_cache_clmem_get] %u output entries in %" PRIu64
"\n",
671 for(GList *l = g_list_first(entry->
cl_mem_list); l;)
673 GList *next = g_list_next(l);
715 for(GList *l = g_list_first(entry->
cl_mem_list); l; l = g_list_next(l))
743 for(GList *l = entry->
cl_mem_list; l; l = g_list_next(l))
746 if(c && c->mem == mem)
748 if(c->refs > 0) c->refs--;
772 cl_mem clmem = (cl_mem)mem;
776 for(GList *l = g_list_first(entry->
cl_mem_list); l; l = g_list_next(l))
788 if(c->refs > 0)
continue;
792 c->host_ptr = host_ptr;
807 c->host_ptr = host_ptr;
821 GList *next = g_list_next(l);
823 if(c && c->mem == mem)
839 GList *next = g_list_next(l);
859 gboolean *out_reused)
862 if(devid < 0 ||
width <= 0 ||
height <= 0 ||
bpp <= 0)
return NULL;
868 if(!use_pinned)
flags &= ~CL_MEM_USE_HOST_PTR;
894 gboolean synced =
FALSE;
918 dt_print(
DT_DEBUG_OPENCL,
"[dt_dev_pixelpipe_cache_get_pinned_image] synchronized with write_host_to_device\n");
937 dt_print(
DT_DEBUG_OPENCL,
"[dt_dev_pixelpipe_cache_put_pinned_image] no cache entry to put the vRAM buffer\n");
945 dt_print(
DT_DEBUG_OPENCL,
"[dt_dev_pixelpipe_cache_put_pinned_image] cache entry put the vRAM buffer (state=%i) in %p\n",
state, entry);
1004 const char *message)
1006 return module && message && bpp == 4 * sizeof(uint8_t) && strcmp(module->op, "gamma") == 0
1007 && strcmp(message, "output") == 0;
1022 gboolean *out_reused,
void *keep)
1025 void *cl_mem_input = NULL;
1026 gboolean reused_from_cache =
FALSE;
1032 if(out_reused) *out_reused =
FALSE;
1036 const int flags = CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR;
1052 dt_print(
DT_DEBUG_OPENCL,
"[dev_pixelpipe] allocated a pinned GPU buffer for %s %s\n", module->name(), message);
1062 (
int)
bpp, CL_MEM_READ_WRITE);
1072 dt_print(
DT_DEBUG_OPENCL,
"[dev_pixelpipe] allocated a device-only GPU buffer for %s %s\n", module->name(), message);
1078 dt_print(
DT_DEBUG_OPENCL,
"[dev_pixelpipe] couldn't allocate GPU buffer for module %s %s\n", module->name(), message);
1080 else if(reused_from_cache)
1086 "[dev_pixelpipe] reused GPU buffer from cache (hits=%d, misses=%d) for module %s %s\n",
1087 hits, misses, module->name(), message);
1094 if(out_reused) *out_reused = reused_from_cache;
1095 return cl_mem_input;
1121 void *host_ptr,
const gboolean cache_device)
1125 cl_mem mem = *cl_mem_buffer;
1135 *cl_mem_buffer = NULL;
1174 const cl_mem mem = (cl_mem)cl_mem_buffer;
1183 "[dev_pixelpipe] successfully synced image %s via map/unmap for module %s (%s)\n",
1184 (cl_mode == CL_MAP_WRITE) ?
"host to device" :
"device to host",
1185 (module) ? module->
op :
"base buffer", message);
1191 cl_int err = CL_SUCCESS;
1192 if(cl_mode == CL_MAP_WRITE)
1194 else if(cl_mode == CL_MAP_READ)
1199 if(err != CL_SUCCESS)
1202 (cl_mode == CL_MAP_WRITE) ?
"host to device" :
"device to host",
1203 (module) ? module->
op :
"base buffer", message);
1208 (cl_mode == CL_MAP_WRITE) ?
"host to device" :
"device to host",
1209 (module) ? module->
op :
"base buffer", message);
1230 const char *message)
1236 CL_MAP_READ, in_bpp, module, message);
1238 return fail ? NULL : input;
1269 float *input,
void **cl_mem_input,
1275 *locked_input_entry = NULL;
1284 const cl_mem mem = (cl_mem)*cl_mem_input;
1288 *locked_input_entry = input_entry;
1302 gboolean input_reused_from_cache =
FALSE;
1304 "input", input_entry,
1305 &input_reused_from_cache, keep);
1311 gboolean keep_lock =
FALSE;
1313 if(!fail && *cl_mem_input)
1315 mem = (cl_mem)*cl_mem_input;
1323 if(!fail && mem && !keep_lock && !input_reused_from_cache)
1327 if(err != CL_SUCCESS)
1330 (module) ? module->
op :
"base buffer",
"cache to input");
1336 (module) ? module->
op :
"base buffer",
"cache to input");
1344 *locked_input_entry = input_entry;
1348 return fail ? 1 : 0;
1354 gboolean *out_reused,
void *keep)
1364 if(out_reused) *out_reused =
FALSE;
1370 const char *message,
void *keep)
1382 void *host_ptr, gboolean cache_device)
1387 if(cl_mem_buffer) *cl_mem_buffer = NULL;
1396 (
void)cl_mem_buffer;
1409 const char *message)
1422 float *input,
void **cl_mem_input,
1435 (
void)locked_input_entry;
1458 size_t *actual_size)
1463 uint32_t pages_needed = 0;
1467 uint32_t total_free_pages = 0, largest_free_run_pages = 0;
1470 while(largest_free_run_pages < pages_needed && g_hash_table_size(cache->
entries) > 0)
1482 uint32_t *largest_pages,
size_t *total_bytes,
size_t *largest_bytes)
1486 if(total_bytes) *total_bytes = (size_t)(*total_pages) * page_size;
1487 if(largest_bytes) *largest_bytes = (size_t)(*largest_pages) * page_size;
1491 const char *entry_name,
const char *module,
uint64_t hash,
1492 gboolean name_is_file)
1494 uint32_t total_free_pages = 0, largest_free_run_pages = 0;
1495 size_t total_free_bytes = 0, largest_free_bytes = 0;
1496 _arena_stats_bytes(cache, &total_free_pages, &largest_free_run_pages, &total_free_bytes, &largest_free_bytes);
1500 "[pixelpipe_cache] failed to allocate %" G_GSIZE_FORMAT
" bytes for entry %" PRIu64
" (%s, module=%s) "
1501 "[arena largest=%" G_GSIZE_FORMAT
" MiB, total=%" G_GSIZE_FORMAT
" MiB, cache=%" G_GSIZE_FORMAT
"/%" G_GSIZE_FORMAT
" MiB]\n",
1502 request_size, hash, entry_name, module ? module :
"unknown",
1503 largest_free_bytes / (1024 * 1024), total_free_bytes / (1024 * 1024),
1507 "[pixelpipe_cache] failed to allocate %" G_GSIZE_FORMAT
" bytes for entry %" PRIu64
" (module=%s) "
1508 "[arena largest=%" G_GSIZE_FORMAT
" MiB, total=%" G_GSIZE_FORMAT
" MiB, cache=%" G_GSIZE_FORMAT
"/%" G_GSIZE_FORMAT
" MiB]\n",
1509 request_size, hash, module ? module :
"unknown",
1510 largest_free_bytes / (1024 * 1024), total_free_bytes / (1024 * 1024),
1514 dt_control_log(_(
"The pipeline cache is full while allocating `%s` (module `%s`). Either your RAM settings are too frugal or your RAM is too small."),
1515 entry_name, module);
1517 dt_control_log(_(
"The pipeline cache is full while allocating `%s`. Either your RAM settings are too frugal or your RAM is too small."),
1520 dt_control_log(_(
"The pipeline cache is full while processing module `%s`. Either your RAM settings are too frugal or your RAM is too small."),
1523 dt_control_log(_(
"The pipeline cache is full. Either your RAM settings are too frugal or your RAM is too small."));
1541 for(GList *l = g_list_first(entry->
cl_mem_list); l;)
1543 GList *next = g_list_next(l);
1554 gboolean referenced = c->refs > 0;
1557 if(referenced || not_ours)
1563 "[dt_dev_pixelpipe_cache_flush_clmem] for entry %" PRIu64
": couldn't flush %p "
1564 "(referenced=%i not ours=%i)\n",
1565 entry->
hash, c->mem, referenced, not_ours);
1599 const char *
module = dt_pixelpipe_cache_current_module;
1605 return cache_entry->
data;
1610 return entry ? entry->
data : NULL;
1615 return entry ? entry->
size : 0;
1630 const char *
module = dt_pixelpipe_cache_current_module;
1631 const gboolean name_is_file = (!
IS_NULL_PTR(
name)) && (strchr(
name,
'/') != NULL) && (strchr(
name,
':') != NULL);
1635 fprintf(stdout,
"[pixelpipe] cache is full, cannot allocate new entry %" PRIu64
" (%s)\n", hash,
name);
1637 fprintf(stdout,
"[pixelpipe] cache is full, cannot allocate new entry (%s)\n",
name);
1639 dt_control_log(_(
"The pipeline cache is full while allocating `%s` (module `%s`). Either your RAM settings are too frugal or your RAM is too small."),
name, module);
1641 dt_control_log(_(
"The pipeline cache is full while allocating `%s`. Either your RAM settings are too frugal or your RAM is too small."),
name);
1643 dt_control_log(_(
"The pipeline cache is full while processing module `%s`. Either your RAM settings are too frugal or your RAM is too small."), module);
1645 dt_control_log(_(
"The pipeline cache is full. Either your RAM settings are too frugal or your RAM is too small."));
1660 if(
error)
return NULL;
1663 size_t page_size = 0;
1692 cache_entry->
data = aligned;
1693 cache_entry->
age = g_get_monotonic_time();
1709 fprintf(stdout,
"error while freeing cache entry: no entry found but we have a buffer, %s.\n", message);
1724 const char *
name,
const int id,
1728 uint32_t pages_needed = 0;
1729 size_t rounded_size = 0;
1732 fprintf(stderr,
"[pixelpipe] invalid cache entry size %" G_GSIZE_FORMAT
" for %s\n",
size,
name);
1737 if(
error)
return NULL;
1743 cache_entry->
size = rounded_size;
1744 cache_entry->
age = 0;
1745 cache_entry->
hits = 0;
1746 cache_entry->
hash = hash;
1748 cache_entry->
id = id;
1753 cache_entry->
data = NULL;
1754 cache_entry->
cache = cache;
1768 cache_entry->
name = g_strdup(
name);
1781 g_hash_table_insert(table,
key, cache_entry);
1810 fprintf(stderr,
"[pixelpipe] cache entry %p has a corrupted back-reference (%p, expected %p); "
1811 "skipping arena free to avoid a crash\n",
1816 if(cache_entry->
data && cache)
1820 for(GList *l = cache_entry->
cl_mem_list; l; l = g_list_next(l))
1858 cache_entry->
data = NULL;
1892 g_hash_table_destroy(cache->
entries);
1906 g_hash_table_destroy(cache->
entries);
1921 const char *
name,
const int id)
1943 if(reuse_hint->
size <
size)
return NULL;
1947 if(cache_entry->
serial != reuse_hint->
serial)
return NULL;
1949 if(cache_entry->
size <
size)
return NULL;
1960 for(GList *l = cache_entry->
cl_mem_list; l; l = g_list_next(l))
1963 if(c && c->refs > 0)
1973 gpointer stolen_key = NULL;
1974 gpointer stolen_value = NULL;
1975 if(!g_hash_table_steal_extended(cache->
entries, &old_hash, &stolen_key, &stolen_value)
1976 || stolen_value != cache_entry)
1978 if(stolen_key && stolen_value) g_hash_table_insert(cache->
entries, stolen_key, stolen_value);
1984 *(
uint64_t *)stolen_key = new_hash;
1985 cache_entry->
hash = new_hash;
1986 g_hash_table_insert(cache->
entries, stolen_key, cache_entry);
1991 "[pixelpipe_cache] writable rekey old=%" PRIu64
" new=%" PRIu64
" entry=%" PRIu64
"/%" PRIu64
1992 " refs=%i auto=%i data=%p module=%s\n",
1993 old_hash, new_hash, cache_entry->
hash, cache_entry->
serial,
2001 const size_t size,
const char *
name,
const int id,
2002 const gboolean alloc,
void **data,
2009 if(data) *data = NULL;
2010 if(entry) *entry = NULL;
2029 cache_entry->
hits++;
2042 if(entry) *entry = cache_entry;
2055 if(entry) *entry = NULL;
2069 if(entry) *entry = cache_entry;
2075 const size_t size,
const char *
name,
const int id,
2076 const gboolean alloc,
const gboolean allow_rekey_reuse,
2083 if(data) *data = NULL;
2084 if(entry) *entry = NULL;
2102 if(data) *data = NULL;
2103 if(entry) *entry = NULL;
2107 if(allow_rekey_reuse)
2115 if(entry) *entry = cache_entry;
2124 if(data) *data = NULL;
2125 if(entry) *entry = NULL;
2133 if(entry) *entry = cache_entry;
2145 const size_t hit_size = hit ? cache_entry->
size : 0;
2149 cache_entry->
hits++;
2163 const int preferred_devid,
void **cl_mem_output)
2171 GList *next = g_list_next(l);
2177 *cl_mem_output = c->mem;
2189 const int preferred_devid,
void **cl_mem_output)
2197 const int preferred_devid,
void **data)
2199 if(data) *data = NULL;
2217 void **cl_mem_output)
2219 if(data) *data = NULL;
2220 if(entry) *entry = NULL;
2221 if(cl_mem_output) *cl_mem_output = NULL;
2238 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2239 if(data) *data = NULL;
2246 if(entry) *entry = cache_entry;
2256 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2257 if(data) *data = NULL;
2267 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2268 if(entry) *entry = cache_entry;
2277 if(preferred_devid < 0)
2286 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2287 if(entry) *entry = cache_entry;
2294 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2295 if(entry) *entry = cache_entry;
2300 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2302 "[pixelpipe] cache entry %" PRIu64
" has no authoritative RAM nor vRAM payload and will be removed\n",
2307 if(data) *data = NULL;
2315 const int id = GPOINTER_TO_INT(user_data);
2322 return (cache_entry->
id ==
id ||
id == -1) && !locked;
2343 for(
size_t k = 0;
k < count;
k++)
2374 int64_t
delta = g_get_monotonic_time() - cache_entry->
age;
2377 const int64_t three_min = 5 * 60 * 1000 * 1000;
2379 gboolean too_old = (
delta > three_min) && (cache_entry->
hits < 4);
2381 return too_old && !used && !locked;
2391 return G_SOURCE_CONTINUE;
2504 if(!used && !locked)
2507 g_hash_table_remove(cache->
entries, &cache_entry->
hash);
2543 if(old_hash == new_hash)
return 0;
2551 "[pixelpipe_cache] rekey miss old=%" PRIu64
" new=%" PRIu64
" module=%s\n",
2558 if(conflict && conflict != entry)
2561 "[pixelpipe_cache] rekey conflict old=%" PRIu64
" new=%" PRIu64
2562 " entry=%" PRIu64
"/%" PRIu64
" conflict=%" PRIu64
"/%" PRIu64
" module=%s\n",
2569 gpointer stolen_key = NULL;
2570 gpointer stolen_value = NULL;
2571 if(!g_hash_table_steal_extended(cache->
entries, &old_hash, &stolen_key, &stolen_value))
2574 "[pixelpipe_cache] rekey steal-miss old=%" PRIu64
" new=%" PRIu64
2575 " entry=%" PRIu64
"/%" PRIu64
" module=%s\n",
2581 if(stolen_value != entry)
2584 "[pixelpipe_cache] rekey stolen-entry mismatch old=%" PRIu64
" new=%" PRIu64
2585 " expected=%" PRIu64
"/%" PRIu64
" got=%" PRIu64
"/%" PRIu64
" module=%s\n",
2586 old_hash, new_hash, entry->
hash, entry->
serial,
2589 g_hash_table_insert(cache->
entries, stolen_key, stolen_value);
2598 for(GList *l = entry->
cl_mem_list; l; l = g_list_next(l))
2601 if(c && c->refs > 0)
2604 g_hash_table_insert(cache->
entries, stolen_key, stolen_value);
2612 *(
uint64_t *)stolen_key = new_hash;
2613 entry->
hash = new_hash;
2614 g_hash_table_insert(cache->
entries, stolen_key, stolen_value);
2616 "[pixelpipe_cache] rekey old=%" PRIu64
" new=%" PRIu64
" entry=%" PRIu64
"/%" PRIu64
2617 " refs=%i auto=%i data=%p module=%s\n",
2632 dt_print(
DT_DEBUG_PIPECACHE,
"[pixelpipe] cache hit rate so far: %.3f%% - size: %" G_GSIZE_FORMAT
" MiB over %" G_GSIZE_FORMAT
" MiB - %i items\n",
2635 g_hash_table_size(cache->
entries));
2640 if(current) *current = 0;
2657 g_hash_table_iter_init(&it, cache->
entries);
2658 while(g_hash_table_iter_next(&it, &
key, &
value))
2674 for(GList *l = e->
cl_mem_list; l; l = g_list_next(l))
2685 g_array_append_val(
out, s);
static void error(char *msg)
int dt_atomic_get_int(dt_atomic_int *var)
int dt_atomic_sub_int(dt_atomic_int *var, int decr)
int dt_atomic_add_int(dt_atomic_int *var, int incr)
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_control_log(const char *msg,...)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
static void dt_free_gpointer(gpointer ptr)
static const dt_aligned_pixel_simd_t value
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define DT_CACHELINE_BYTES
static int dt_pthread_rwlock_unlock(dt_pthread_rwlock_t *rwlock)
static int dt_pthread_rwlock_tryrdlock(dt_pthread_rwlock_t *rwlock)
static int dt_pthread_mutex_BAD_trylock(dt_pthread_mutex_t *mutex)
static int dt_pthread_mutex_BAD_unlock(dt_pthread_mutex_t *mutex)
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_rwlock_trywrlock(dt_pthread_rwlock_t *rwlock)
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
static int dt_pthread_rwlock_destroy(dt_pthread_rwlock_t *lock)
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 int dt_pthread_rwlock_rdlock(dt_pthread_rwlock_t *rwlock)
static int dt_pthread_rwlock_wrlock(dt_pthread_rwlock_t *rwlock)
float *const restrict const size_t k
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)
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_get_mem_context_id(cl_mem mem)
int dt_opencl_get_image_height(cl_mem mem)
int dt_opencl_unmap_mem_object(const int devid, cl_mem mem_object, void *mapped_ptr)
int dt_opencl_is_enabled(void)
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_mem_object(cl_mem mem)
int dt_opencl_get_image_element_size(cl_mem mem)
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
static const char * _cache_debug_module_name(void)
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 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)
size_t dt_dev_pixelpipe_cache_get_vram_total(void)
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_pixelpipe_cache_free_align_cache(dt_dev_pixelpipe_cache_t *cache, void **mem, const char *message)
Free aligned memory allocated with dt_pixelpipe_cache_alloc_align_cache.
void dt_dev_pixelpipe_cache_cleanup(dt_dev_pixelpipe_cache_t *cache)
int dt_dev_pixelpipe_cache_invalidate_hashes(dt_dev_pixelpipe_cache_t *cache, const uint64_t *hashes, const size_t count)
Invalidate cache lines matching an explicit list of hashes.
GArray * dt_dev_pixelpipe_cache_get_entries_stats(dt_dev_pixelpipe_cache_t *cache)
static int garbage_collection
void * dt_pixel_cache_entry_get_data(dt_pixel_cache_entry_t *entry)
void * dt_dev_pixelpipe_cache_get_pinned_image(dt_dev_pixelpipe_cache_t *cache, 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 int dt_dev_pixelpipe_cache_flush_old(dt_dev_pixelpipe_cache_t *cache)
dt_dev_pixelpipe_cache_t * dt_dev_pixelpipe_cache_init(size_t max_memory)
static void _pixel_cache_clmem_remove(dt_pixel_cache_entry_t *entry, void *mem)
void dt_dev_pixelpipe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Increase/Decrease the reference count on the cache line as to prevent LRU item removal....
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_print(dt_dev_pixelpipe_cache_t *cache)
void * dt_pixel_cache_alloc(dt_dev_pixelpipe_cache_t *cache, 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...
void dt_dev_pixelpipe_cache_flush(dt_dev_pixelpipe_cache_t *cache, const int id)
Remove cache lines matching id. Entries locked in read/write or having reference count greater than 0...
static void _cache_get_oldest(gpointer key, gpointer value, gpointer user_data)
void dt_dev_pixelpipe_cache_unref_hash(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash)
Find the entry matching hash, and decrease its ref_count if found.
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)
void dt_dev_pixelpipe_cache_flush_clmem_for_pipe(dt_dev_pixelpipe_cache_t *cache, const int devid)
Like dt_dev_pixelpipe_cache_flush_clmem(), for callers that do not hold darktable....
static int _non_thread_safe_pixel_pipe_cache_remove_lru(dt_dev_pixelpipe_cache_t *cache)
void dt_dev_pixelpipe_cache_flag_auto_destroy(dt_dev_pixelpipe_cache_t *cache, dt_pixel_cache_entry_t *cache_entry)
Flag the cache entry as "auto_destroy". This is useful for short-lived/disposable cache entries,...
void dt_dev_pixelpipe_cache_auto_destroy_apply(dt_dev_pixelpipe_cache_t *cache, dt_pixel_cache_entry_t *cache_entry)
Free the entry if it has the flag "auto_destroy". See dt_dev_pixelpipe_cache_flag_auto_destroy()....
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_put_pinned_image(dt_dev_pixelpipe_cache_t *cache, 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().
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.
gboolean dt_dev_pixelpipe_cache_peek(dt_dev_pixelpipe_cache_t *cache, 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.
int dt_dev_pixel_pipe_cache_remove_lru(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)
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_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)
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
static size_t _pixel_cache_get_size(dt_pixel_cache_entry_t *cache_entry)
static gboolean _cache_entry_clmem_flush_host_pinned_locked(dt_pixel_cache_entry_t *entry, void *host_ptr, int devid)
void dt_dev_pixelpipe_cache_get_usage(dt_dev_pixelpipe_cache_t *cache, size_t *current, size_t *max)
static void _free_cache_entry(dt_pixel_cache_entry_t *cache_entry)
dt_pixel_cache_entry_t * dt_dev_pixelpipe_cache_get_entry(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash)
Get an internal reference to the cache entry matching hash. If you are going to access this entry mor...
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)
int dt_dev_pixelpipe_cache_get(dt_dev_pixelpipe_cache_t *cache, 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.
int dt_dev_pixelpipe_cache_remove(dt_dev_pixelpipe_cache_t *cache, const gboolean force, dt_pixel_cache_entry_t *cache_entry)
Arbitrarily remove the cache entry matching hash. Entries having a reference count > 0 (inter-thread ...
gboolean dt_dev_pixelpipe_cache_ref_entry_by_hash(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry)
Resolve and retain an existing cache entry by hash.
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)
dt_pixel_cache_entry_t * dt_dev_pixelpipe_cache_get_entry_by_data(dt_dev_pixelpipe_cache_t *cache, void *data)
static gboolean _is_gamma_rgba8_output(const dt_iop_module_t *module, const size_t bpp, const char *message)
dt_dev_pixelpipe_cache_writable_status_t dt_dev_pixelpipe_cache_get_writable(dt_dev_pixelpipe_cache_t *cache, 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, void **data, dt_pixel_cache_entry_t **entry)
gboolean dt_dev_pixelpipe_cache_restore_host_payload(dt_dev_pixelpipe_cache_t *cache, 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_wrlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the write lock on the entry.
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.
gboolean dt_dev_pixelpipe_cache_flush_host_pinned_image(dt_dev_pixelpipe_cache_t *cache, void *host_ptr, dt_pixel_cache_entry_t *entry_hint, int devid)
Drop cached pinned OpenCL images associated with a given host buffer.
size_t dt_pixel_cache_entry_get_size(dt_pixel_cache_entry_t *entry)
Peek the size (in bytes) reserved for the host buffer of a cache entry.
int dt_dev_pixelpipe_cache_rekey(dt_dev_pixelpipe_cache_t *cache, 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...
void dt_dev_pixelpipe_cache_rdlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
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)
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 * _arena_alloc_with_defrag(dt_dev_pixelpipe_cache_t *cache, size_t request_size, size_t *actual_size)
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_pixelpipe_cache_alloc_align_cache_impl(dt_dev_pixelpipe_cache_t *cache, 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...
static gboolean _cache_entry_materialize_host_data(dt_dev_pixelpipe_cache_t *cache, int preferred_devid, dt_pixel_cache_entry_t *entry)
static gboolean _cache_entry_materialize_host_data_locked(dt_pixel_cache_entry_t *entry, int preferred_devid, gboolean prefer_device_payload)
dt_pixel_cache_entry_t * dt_dev_pixelpipe_cache_ref_entry_for_host_ptr(dt_dev_pixelpipe_cache_t *cache, void *host_ptr)
Resolve and retain the cache entry owning a host pointer.
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)
void dt_dev_pixelpipe_cache_flush_clmem(dt_dev_pixelpipe_cache_t *cache, const int devid)
Release cached OpenCL buffers for a single device.
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.
const char * dt_pixelpipe_cache_set_current_module(const char *module)
Set the current module name for cache diagnostics (thread-local).
Pixelpipe cache for storing intermediate results in the pixelpipe.
#define DT_PIXELPIPE_CACHE_HASH_INVALID
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
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
@ DT_SIGNAL_CACHELINE_READY
This signal is raised when one cacheline write lock is released. 1 : uint64_t cacheline hash no retur...
const float uint32_t state[4]
unsigned __int64 uint64_t
dt_pixel_cache_entry_t * cache_entry
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
struct dt_control_signal_t * signals
struct dt_opencl_t * opencl
GHashTable * external_entries
GModule *dt_dev_operation_t op
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
void dt_supervisor_cacheline_delete(const uint64_t hash, const size_t size, const int owner_pipe_id, const char *name)
void dt_supervisor_rekey(const uint64_t old_hash, const uint64_t new_hash)
void dt_supervisor_cacheline_read(const uint64_t hash, const size_t size)
static gboolean dt_supervisor_active(void)