63 void *data,
void *cl_mem_output,
const int preferred_devid,
const gboolean verbose)
69 "[pixelpipe_cache] exact-hit %s req=%" PRIu64
" entry=%" PRIu64
"/%" PRIu64
70 " data=%p cl=%p refs=%i auto=%i dev=%i module=%s name=%s\n",
72 cache_entry ? cache_entry->
serial : 0, data, cl_mem_output,
75 (cache_entry && cache_entry->
name) ? cache_entry->
name :
"-");
106 const char *message);
112 const char *
name,
const int id);
114 const char *
name,
const int id,
119 gboolean prefer_device_payload);
156 if(!cache || !data)
return NULL;
164 g_hash_table_iter_init(&iter, cache->
entries);
165 while(g_hash_table_iter_next(&iter, &
key, &
value))
168 if(entry && entry->
data == data)
177 while(g_hash_table_iter_next(&iter, &
key, &
value))
180 if(entry && entry->
data == data)
194 return cache_entry->
size / (1024 * 1024);
203 "[pixelpipe] cache entry %" PRIu64
"/%" PRIu64
": %s (data=%p - %" G_GSIZE_FORMAT
" MiB - age %" PRId64
204 " - hits %i - refs %i - auto %i - ext %i - id %i - module %s) %s\n",
206 cache_entry->
name ? cache_entry->
name :
"-", cache_entry->
data,
215 cache_entry->
age = g_get_monotonic_time();
267 if(!used && (!locked || force))
270 g_hash_table_remove(table, &cache_entry->
hash);
297 gboolean prefer_device_payload)
311 for(GList *l = g_list_first(entry->
cl_mem_list); l; l = g_list_next(l))
320 if(mem_devid != preferred_devid)
continue;
322 const gboolean host_backed = (c->host_ptr == entry->
data);
323 const gboolean device_only = (
IS_NULL_PTR(c->host_ptr));
324 if(!host_backed && !device_only)
continue;
327 if(!prefer_device_payload)
329 if(host_backed && (preferred_devid < 0 || mem_devid == preferred_devid))
331 else if(device_only && preferred_devid >= 0 && mem_devid == preferred_devid)
340 if(device_only && preferred_devid >= 0 && mem_devid == preferred_devid)
344 else if(host_backed && (preferred_devid < 0 || mem_devid == preferred_devid))
384 gboolean prefer_device_payload)
386 (
void)preferred_devid;
387 (
void)prefer_device_payload;
399 gboolean use_host_ptr =
TRUE;
403 use_host_ptr =
FALSE;
416 gboolean found =
FALSE;
418 for(GList *l = g_list_first(entry->
cl_mem_list); l; l = g_list_next(l))
440 gboolean flushed =
FALSE;
443 for(GList *l = g_list_first(entry->
cl_mem_list); l;)
445 GList *next = g_list_next(l);
489 if(devid < 0)
return;
501 g_hash_table_iter_init(&iter, cache->
entries);
502 while(g_hash_table_iter_next(&iter, &
key, &
value))
522 "[dt_dev_pixelpipe_cache_flush_clmem] entry %" PRIu64
" is in use (refcount=%i locked=%i), "
529 "[dt_dev_pixelpipe_cache_flush_clmem] trying to flush vRAM for entry %" PRIu64
" on device %d...\n",
538 g_hash_table_iter_remove(&iter);
620 lru->
max_age = g_get_monotonic_time();
662 "[_pixel_cache_clmem_get] %u output entries in %" PRIu64
"\n",
665 for(GList *l = g_list_first(entry->
cl_mem_list); l;)
667 GList *next = g_list_next(l);
709 for(GList *l = g_list_first(entry->
cl_mem_list); l; l = g_list_next(l))
737 for(GList *l = entry->
cl_mem_list; l; l = g_list_next(l))
740 if(c && c->mem == mem)
742 if(c->refs > 0) c->refs--;
766 cl_mem clmem = (cl_mem)mem;
770 for(GList *l = g_list_first(entry->
cl_mem_list); l; l = g_list_next(l))
782 if(c->refs > 0)
continue;
786 c->host_ptr = host_ptr;
801 c->host_ptr = host_ptr;
815 GList *next = g_list_next(l);
817 if(c && c->mem == mem)
833 GList *next = g_list_next(l);
853 gboolean *out_reused)
856 if(devid < 0 ||
width <= 0 ||
height <= 0 ||
bpp <= 0)
return NULL;
862 if(!use_pinned)
flags &= ~CL_MEM_USE_HOST_PTR;
888 gboolean synced =
FALSE;
912 dt_print(
DT_DEBUG_OPENCL,
"[dt_dev_pixelpipe_cache_get_pinned_image] synchronized with write_host_to_device\n");
931 dt_print(
DT_DEBUG_OPENCL,
"[dt_dev_pixelpipe_cache_put_pinned_image] no cache entry to put the vRAM buffer\n");
939 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);
1000 return module && message && bpp == 4 * sizeof(uint8_t) && strcmp(module->op, "gamma") == 0
1001 && strcmp(message, "output") == 0;
1016 gboolean *out_reused,
void *keep)
1019 void *cl_mem_input = NULL;
1020 gboolean reused_from_cache =
FALSE;
1026 if(out_reused) *out_reused =
FALSE;
1030 const int flags = CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR;
1046 dt_print(
DT_DEBUG_OPENCL,
"[dev_pixelpipe] allocated a pinned GPU buffer for %s %s\n", module->name(), message);
1056 (
int)
bpp, CL_MEM_READ_WRITE);
1066 dt_print(
DT_DEBUG_OPENCL,
"[dev_pixelpipe] allocated a device-only GPU buffer for %s %s\n", module->name(), message);
1072 dt_print(
DT_DEBUG_OPENCL,
"[dev_pixelpipe] couldn't allocate GPU buffer for module %s %s\n", module->name(), message);
1074 else if(reused_from_cache)
1080 "[dev_pixelpipe] reused GPU buffer from cache (hits=%d, misses=%d) for module %s %s\n",
1081 hits, misses, module->name(), message);
1088 if(out_reused) *out_reused = reused_from_cache;
1089 return cl_mem_input;
1115 void *host_ptr,
const gboolean cache_device)
1119 cl_mem mem = *cl_mem_buffer;
1129 *cl_mem_buffer = NULL;
1168 const cl_mem mem = (cl_mem)cl_mem_buffer;
1177 "[dev_pixelpipe] successfully synced image %s via map/unmap for module %s (%s)\n",
1178 (cl_mode == CL_MAP_WRITE) ?
"host to device" :
"device to host",
1179 (module) ? module->
op :
"base buffer", message);
1185 cl_int err = CL_SUCCESS;
1186 if(cl_mode == CL_MAP_WRITE)
1188 else if(cl_mode == CL_MAP_READ)
1193 if(err != CL_SUCCESS)
1196 (cl_mode == CL_MAP_WRITE) ?
"host to device" :
"device to host",
1197 (module) ? module->
op :
"base buffer", message);
1202 (cl_mode == CL_MAP_WRITE) ?
"host to device" :
"device to host",
1203 (module) ? module->
op :
"base buffer", message);
1224 const char *message)
1230 CL_MAP_READ, in_bpp, module, message);
1232 return fail ? NULL : input;
1263 float *input,
void **cl_mem_input,
1269 *locked_input_entry = NULL;
1278 const cl_mem mem = (cl_mem)*cl_mem_input;
1282 *locked_input_entry = input_entry;
1296 gboolean input_reused_from_cache =
FALSE;
1298 "input", input_entry,
1299 &input_reused_from_cache, keep);
1305 gboolean keep_lock =
FALSE;
1307 if(!fail && *cl_mem_input)
1309 mem = (cl_mem)*cl_mem_input;
1317 if(!fail && mem && !keep_lock && !input_reused_from_cache)
1321 if(err != CL_SUCCESS)
1324 (module) ? module->
op :
"base buffer",
"cache to input");
1330 (module) ? module->
op :
"base buffer",
"cache to input");
1338 *locked_input_entry = input_entry;
1342 return fail ? 1 : 0;
1348 gboolean *out_reused,
void *keep)
1358 if(out_reused) *out_reused =
FALSE;
1364 const char *message,
void *keep)
1376 void *host_ptr, gboolean cache_device)
1381 if(cl_mem_buffer) *cl_mem_buffer = NULL;
1390 (
void)cl_mem_buffer;
1403 const char *message)
1416 float *input,
void **cl_mem_input,
1429 (
void)locked_input_entry;
1452 size_t *actual_size)
1457 uint32_t pages_needed = 0;
1461 uint32_t total_free_pages = 0, largest_free_run_pages = 0;
1464 while(largest_free_run_pages < pages_needed && g_hash_table_size(cache->
entries) > 0)
1476 uint32_t *largest_pages,
size_t *total_bytes,
size_t *largest_bytes)
1480 if(total_bytes) *total_bytes = (size_t)(*total_pages) * page_size;
1481 if(largest_bytes) *largest_bytes = (size_t)(*largest_pages) * page_size;
1485 const char *entry_name,
const char *module,
uint64_t hash,
1486 gboolean name_is_file)
1488 uint32_t total_free_pages = 0, largest_free_run_pages = 0;
1489 size_t total_free_bytes = 0, largest_free_bytes = 0;
1490 _arena_stats_bytes(cache, &total_free_pages, &largest_free_run_pages, &total_free_bytes, &largest_free_bytes);
1494 "[pixelpipe_cache] failed to allocate %" G_GSIZE_FORMAT
" bytes for entry %" PRIu64
" (%s, module=%s) "
1495 "[arena largest=%" G_GSIZE_FORMAT
" MiB, total=%" G_GSIZE_FORMAT
" MiB, cache=%" G_GSIZE_FORMAT
"/%" G_GSIZE_FORMAT
" MiB]\n",
1496 request_size, hash, entry_name, module ? module :
"unknown",
1497 largest_free_bytes / (1024 * 1024), total_free_bytes / (1024 * 1024),
1501 "[pixelpipe_cache] failed to allocate %" G_GSIZE_FORMAT
" bytes for entry %" PRIu64
" (module=%s) "
1502 "[arena largest=%" G_GSIZE_FORMAT
" MiB, total=%" G_GSIZE_FORMAT
" MiB, cache=%" G_GSIZE_FORMAT
"/%" G_GSIZE_FORMAT
" MiB]\n",
1503 request_size, hash, module ? module :
"unknown",
1504 largest_free_bytes / (1024 * 1024), total_free_bytes / (1024 * 1024),
1508 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."),
1509 entry_name, module);
1511 dt_control_log(_(
"The pipeline cache is full while allocating `%s`. Either your RAM settings are too frugal or your RAM is too small."),
1514 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."),
1517 dt_control_log(_(
"The pipeline cache is full. Either your RAM settings are too frugal or your RAM is too small."));
1535 for(GList *l = g_list_first(entry->
cl_mem_list); l;)
1537 GList *next = g_list_next(l);
1548 gboolean referenced = c->refs > 0;
1551 if(referenced || not_ours)
1557 "[dt_dev_pixelpipe_cache_flush_clmem] for entry %" PRIu64
": couldn't flush %p "
1558 "(referenced=%i not ours=%i)\n",
1559 entry->
hash, c->mem, referenced, not_ours);
1593 const char *
module = dt_pixelpipe_cache_current_module;
1599 return cache_entry->
data;
1604 return entry ? entry->
data : NULL;
1609 return entry ? entry->
size : 0;
1624 const char *
module = dt_pixelpipe_cache_current_module;
1625 const gboolean name_is_file = (!
IS_NULL_PTR(
name)) && (strchr(
name,
'/') != NULL) && (strchr(
name,
':') != NULL);
1629 fprintf(stdout,
"[pixelpipe] cache is full, cannot allocate new entry %" PRIu64
" (%s)\n", hash,
name);
1631 fprintf(stdout,
"[pixelpipe] cache is full, cannot allocate new entry (%s)\n",
name);
1633 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);
1635 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);
1637 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);
1639 dt_control_log(_(
"The pipeline cache is full. Either your RAM settings are too frugal or your RAM is too small."));
1654 if(
error)
return NULL;
1657 size_t page_size = 0;
1686 cache_entry->
data = aligned;
1687 cache_entry->
age = g_get_monotonic_time();
1703 fprintf(stdout,
"error while freeing cache entry: no entry found but we have a buffer, %s.\n", message);
1718 const char *
name,
const int id,
1722 uint32_t pages_needed = 0;
1723 size_t rounded_size = 0;
1726 fprintf(stderr,
"[pixelpipe] invalid cache entry size %" G_GSIZE_FORMAT
" for %s\n",
size,
name);
1731 if(
error)
return NULL;
1737 cache_entry->
size = rounded_size;
1738 cache_entry->
age = 0;
1739 cache_entry->
hits = 0;
1740 cache_entry->
hash = hash;
1742 cache_entry->
id = id;
1746 cache_entry->
data = NULL;
1747 cache_entry->
cache = cache;
1761 cache_entry->
name = g_strdup(
name);
1774 g_hash_table_insert(table,
key, cache_entry);
1788 if(cache_entry->
data)
1792 for(GList *l = cache_entry->
cl_mem_list; l; l = g_list_next(l))
1814 cache_entry->
data = NULL;
1848 g_hash_table_destroy(cache->
entries);
1862 g_hash_table_destroy(cache->
entries);
1877 const char *
name,
const int id)
1899 if(reuse_hint->
size <
size)
return NULL;
1903 if(cache_entry->
serial != reuse_hint->
serial)
return NULL;
1905 if(cache_entry->
size <
size)
return NULL;
1916 for(GList *l = cache_entry->
cl_mem_list; l; l = g_list_next(l))
1919 if(c && c->refs > 0)
1929 gpointer stolen_key = NULL;
1930 gpointer stolen_value = NULL;
1931 if(!g_hash_table_steal_extended(cache->
entries, &old_hash, &stolen_key, &stolen_value)
1932 || stolen_value != cache_entry)
1934 if(stolen_key && stolen_value) g_hash_table_insert(cache->
entries, stolen_key, stolen_value);
1940 *(
uint64_t *)stolen_key = new_hash;
1941 cache_entry->
hash = new_hash;
1942 g_hash_table_insert(cache->
entries, stolen_key, cache_entry);
1945 "[pixelpipe_cache] writable rekey old=%" PRIu64
" new=%" PRIu64
" entry=%" PRIu64
"/%" PRIu64
1946 " refs=%i auto=%i data=%p module=%s\n",
1947 old_hash, new_hash, cache_entry->
hash, cache_entry->
serial,
1955 const size_t size,
const char *
name,
const int id,
1956 const gboolean alloc,
void **data,
1963 if(data) *data = NULL;
1964 if(entry) *entry = NULL;
1983 cache_entry->
hits++;
1996 if(entry) *entry = cache_entry;
2005 if(entry) *entry = NULL;
2019 if(entry) *entry = cache_entry;
2025 const size_t size,
const char *
name,
const int id,
2026 const gboolean alloc,
const gboolean allow_rekey_reuse,
2033 if(data) *data = NULL;
2034 if(entry) *entry = NULL;
2052 if(data) *data = NULL;
2053 if(entry) *entry = NULL;
2057 if(allow_rekey_reuse)
2065 if(entry) *entry = cache_entry;
2074 if(data) *data = NULL;
2075 if(entry) *entry = NULL;
2083 if(entry) *entry = cache_entry;
2097 cache_entry->
hits++;
2107 const int preferred_devid,
void **cl_mem_output)
2115 GList *next = g_list_next(l);
2121 *cl_mem_output = c->mem;
2133 const int preferred_devid,
void **cl_mem_output)
2141 const int preferred_devid,
void **data)
2143 if(data) *data = NULL;
2161 void **cl_mem_output)
2163 if(data) *data = NULL;
2164 if(entry) *entry = NULL;
2165 if(cl_mem_output) *cl_mem_output = NULL;
2182 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2183 if(data) *data = NULL;
2190 if(entry) *entry = cache_entry;
2200 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2201 if(data) *data = NULL;
2211 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2212 if(entry) *entry = cache_entry;
2221 if(preferred_devid < 0)
2230 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2231 if(entry) *entry = cache_entry;
2238 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2239 if(entry) *entry = cache_entry;
2244 cl_mem_output ? *cl_mem_output : NULL, preferred_devid,
FALSE);
2246 "[pixelpipe] cache entry %" PRIu64
" has no authoritative RAM nor vRAM payload and will be removed\n",
2251 if(data) *data = NULL;
2259 const int id = GPOINTER_TO_INT(user_data);
2266 return (cache_entry->
id ==
id ||
id == -1) && !locked;
2287 for(
size_t k = 0;
k < count;
k++)
2318 int64_t
delta = g_get_monotonic_time() - cache_entry->
age;
2321 const int64_t three_min = 5 * 60 * 1000 * 1000;
2323 gboolean too_old = (
delta > three_min) && (cache_entry->
hits < 4);
2325 return too_old && !used && !locked;
2335 return G_SOURCE_CONTINUE;
2442 if(!used && !locked)
2445 g_hash_table_remove(cache->
entries, &cache_entry->
hash);
2481 if(old_hash == new_hash)
return 0;
2489 "[pixelpipe_cache] rekey miss old=%" PRIu64
" new=%" PRIu64
" module=%s\n",
2496 if(conflict && conflict != entry)
2499 "[pixelpipe_cache] rekey conflict old=%" PRIu64
" new=%" PRIu64
2500 " entry=%" PRIu64
"/%" PRIu64
" conflict=%" PRIu64
"/%" PRIu64
" module=%s\n",
2507 gpointer stolen_key = NULL;
2508 gpointer stolen_value = NULL;
2509 if(!g_hash_table_steal_extended(cache->
entries, &old_hash, &stolen_key, &stolen_value))
2512 "[pixelpipe_cache] rekey steal-miss old=%" PRIu64
" new=%" PRIu64
2513 " entry=%" PRIu64
"/%" PRIu64
" module=%s\n",
2519 if(stolen_value != entry)
2522 "[pixelpipe_cache] rekey stolen-entry mismatch old=%" PRIu64
" new=%" PRIu64
2523 " expected=%" PRIu64
"/%" PRIu64
" got=%" PRIu64
"/%" PRIu64
" module=%s\n",
2524 old_hash, new_hash, entry->
hash, entry->
serial,
2527 g_hash_table_insert(cache->
entries, stolen_key, stolen_value);
2536 for(GList *l = entry->
cl_mem_list; l; l = g_list_next(l))
2539 if(c && c->refs > 0)
2542 g_hash_table_insert(cache->
entries, stolen_key, stolen_value);
2550 *(
uint64_t *)stolen_key = new_hash;
2551 entry->
hash = new_hash;
2552 g_hash_table_insert(cache->
entries, stolen_key, stolen_value);
2554 "[pixelpipe_cache] rekey old=%" PRIu64
" new=%" PRIu64
" entry=%" PRIu64
"/%" PRIu64
2555 " refs=%i auto=%i data=%p module=%s\n",
2568 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",
2571 g_hash_table_size(cache->
entries));
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)
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
#define dt_pthread_rwlock_tryrdlock
#define dt_pthread_rwlock_destroy
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)
#define dt_pthread_rwlock_wrlock
#define dt_pthread_rwlock_trywrlock
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)
#define dt_pthread_rwlock_init
#define dt_pthread_rwlock_unlock
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
#define dt_pthread_rwlock_rdlock
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)
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)
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)
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.
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)
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