Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
opencl.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010-2012, 2016 johannes hanika.
4 Copyright (C) 2011 Bruce Guenter.
5 Copyright (C) 2011 Henrik Andersson.
6 Copyright (C) 2011 Moritz Lipp.
7 Copyright (C) 2011-2019 Ulrich Pegelow.
8 Copyright (C) 2012 Christian Tellefsen.
9 Copyright (C) 2012 Jérémy Rosen.
10 Copyright (C) 2012 Michal Babej.
11 Copyright (C) 2012 Richard Wonka.
12 Copyright (C) 2012-2014, 2016-2018 Tobias Ellinghaus.
13 Copyright (C) 2013-2019 Roman Lebedev.
14 Copyright (C) 2013 Simon Spannagel.
15 Copyright (C) 2015, 2019 Dan Torop.
16 Copyright (C) 2015, 2017 parafin.
17 Copyright (C) 2015 Pascal de Bruijn.
18 Copyright (C) 2016-2017, 2019 Peter Budai.
19 Copyright (C) 2017-2019 Edgardo Hoszowski.
20 Copyright (C) 2017, 2019 luzpaz.
21 Copyright (C) 2019 Andreas Schneider.
22 Copyright (C) 2019, 2021-2022, 2025-2026 Aurélien PIERRE.
23 Copyright (C) 2019 Damian D. Martinez Dreyer.
24 Copyright (C) 2019-2020 Heiko Bauke.
25 Copyright (C) 2019 jakubfi.
26 Copyright (C) 2019-2021 Pascal Obry.
27 Copyright (C) 2020 David-Tillmann Schaefer.
28 Copyright (C) 2020-2022 Hubert Kowalski.
29 Copyright (C) 2020-2021 Ralf Brown.
30 Copyright (C) 2021 Chris Elston.
31 Copyright (C) 2022 Hanno Schwalm.
32 Copyright (C) 2022 Martin Bařinka.
33 Copyright (C) 2022 Victor Forsiuk.
34 Copyright (C) 2024 Alynx Zhou.
35 Copyright (C) 2025-2026 Guillaume Stutin.
36
37 darktable is free software: you can redistribute it and/or modify
38 it under the terms of the GNU General Public License as published by
39 the Free Software Foundation, either version 3 of the License, or
40 (at your option) any later version.
41
42 darktable is distributed in the hope that it will be useful,
43 but WITHOUT ANY WARRANTY; without even the implied warranty of
44 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45 GNU General Public License for more details.
46
47 You should have received a copy of the GNU General Public License
48 along with darktable. If not, see <http://www.gnu.org/licenses/>.
49*/
50
51#ifdef HAVE_OPENCL
52
53#include "common/opencl.h"
54#include "common/paths.h" // DT_PATH_MAX. conditional-ok: this whole file is inside #ifdef HAVE_OPENCL
56#include "common/utility.h" // dt_util_str_replace, used under __APPLE__ only
57#include "system/capabilities.h"
59#include "pixel/bilateralcl.h"
60#include "darktable.h"
61#include "common/dlopencl.h"
62#include "pixel/dwt.h"
64#include "pixel/gaussian.h"
65#include "pixel/guided_filter.h"
66#include "pixel/heal.h"
67#include "pixel/interpolation.h"
69#include "system/nvidia_gpus.h"
70#include <fcntl.h> // O_WRONLY/O_CREAT/O_APPEND. conditional-ok: this whole file is inside #ifdef HAVE_OPENCL
72#include "common/conf.h"
73#include "develop/blend.h"
74#include "develop/pixelpipe.h"
76#include "common/times.h" // dt_get_wtime(). conditional-ok: this whole file is inside #ifdef HAVE_OPENCL
77
78#include <assert.h>
79#include <locale.h>
80#include <stdio.h>
81#include <string.h>
82#include <strings.h>
83
84#include <ctype.h>
85#include <errno.h>
86#include <glib/gstdio.h> // g_fopen, g_rename, g_unlink. conditional-ok: this whole file is inside #ifdef HAVE_OPENCL
87#include <sys/stat.h>
88#include <zlib.h>
89
90typedef struct dt_opencl_t
91{
92 dt_pthread_mutex_t lock;
93 int inited;
101 uint32_t crc;
102 int mandatory[5];
110
111 /* NOTE: the per-subsystem OpenCL kernel bundles (blend, bilateral, gaussian, interpolation,
112 * local laplacian, dwt, heal, colorspaces, guided filter) used to live here. Each was built
113 * by its own subsystem, parked on this struct, and read back from it by that same
114 * subsystem -- a round trip that made nine modules' state look like the OpenCL module's.
115 * They are file-statics in their owners now; this module only orders their init and free
116 * against device setup. */
117
118 // Maps every live cl_mem we allocated to the (devid, byte size) we requested,
119 // so memory accounting never has to query the driver (clGetMemObjectInfo) about
120 // a freshly-created object -- some drivers fault on that under vRAM pressure.
121 GHashTable *mem_sizes;
122 dt_pthread_mutex_t mem_sizes_lock;
124
125/* The OpenCL module's state, owned HERE. It used to hang off the application god-struct as
126 * `darktable.opencl`, which put every device handle, every kernel bundle and this module's
127 * lock one dereference away from any translation unit that included darktable.h. Nothing
128 * outside src/common/opencl.* names it now; callers ask questions instead
129 * (dt_opencl_get_num_devices(), dt_opencl_get_device_name(), ...) and reserve devices through
130 * dt_opencl_reserve_device_*(). */
131static dt_opencl_t *_opencl = NULL;
132
133/* Internal: neither is called from outside this file. */
134static void dt_opencl_cleanup_device(dt_opencl_t *cl, int i);
135
136static inline void _opencl_splash_update_compile(const char *programname)
137{
138 if(IS_NULL_PTR(programname)) return;
139
140 // Whether this becomes a splash screen -- and whether one needs opening first -- is the
141 // display's business. No "is there a GUI?" test needed: unhandled reports are no-ops.
142 dt_startup_progress_report(_("Building OpenCL kernels: %s"), programname);
143}
144
145static const char *dt_opencl_get_vendor_by_id(unsigned int id);
148static const char *_gpu_runtime_of_platform(const char *platform_name);
149static int _gpu_runtime_crash_streak(const char *runtime);
150static void _gpu_runtime_set_crash_streak(const char *runtime, int value);
151static char *_ascii_str_canonical(const char *in, char *out, int maxlen);
153static void dt_opencl_priority_parse(dt_opencl_t *cl, char *configstr, int *priority_list, int *mandatory);
155static void dt_opencl_update_priorities();
160
161
162static int dt_opencl_get_device_info(dt_opencl_t *cl, cl_device_id device, cl_device_info param_name, void **param_value,
163 size_t *param_value_size)
164{
165 *param_value_size = SIZE_MAX;
166
167 // 1. figure out how much memory is needed
168 cl_int err = (cl->dlocl->symbols->dt_clGetDeviceInfo)(device, param_name, 0, NULL, param_value_size);
169 if(err != CL_SUCCESS)
170 {
172 "[dt_opencl_get_device_info] could not query the actual size in bytes of info %d: %i\n", param_name, err);
173 goto error;
174 }
175
176 // 2. did we /actually/ get the size?
177 if(*param_value_size == SIZE_MAX || *param_value_size == 0)
178 {
179 // both of these sizes make no sense. either i failed to parse spec, or opencl implementation bug?
181 "[dt_opencl_get_device_info] ERROR: no size returned, or zero size returned for data %d: %" G_GSIZE_FORMAT "\n",
182 param_name, *param_value_size);
183 err = CL_INVALID_VALUE; // FIXME: anything better?
184 goto error;
185 }
186
187 // 3. make sure that *param_value points to big-enough memory block
188 {
189 void *ptr = realloc(*param_value, *param_value_size);
190 if(IS_NULL_PTR(ptr))
191 {
193 "[dt_opencl_get_device_info] memory allocation failed! tried to allocate %" G_GSIZE_FORMAT " bytes for data %d: %i",
194 *param_value_size, param_name, err);
195 err = CL_OUT_OF_HOST_MEMORY;
196 goto error;
197 }
198
199 // allocation succeeded, update pointer.
200 *param_value = ptr;
201 }
202
203 // 4. actually get the value
204 err = (cl->dlocl->symbols->dt_clGetDeviceInfo)(device, param_name, *param_value_size, *param_value, NULL);
205 if(err != CL_SUCCESS)
206 {
207 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_get_device_info] could not query info %d: %i\n", param_name, err);
208 goto error;
209 }
210
211 return CL_SUCCESS;
212
213error:
214 dt_free(*param_value);
215 *param_value_size = 0;
216 return err;
217}
218
219int dt_opencl_avoid_atomics(const int devid)
220{
221 dt_opencl_t *cl = _opencl;
222 return (!cl->inited || devid < 0) ? 0 : cl->dev[devid].avoid_atomics;
223}
224
225int dt_opencl_micro_nap(const int devid)
226{
227 dt_opencl_t *cl = _opencl;
228 return (!cl->inited || devid < 0) ? 0 : cl->dev[devid].micro_nap;
229}
230
231gboolean dt_opencl_use_pinned_memory(const int devid)
232{
233 dt_opencl_t *cl = _opencl;
234 if(!cl->inited || devid < 0) return FALSE;
235 return cl->dev[devid].pinned_memory & DT_OPENCL_PINNING_ON;
236}
237
238gboolean dt_opencl_is_pinned_memory(cl_mem mem)
239{
240 const cl_mem_flags flags = dt_opencl_get_mem_flags(mem);
241 return (flags & CL_MEM_USE_HOST_PTR) || (flags & CL_MEM_ALLOC_HOST_PTR);
242}
243
244void dt_opencl_write_device_config(const int devid)
245{
246 if(devid < 0) return;
247 dt_opencl_t *cl = _opencl;
248 gchar buf[256] = { 0 };
249 gchar key_device[256] = { 0 };
250 g_snprintf(key_device, 254, "%s/%i/%s", DT_CLDEVICE_HEAD, devid, cl->dev[devid].cname);
251
252 g_snprintf(buf, sizeof(buf), "%s/avoid_atomics", key_device);
253 dt_conf_set_int(buf, cl->dev[devid].avoid_atomics);
254
255 g_snprintf(buf, sizeof(buf), "%s/micro_nap", key_device);
256 dt_conf_set_int(buf, cl->dev[devid].micro_nap);
257
258 g_snprintf(buf, sizeof(buf), "%s/pinned_memory", key_device);
260
261 g_snprintf(buf, sizeof(buf), "%s/wd", key_device);
262 dt_conf_set_int(buf, cl->dev[devid].clroundup_wd);
263
264 g_snprintf(buf, sizeof(buf), "%s/ht", key_device);
265 dt_conf_set_int(buf, cl->dev[devid].clroundup_ht);
266
267 g_snprintf(buf, sizeof(buf), "%s/event_handles", key_device);
268 dt_conf_set_int(buf, cl->dev[devid].event_handles);
269
270 g_snprintf(buf, sizeof(buf), "%s/disabled", key_device);
271 dt_conf_set_int(buf, cl->dev[devid].disabled & 1);
272
273 g_snprintf(buf, sizeof(buf), "%s/id%i/forced_headroom", key_device, devid);
274 dt_conf_set_int(buf, cl->dev[devid].forced_headroom);
275}
276
277static int _dt_opencl_get_conf_int(const gchar *key_device, const gchar *conf_name, gboolean *safety_ok)
278{
279 int res = 0;
280 gchar *key = g_strconcat(key_device, "/", conf_name, NULL);
281 const gboolean existing_device = dt_conf_key_not_empty(key);
282 if(existing_device)
284 else
285 {
286 dt_print(DT_DEBUG_OPENCL, "Warning: conf '%s' not found in anselrc.\n", key);
287 *safety_ok = FALSE;
288 }
289
290 dt_free(key);
291 return res;
292}
293
294gboolean dt_opencl_read_device_config(const int devid)
295{
296 if(devid < 0) return FALSE;
297 dt_opencl_t *cl = _opencl;
298 gchar key_device[256] = { 0 };
299 g_snprintf(key_device, 254, "%s/%i/%s", DT_CLDEVICE_HEAD, devid, cl->dev[devid].cname);
300 gboolean safety_ok = TRUE;
301
302 int avoid_atomics = _dt_opencl_get_conf_int(key_device, "avoid_atomics", &safety_ok);
303 int micro_nap = _dt_opencl_get_conf_int(key_device, "micro_nap", &safety_ok);
304 int pinned_memory = _dt_opencl_get_conf_int(key_device, "pinned_memory", &safety_ok);
305 int wd = _dt_opencl_get_conf_int(key_device, "wd", &safety_ok);
306 int ht = _dt_opencl_get_conf_int(key_device, "ht", &safety_ok);
307 int event_handles = _dt_opencl_get_conf_int(key_device, "event_handles", &safety_ok);
308 int disabled = _dt_opencl_get_conf_int(key_device, "disabled", &safety_ok);
309
310 // some rudimentary safety checking if string seems to be ok
311 safety_ok |= (wd > 1) && (wd < 513) && (ht > 1) && (ht < 513);
312
313 if(safety_ok)
314 {
315 cl->dev[devid].avoid_atomics = avoid_atomics;
316 cl->dev[devid].micro_nap = micro_nap;
317 cl->dev[devid].pinned_memory = pinned_memory;
318 cl->dev[devid].clroundup_wd = wd;
319 cl->dev[devid].clroundup_ht = ht;
320 cl->dev[devid].event_handles = event_handles;
321 cl->dev[devid].disabled = disabled;
322 }
323 else // if there is something wrong with the found conf key reset to defaults
324 {
325 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_read_device_config] malformed data '%s'\n", key_device);
326 }
327
328 // do some safety housekeeping
329 cl->dev[devid].avoid_atomics &= 1;
331
332 /* PINNED HOST MEMORY IS THE DEFAULT, and a stored OFF from before this was decided must not
333 * keep winning silently.
334 *
335 * Every buffer that has to cross back to the CPU -- and on a darkroom frame that is at least
336 * the displayed output, which Cairo can only read from host memory -- is copied by
337 * `dt_opencl_read_host_from_device()`, a BLOCKING read. Into ordinary pageable memory the
338 * driver cannot DMA out of the pages it was handed: it stages through an internal pinned
339 * buffer and copies twice. Page-locked memory removes the staging copy, and
340 * `dt_dev_pixelpipe_cache_sync_cl_buffer()` can additionally take its map/unmap path instead
341 * of copying at all, since `dt_opencl_is_pinned_memory()` tests exactly these flags.
342 *
343 * Measured on a Quadro M2200 over a painting stroke, the same 11.7 MB display buffer, once
344 * per frame: 12.43 ms at 0.94 GB/s with this off, 2.04 ms at 5.58 GB/s with it on. It was
345 * 38% of the frame and became 7%. The default in `_opencl_device_init()` has always been
346 * DT_OPENCL_PINNING_ON; what reached users was a `0` inherited from configurations written
347 * before that, which `dt_opencl_read_device_config()` then loaded over it every start.
348 *
349 * So flip a stored OFF once, per device, and record that we did. The marker is a plain conf
350 * key rather than a confgen one on purpose: confgen keys report as existing from the first
351 * run, so they cannot answer "has this ever been written", whereas this one is absent until
352 * we write it. A user who genuinely wants pinning off sets it again afterwards and keeps it
353 * -- the flip happens once, not on every start. A device seen for the first time gets the
354 * marker with the default already on, so nothing is flipped for it later.
355 *
356 * Pinning is not free: page-locked pages cannot be swapped, so the cache flushes them under
357 * memory pressure (`flushing cached pinned buffers and retrying`). That is a bounded,
358 * handled cost against a copy paid on every frame of every interaction. */
359 gchar pin_default_key[256] = { 0 };
360 g_snprintf(pin_default_key, sizeof(pin_default_key), "%s/pinned_memory_default_applied", key_device);
361 if(!dt_conf_key_exists(pin_default_key))
362 {
363 if(cl->dev[devid].pinned_memory == DT_OPENCL_PINNING_OFF)
364 {
367 "[dt_opencl_read_device_config] '%s' had pinned memory transfer off from an older "
368 "configuration; enabling it, which is the default\n", cl->dev[devid].cname);
369 }
370 dt_conf_set_bool(pin_default_key, TRUE);
371 }
372 cl->dev[devid].micro_nap = CLAMP(cl->dev[devid].micro_nap, 250, 1000000);
373 if((cl->dev[devid].clroundup_wd < 2) || (cl->dev[devid].clroundup_wd > 512))
374 cl->dev[devid].clroundup_wd = 16;
375 if((cl->dev[devid].clroundup_ht < 2) || (cl->dev[devid].clroundup_ht > 512))
376 cl->dev[devid].clroundup_ht = 16;
377 if(cl->dev[devid].event_handles < 0)
378 cl->dev[devid].event_handles = 0x40961440;
379
380 cl->dev[devid].use_events = (cl->dev[devid].event_handles != 0) ? 1 : 0;
381 cl->dev[devid].disabled &= 1;
382
383 // Also take care of extended device data, these are not only device specific but also depend on the devid
384 g_snprintf(key_device, 254, "%s/%i/%s/id%i/forced_headroom", DT_CLDEVICE_HEAD, devid, cl->dev[devid].cname, devid);
385 if(dt_conf_key_not_empty(key_device))
386 {
387 int forced_headroom = dt_conf_get_int(key_device);
388 if(forced_headroom > 0) cl->dev[devid].forced_headroom = forced_headroom;
389 }
390 else if(cl->dev[devid].host_unified_memory)
391 cl->dev[devid].forced_headroom = MAX(512ul, (size_t)dt_conf_get_int64("memory_opencl_headroom"));
392 else // this is used if updating to 4.0 or fresh installs; see commenting _opencl_get_unused_device_mem()
393 cl->dev[devid].forced_headroom = dt_conf_get_int64("memory_opencl_headroom");
394
396 return !safety_ok;
397}
398
400{
401 dt_opencl_t *cl = _opencl;
402 if(IS_NULL_PTR(cl)) return 0;
403
404 return cl->num_detected_devs;
405}
406
408{
409 dt_opencl_t *cl = _opencl;
410 if(IS_NULL_PTR(cl) || detected < 0 || detected >= cl->num_detected_devs) return NULL;
411
412 return cl->detected_devs + detected;
413}
414
415gboolean dt_opencl_detected_device_enabled(const int detected)
416{
418 if(IS_NULL_PTR(device)) return FALSE;
419
420 gchar key[256] = { 0 };
421 g_snprintf(key, sizeof(key), "%s/%d/%s/disabled", DT_CLDEVICE_HEAD, device->config_id,
422 !IS_NULL_PTR(device->cname) ? device->cname : "");
423 const gboolean disabled = dt_conf_key_not_empty(key) ? dt_conf_get_int(key) : (device->disabled & 1);
424
425 return !disabled;
426}
427
428int dt_opencl_set_detected_device_enabled(const int detected, const gboolean enabled)
429{
431 if(IS_NULL_PTR(device)) return -1;
432
433 gchar key[256] = { 0 };
434 g_snprintf(key, sizeof(key), "%s/%d/%s/disabled", DT_CLDEVICE_HEAD, device->config_id,
435 !IS_NULL_PTR(device->cname) ? device->cname : "");
436 dt_conf_set_int(key, enabled ? 0 : 1);
437
438 dt_opencl_t *cl = _opencl;
439 cl->detected_devs[detected].disabled = enabled ? 0 : 1;
440
441 gboolean opencl_enabled = enabled;
442 if(!opencl_enabled)
443 {
444 // The global OpenCL preference is derived from all detected GPUs. We are looking
445 // for any GPU still enabled before turning OpenCL off globally.
446 for(int dev = 0; dev < cl->num_detected_devs; dev++)
447 {
449 {
450 opencl_enabled = TRUE;
451 break;
452 }
453 }
454 }
455
456 dt_conf_set_bool("opencl", opencl_enabled);
457 return 0;
458}
459
460gboolean dt_opencl_detected_device_pinned_memory(const int detected)
461{
463 if(IS_NULL_PTR(device)) return FALSE;
464
465 gchar key[256] = { 0 };
466 g_snprintf(key, sizeof(key), "%s/%d/%s/pinned_memory", DT_CLDEVICE_HEAD, device->config_id,
467 !IS_NULL_PTR(device->cname) ? device->cname : "");
468 const int pinned_memory = dt_conf_key_not_empty(key) ? dt_conf_get_int(key) : device->pinned_memory;
469
470 return pinned_memory & DT_OPENCL_PINNING_ON;
471}
472
473int dt_opencl_set_detected_device_pinned_memory(const int detected, const gboolean enabled)
474{
476 if(IS_NULL_PTR(device)) return -1;
477
478 gchar key[256] = { 0 };
479 const int pinned_memory = enabled ? DT_OPENCL_PINNING_ON : DT_OPENCL_PINNING_OFF;
480 g_snprintf(key, sizeof(key), "%s/%d/%s/pinned_memory", DT_CLDEVICE_HEAD, device->config_id,
481 !IS_NULL_PTR(device->cname) ? device->cname : "");
482 dt_conf_set_int(key, pinned_memory);
483
484 dt_opencl_t *cl = _opencl;
485 cl->detected_devs[detected].pinned_memory = pinned_memory;
486 // device->config_id is this device's live index into cl->dev[] (assigned at detection time,
487 // see dt_opencl_device_init()) -- apply immediately instead of only on the next restart, since
488 // dt_opencl_use_pinned_memory() reads cl->dev[], never cl->detected_devs[].
489 if(device->config_id >= 0 && device->config_id < cl->num_devs)
490 cl->dev[device->config_id].pinned_memory = pinned_memory;
491 return 0;
492}
493
494size_t dt_opencl_detected_device_headroom(const int detected)
495{
497 if(IS_NULL_PTR(device)) return 0;
498
499 gchar key[256] = { 0 };
500 g_snprintf(key, sizeof(key), "%s/%d/%s/id%d/forced_headroom", DT_CLDEVICE_HEAD, device->config_id,
501 !IS_NULL_PTR(device->cname) ? device->cname : "", device->config_id);
502
503 return dt_conf_key_not_empty(key) ? (size_t)dt_conf_get_int(key) : device->forced_headroom;
504}
505
506int dt_opencl_set_detected_device_headroom(const int detected, const size_t headroom)
507{
509 if(IS_NULL_PTR(device)) return -1;
510
511 gchar key[256] = { 0 };
512 g_snprintf(key, sizeof(key), "%s/%d/%s/id%d/forced_headroom", DT_CLDEVICE_HEAD, device->config_id,
513 !IS_NULL_PTR(device->cname) ? device->cname : "", device->config_id);
514 const int clamped_headroom = (int)MIN(headroom, (size_t)G_MAXINT);
515 dt_conf_set_int(key, clamped_headroom);
516
517 dt_opencl_t *cl = _opencl;
518 cl->detected_devs[detected].forced_headroom = clamped_headroom;
519 // Same live-apply as pinned memory above: device->config_id is this device's index into
520 // cl->dev[], which dt_opencl_get_device_available() actually reads through used_available.
521 // dt_opencl_check_tuning() recomputes that from the value we just wrote, so the new headroom
522 // is in effect before this function returns instead of only after a restart.
523 if(device->config_id >= 0 && device->config_id < cl->num_devs)
524 {
525 cl->dev[device->config_id].forced_headroom = clamped_headroom;
527 }
528 return 0;
529}
530
531// returns 0 if all ok or an error if we failed to init this device
532static int dt_opencl_device_init(dt_opencl_t *cl, const int dev, cl_device_id *devices, const int k)
533{
534 int res;
535 cl_int err;
536 gboolean lock_initialized = FALSE;
537
538 memset(cl->dev[dev].program, 0x0, sizeof(cl_program) * DT_OPENCL_MAX_PROGRAMS);
539 memset(cl->dev[dev].program_used, 0x0, sizeof(int) * DT_OPENCL_MAX_PROGRAMS);
540 memset(cl->dev[dev].kernel, 0x0, sizeof(cl_kernel) * DT_OPENCL_MAX_KERNELS);
541 memset(cl->dev[dev].kernel_used, 0x0, sizeof(int) * DT_OPENCL_MAX_KERNELS);
542 cl->dev[dev].context = NULL;
543 cl->dev[dev].cmd_queue = NULL;
544 cl->dev[dev].eventlist = NULL;
545 cl->dev[dev].eventtags = NULL;
546 cl->dev[dev].numevents = 0;
547 cl->dev[dev].eventsconsolidated = 0;
548 cl->dev[dev].maxevents = 0;
549 cl->dev[dev].maxeventslot = 0;
550 cl->dev[dev].lostevents = 0;
551 cl->dev[dev].totalevents = 0;
552 cl->dev[dev].totalsuccess = 0;
553 cl->dev[dev].totallost = 0;
554 cl->dev[dev].summary = CL_COMPLETE;
555 cl->dev[dev].used_global_mem = 0;
556 cl->dev[dev].nvidia_sm_20 = 0;
557 cl->dev[dev].vendor = NULL;
558 cl->dev[dev].runtime_id = NULL;
559 cl->dev[dev].name = NULL;
560 cl->dev[dev].cname = NULL;
561 cl->dev[dev].options = NULL;
562 cl->dev[dev].options_md5 = NULL;
563 cl->dev[dev].memory_in_use = 0;
564 cl->dev[dev].peak_memory = 0;
565 cl->dev[dev].used_available = 0;
566 // setting sane/conservative defaults at first
567 cl->dev[dev].avoid_atomics = 0;
568 cl->dev[dev].micro_nap = 250;
570 cl->dev[dev].clroundup_wd = 16;
571 cl->dev[dev].clroundup_ht = 16;
572 cl->dev[dev].use_events = 1;
573 cl->dev[dev].event_handles = 128;
574 cl->dev[dev].disabled = 0;
575 cl->dev[dev].forced_headroom = 0;
576 cl->dev[dev].runtime_error = 0;
577 cl_device_id devid = cl->dev[dev].devid = devices[k];
578
579 char *infostr = NULL;
580 size_t infostr_size;
581
582 char *cname = NULL;
583 size_t cname_size;
584
585 char *vendor = NULL;
586 size_t vendor_size;
587
588 char *driverversion = NULL;
589 size_t driverversion_size;
590
591 char *deviceversion = NULL;
592 size_t deviceversion_size;
593
594 size_t infoint;
595 size_t *infointtab = NULL;
596 cl_device_type type;
597 cl_bool image_support = 0;
598 cl_bool device_available = 0;
599 cl_uint vendor_id = 0;
600 cl_bool little_endian = 0;
601 cl_platform_id platform_id = 0;
602
603 char *dtcache = calloc(DT_PATH_MAX, sizeof(char));
604 char *cachedir = calloc(DT_PATH_MAX, sizeof(char));
605 char *devname = calloc(DT_OPENCL_CBUFFSIZE, sizeof(char));
606 char *drvversion = calloc(DT_OPENCL_CBUFFSIZE, sizeof(char));
607 char *platform_name = calloc(DT_OPENCL_CBUFFSIZE, sizeof(char));
608 char *platform_vendor = calloc(DT_OPENCL_CBUFFSIZE, sizeof(char));
609
610 char kerneldir[DT_PATH_MAX] = { 0 };
611 char *filename = calloc(DT_PATH_MAX, sizeof(char));
612 char *confentry = calloc(DT_PATH_MAX, sizeof(char));
613 char *binname = calloc(DT_PATH_MAX, sizeof(char));
614 dt_print_nts(DT_DEBUG_OPENCL, "\n[dt_opencl_device_init]\n");
615
616 // test GPU availability, vendor, memory, image support etc:
617 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_AVAILABLE, sizeof(cl_bool), &device_available, NULL);
618
619 // Queried early (before dt_opencl_read_device_config() below, which needs it to pick a sane
620 // default headroom on first run) rather than alongside the other capability queries further down.
621 cl_bool host_unified_memory = CL_FALSE;
622 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_HOST_UNIFIED_MEMORY, sizeof(cl_bool),
623 &host_unified_memory, NULL);
624 cl->dev[dev].host_unified_memory = (host_unified_memory == CL_TRUE);
625
626 err = dt_opencl_get_device_info(cl, devid, CL_DEVICE_VENDOR, (void **)&vendor, &vendor_size);
627 if(err != CL_SUCCESS)
628 {
629 dt_print_nts(DT_DEBUG_OPENCL, " *** could not get vendor name of device %d: %i\n", k, err);
630 res = -1;
631 goto end;
632 }
633
634 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_VENDOR_ID, sizeof(cl_uint), &vendor_id, NULL);
635
636 err = dt_opencl_get_device_info(cl, devid, CL_DEVICE_NAME, (void **)&infostr, &infostr_size);
637 if(err != CL_SUCCESS)
638 {
639 dt_print_nts(DT_DEBUG_OPENCL, " *** could not get device name of device %d: %i\n", k, err);
640 res = -1;
641 goto end;
642 }
643
644 // get the canonical device name
645 cname_size = infostr_size;
646 cname = malloc(cname_size);
647 _ascii_str_canonical(infostr, cname, cname_size);
648 cl->dev[dev].name = strdup(infostr);
649 cl->dev[dev].cname = strdup(cname);
650
651 // take every detected device into account of checksum
652 cl->crc = crc32(cl->crc, (const unsigned char *)infostr, strlen(infostr));
653
654 err = (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &platform_id, NULL);
655 if(err != CL_SUCCESS)
656 {
657 g_strlcpy(platform_vendor, "no platform id", DT_OPENCL_CBUFFSIZE);
658 g_strlcpy(platform_name, "no platform id", DT_OPENCL_CBUFFSIZE);
659 dt_print_nts(DT_DEBUG_OPENCL, " *** could not get platform id for device `%s' : %i\n", cl->dev[dev].name, err);
660 }
661 else
662 {
663 err = (cl->dlocl->symbols->dt_clGetPlatformInfo)(platform_id, CL_PLATFORM_NAME, DT_OPENCL_CBUFFSIZE, platform_name, NULL);
664 if(err != CL_SUCCESS)
665 {
666 dt_print_nts(DT_DEBUG_OPENCL, " *** could not get platform name for device `%s' : %i\n", cl->dev[dev].name, err);
667 g_strlcpy(platform_name, "???", DT_OPENCL_CBUFFSIZE);
668 }
669
670 err = (cl->dlocl->symbols->dt_clGetPlatformInfo)(platform_id, CL_PLATFORM_VENDOR, DT_OPENCL_CBUFFSIZE, platform_vendor, NULL);
671 if(err != CL_SUCCESS)
672 {
673 dt_print_nts(DT_DEBUG_OPENCL, " *** could not get platform vendor for device `%s' : %i\n", cl->dev[dev].name, err);
674 g_strlcpy(platform_vendor, "???", DT_OPENCL_CBUFFSIZE);
675 }
676 }
677
678 const gboolean newdevice = dt_opencl_read_device_config(dev);
679 dt_print_nts(DT_DEBUG_OPENCL, " DEVICE: %d: '%s'%s\n", k, infostr, (newdevice) ? ", NEW" : "" );
680 dt_print_nts(DT_DEBUG_OPENCL, " CANONICAL NAME: %s\n", cname);
681 dt_print_nts(DT_DEBUG_OPENCL, " PLATFORM NAME & VENDOR: %s, %s\n", platform_name, platform_vendor);
682
683 err = dt_opencl_get_device_info(cl, devid, CL_DRIVER_VERSION, (void **)&driverversion, &driverversion_size);
684 if(err != CL_SUCCESS)
685 {
686 dt_print_nts(DT_DEBUG_OPENCL, " *** driver version not available *** %i\n", err);
687 res = -1;
688 cl->dev[dev].disabled |= 1;
689 goto end;
690 }
691
692 err = dt_opencl_get_device_info(cl, devid, CL_DEVICE_VERSION, (void **)&deviceversion, &deviceversion_size);
693 if(err != CL_SUCCESS)
694 {
695 dt_print_nts(DT_DEBUG_OPENCL, " *** device version not available *** %i\n", err);
696 res = -1;
697 cl->dev[dev].disabled |= 1;
698 goto end;
699 }
700
701 // take every detected device driver into account of checksum
702 cl->crc = crc32(cl->crc, (const unsigned char *)deviceversion, deviceversion_size);
703
704 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_TYPE, sizeof(cl_device_type), &type, NULL);
705 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_IMAGE_SUPPORT, sizeof(cl_bool), &image_support, NULL);
706 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof(size_t),
707 &(cl->dev[dev].max_image_height), NULL);
708 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof(size_t),
709 &(cl->dev[dev].max_image_width), NULL);
710 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong),
711 &(cl->dev[dev].max_mem_alloc), NULL);
712 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_ENDIAN_LITTLE, sizeof(cl_bool), &little_endian, NULL);
713
714 cl->dev[dev].cltype = (unsigned int)type;
715
716
717 if(!strncasecmp(vendor, "NVIDIA", 6))
718 {
719 // very lame attempt to detect support for atomic float add in global memory.
720 // we need compute model sm_20, but let's try for all nvidia devices :(
722 }
723
724 const gboolean is_cpu_device = (type & CL_DEVICE_TYPE_CPU) == CL_DEVICE_TYPE_CPU;
725
726 // micro_nap can be made less conservative on current systems at least if not on-CPU
727 if(newdevice)
728 cl->dev[dev].micro_nap = (is_cpu_device) ? 1000 : 250;
729
730 dt_print_nts(DT_DEBUG_OPENCL, " DRIVER VERSION: %s\n", driverversion);
731 dt_print_nts(DT_DEBUG_OPENCL, " DEVICE VERSION: %s%s\n", deviceversion,
732 cl->dev[dev].nvidia_sm_20 ? ", SM_20 SUPPORT" : "");
733 dt_print_nts(DT_DEBUG_OPENCL, " DEVICE_TYPE: %s%s%s\n",
734 ((type & CL_DEVICE_TYPE_CPU) == CL_DEVICE_TYPE_CPU) ? "CPU" : "",
735 ((type & CL_DEVICE_TYPE_GPU) == CL_DEVICE_TYPE_GPU) ? "GPU" : "",
736 (type & CL_DEVICE_TYPE_ACCELERATOR) ? ", Accelerator" : "" );
737
738 if(is_cpu_device && newdevice)
739 {
740 dt_print_nts(DT_DEBUG_OPENCL, " *** discarding new device as emulated by CPU ***\n");
741 cl->dev[dev].disabled |= 1;
742 res = -1;
743 goto end;
744 }
745
746 if(!device_available)
747 {
748 dt_print_nts(DT_DEBUG_OPENCL, " *** device is not available ***\n");
749 res = -1;
750 goto end;
751 }
752
753 if(!image_support)
754 {
755 dt_print_nts(DT_DEBUG_OPENCL, " *** The OpenCL driver doesn't provide image support. See also 'clinfo' output ***\n");
756 res = -1;
757 cl->dev[dev].disabled |= 1;
758 goto end;
759 }
760
761 if(!little_endian)
762 {
763 dt_print_nts(DT_DEBUG_OPENCL, " *** device is not little endian ***\n");
764 res = -1;
765 cl->dev[dev].disabled |= 1;
766 goto end;
767 }
768
769 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(cl_ulong),
770 &(cl->dev[dev].max_global_mem), NULL);
771 if(cl->dev[dev].max_global_mem < (uint64_t)512ul * 1024ul * 1024ul)
772 {
773 dt_print_nts(DT_DEBUG_OPENCL, " *** insufficient global memory (%" PRIu64 "MB) ***\n",
774 cl->dev[dev].max_global_mem / 1024 / 1024);
775 res = -1;
776 cl->dev[dev].disabled |= 1;
777 goto end;
778 }
779
780 cl->dev[dev].vendor = strdup(dt_opencl_get_vendor_by_id(vendor_id));
781 cl->dev[dev].vendor_id = vendor_id;
782
783 /* Which OpenCL runtime publishes this device. A string literal owned by the runtime table,
784 * so it outlives the device and is never freed; NULL for a platform we ship no rule for,
785 * which simply means no crash can ever be attributed to it. */
786 cl->dev[dev].runtime_id = _gpu_runtime_of_platform(platform_name);
787 dt_print_nts(DT_DEBUG_OPENCL, " OPENCL RUNTIME: %s\n",
788 cl->dev[dev].runtime_id ? cl->dev[dev].runtime_id : "unrecognised");
789
790 /* Skip this device if ITS runtime is what keeps crashing.
791 *
792 * Per runtime, not per vendor: Mesa's Rusticl drives AMD and Intel cards alike, so keying on
793 * the hardware vendor could neither disable both nor tell a Rusticl panic apart from a fault
794 * in AMD's own amdocl on the same card. A machine with an Intel iGPU and an NVIDIA dGPU
795 * still keeps the NVIDIA when Intel's compiler is the one faulting -- those are different
796 * runtimes, which is exactly what the streak counts. A device whose runtime was never on a
797 * crashing stack is untouched however often something else fails.
798 *
799 * The device name and driver version go in the message because that is what a user needs to
800 * act on -- which card, which driver to update. */
801 const int runtime_crash_streak = _gpu_runtime_crash_streak(cl->dev[dev].runtime_id);
802 if(runtime_crash_streak >= 2)
803 {
805 "[opencl_init] disabling device %d `%s' (%s runtime, driver %s): the last %d"
806 " crashes happened inside this OpenCL runtime. Re-enable it in preferences once"
807 " the driver is updated; devices on other runtimes are unaffected.\n",
808 dev, infostr ? infostr : "?", cl->dev[dev].runtime_id,
809 driverversion ? driverversion : "?", runtime_crash_streak);
810 cl->dev[dev].disabled |= 1;
811 res = -1;
812 goto end;
813 }
814
815 const gboolean is_blacklisted = dt_opencl_check_driver_blacklist(deviceversion);
816
817 // disable device for now if this is the first time detected and blacklisted too.
818 if(newdevice && is_blacklisted)
819 {
820 // To keep installations we look for the old blacklist conf key
821 const gboolean old_blacklist = dt_conf_get_bool("opencl_disable_drivers_blacklist");
822 cl->dev[dev].disabled |= (old_blacklist) ? 0 : 1;
823 if(cl->dev[dev].disabled)
824 dt_print_nts(DT_DEBUG_OPENCL, " *** new device is blacklisted ***\n");
825 res = -1;
826 goto end;
827 }
828
829 dt_print_nts(DT_DEBUG_OPENCL, " GLOBAL MEM SIZE: %.0f MB\n", (double)cl->dev[dev].max_global_mem / 1024.0 / 1024.0);
830 dt_print_nts(DT_DEBUG_OPENCL, " MAX MEM ALLOC: %.0f MB\n", (double)cl->dev[dev].max_mem_alloc / 1024.0 / 1024.0);
831 dt_print_nts(DT_DEBUG_OPENCL, " MAX IMAGE SIZE: %" G_GSIZE_FORMAT " x %" G_GSIZE_FORMAT "\n", cl->dev[dev].max_image_width, cl->dev[dev].max_image_height);
832 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(infoint), &infoint, NULL);
833 dt_print_nts(DT_DEBUG_OPENCL, " MAX WORK GROUP SIZE: %" G_GSIZE_FORMAT "\n", infoint);
834 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(infoint), &infoint, NULL);
835 dt_print_nts(DT_DEBUG_OPENCL, " MAX WORK ITEM DIMENSIONS: %" G_GSIZE_FORMAT "\n", infoint);
836
837 size_t infointtab_size;
838 err = dt_opencl_get_device_info(cl, devid, CL_DEVICE_MAX_WORK_ITEM_SIZES, (void **)&infointtab, &infointtab_size);
839 if(err == CL_SUCCESS)
840 {
841 dt_print_nts(DT_DEBUG_OPENCL, " MAX WORK ITEM SIZES: [ ");
842 for(size_t i = 0; i < infoint; i++) dt_print_nts(DT_DEBUG_OPENCL, "%" G_GSIZE_FORMAT " ", infointtab[i]);
843 dt_free(infointtab);
845 }
846 else
847 {
848 dt_print_nts(DT_DEBUG_OPENCL, " *** could not get maximum work item sizes ***\n");
849 res = -1;
850 cl->dev[dev].disabled |= 1;
851 goto end;
852 }
853
854 const gboolean pinning = (cl->dev[dev].pinned_memory & DT_OPENCL_PINNING_ON);
855 dt_print_nts(DT_DEBUG_OPENCL, " PINNED MEMORY TRANSFER: %s\n", pinning ? "WANTED" : "NO");
856 dt_print_nts(DT_DEBUG_OPENCL, " FORCED HEADROOM: %" G_GSIZE_FORMAT "\n", cl->dev[dev].forced_headroom);
857 dt_print_nts(DT_DEBUG_OPENCL, " AVOID ATOMICS: %s\n", (cl->dev[dev].avoid_atomics) ? "YES" : "NO");
858 dt_print_nts(DT_DEBUG_OPENCL, " MICRO NAP: %i\n", cl->dev[dev].micro_nap);
859 dt_print_nts(DT_DEBUG_OPENCL, " ROUNDUP WIDTH: %i\n", cl->dev[dev].clroundup_wd);
860 dt_print_nts(DT_DEBUG_OPENCL, " ROUNDUP HEIGHT: %i\n", cl->dev[dev].clroundup_ht);
861 dt_print_nts(DT_DEBUG_OPENCL, " CHECK EVENT HANDLES: %i\n", cl->dev[dev].event_handles);
862 dt_print_nts(DT_DEBUG_OPENCL, " DEFAULT DEVICE: %s\n", (type & CL_DEVICE_TYPE_DEFAULT) ? "YES" : "NO");
863
864 if(type & CL_DEVICE_TYPE_GPU)
865 {
866 dt_opencl_detected_device_t *detected_devs
867 = g_realloc(cl->detected_devs, sizeof(*cl->detected_devs) * (cl->num_detected_devs + 1));
868 if(!IS_NULL_PTR(detected_devs))
869 {
870 cl->detected_devs = detected_devs;
872 detected->config_id = dev;
873 detected->name = g_strdup(cl->dev[dev].name);
874 detected->cname = g_strdup(cl->dev[dev].cname);
875 detected->cltype = cl->dev[dev].cltype;
876 detected->disabled = cl->dev[dev].disabled & 1;
877 detected->pinned_memory = cl->dev[dev].pinned_memory;
878 detected->forced_headroom = cl->dev[dev].forced_headroom;
879 detected->host_unified_memory = cl->dev[dev].host_unified_memory;
880 cl->num_detected_devs++;
881 }
882 }
883
884 if(cl->dev[dev].disabled)
885 {
886 dt_print_nts(DT_DEBUG_OPENCL, " *** marked as disabled ***\n");
887 res = -1;
888 goto end;
889 }
890 dt_print_nts(DT_DEBUG_OPENCL, " *** Device enabled ***\n");
891
892 dt_pthread_mutex_init(&cl->dev[dev].lock, NULL);
893 lock_initialized = TRUE;
894
895 cl->dev[dev].context = (cl->dlocl->symbols->dt_clCreateContext)(0, 1, &devid, NULL, NULL, &err);
896 if(err != CL_SUCCESS)
897 {
898 dt_print_nts(DT_DEBUG_OPENCL, " *** could not create context *** %i\n", err);
899 res = -1;
900 goto end;
901 }
902 // create a command queue for first device the context reported
904 cl->dev[dev].context, devid, (dt_get_debug_flags() & DT_DEBUG_PERF) ? CL_QUEUE_PROFILING_ENABLE : 0, &err);
905 if(err != CL_SUCCESS)
906 {
907 dt_print_nts(DT_DEBUG_OPENCL, " *** could not create command queue *** %i\n", err);
908 res = -1;
909 goto end;
910 }
911
912 dt_loc_get_kerneldir(kerneldir, sizeof(kerneldir));
913 dt_print_nts(DT_DEBUG_OPENCL, " KERNEL SOURCE DIRECTORY: %s\n", kerneldir);
914
915 double tstart, tend, tdiff;
916 dt_loc_get_user_cache_dir(dtcache, DT_PATH_MAX * sizeof(char));
917
918 int len = MIN(strlen(infostr),1024 * sizeof(char));;
919 int j = 0;
920 // remove non-alphanumeric chars from device name
921 for(int i = 0; i < len; i++)
922 if(isalnum(infostr[i])) devname[j++] = infostr[i];
923 devname[j] = 0;
924 len = MIN(strlen(driverversion), 1024 * sizeof(char));
925 j = 0;
926 // remove non-alphanumeric chars from driver version
927 for(int i = 0; i < len; i++)
928 if(isalnum(driverversion[i])) drvversion[j++] = driverversion[i];
929 drvversion[j] = 0;
930 snprintf(cachedir, DT_PATH_MAX * sizeof(char), "%s" G_DIR_SEPARATOR_S "cached_kernels_for_%s_%s", dtcache, devname, drvversion);
931
932 dt_print_nts(DT_DEBUG_OPENCL, " KERNEL BUILD DIRECTORY: %s\n", cachedir);
933
934 if(g_mkdir_with_parents(cachedir, 0700) == -1)
935 {
936 dt_print_nts(DT_DEBUG_OPENCL, " *** failed to create kernel directory `%s' ***\n", cachedir);
937 res = -1;
938 goto end;
939 }
940
941 dt_concat_path_file(filename, kerneldir, "programs.conf");
942
943 char *escapedkerneldir = NULL;
944#ifndef __APPLE__
945 escapedkerneldir = g_strdup_printf("\"%s\"", kerneldir);
946#else
947 escapedkerneldir = dt_util_str_replace(kerneldir, " ", "\\ ");
948#endif
949
950 gchar* compile_option_name_cname = g_strdup_printf("%s/%i/%s/building", DT_CLDEVICE_HEAD, dev, cl->dev[dev].cname);
951 const char* compile_opt = NULL;
952
953 if(dt_conf_key_exists(compile_option_name_cname))
954 compile_opt = dt_conf_get_string_const(compile_option_name_cname);
955 else
956 {
957 switch(vendor_id)
958 {
960 compile_opt = DT_OPENCL_DEFAULT_COMPILE_AMD;
961 break;
964 break;
967 break;
968 default:
969 compile_opt = DT_OPENCL_DEFAULT_COMPILE;
970 }
971 }
972 gchar *my_option = g_strdup(compile_opt);
973 dt_conf_set_string(compile_option_name_cname, my_option);
974
975 cl->dev[dev].options = g_strdup_printf("-w %s %s -D%s=1 -I%s",
976 my_option,
977 (cl->dev[dev].nvidia_sm_20 ? " -DNVIDIA_SM_20=1" : ""),
978 dt_opencl_get_vendor_by_id(vendor_id), escapedkerneldir);
979 // Keep kernel checksum stable when the runtime kernel path changes (e.g. AppImage mount point).
980 const char *kerneldir_token = "<ansel-kernels>";
981 char *escapedkerneldir_md5 = NULL;
982#ifndef __APPLE__
983 escapedkerneldir_md5 = g_strdup_printf("\"%s\"", kerneldir_token);
984#else
985 escapedkerneldir_md5 = g_strdup(kerneldir_token);
986#endif
987 cl->dev[dev].options_md5 = g_strdup_printf("-w %s %s -D%s=1 -I%s",
988 my_option,
989 (cl->dev[dev].nvidia_sm_20 ? " -DNVIDIA_SM_20=1" : ""),
990 dt_opencl_get_vendor_by_id(vendor_id), escapedkerneldir_md5);
991
992 dt_print_nts(DT_DEBUG_OPENCL, " CL COMPILER OPTION: %s\n", my_option);
993
994 dt_free(compile_option_name_cname);
995 dt_free(my_option);
996 dt_free(escapedkerneldir);
997 dt_free(escapedkerneldir_md5);
998 escapedkerneldir = NULL;
999
1000 /* Every header a .cl may include, so a change to one invalidates the cached device
1001 * binaries that were built from it -- an omission here does not fail, it silently keeps
1002 * running yesterday's kernel. lensserious_eval.h is LensSerious's evaluator, installed
1003 * beside the kernels by data/kernels/CMakeLists.txt. */
1004 const char *clincludes[DT_OPENCL_MAX_INCLUDES] = { "rgb_norms.h", "noise_generator.h", "color_conversion.h", "colorspaces.cl", "colorspace.h", "common.h", "lensserious_eval.h", NULL };
1005 char *includemd5[DT_OPENCL_MAX_INCLUDES] = { NULL };
1006 dt_opencl_md5sum(clincludes, includemd5);
1007
1008 if(newdevice) // so far the device seems to be ok. Make sure to write&export the conf database to
1009 {
1011 dt_conf_flush();
1012 }
1013
1014 // now load all darktable cl kernels.
1015 // TODO: compile as a job?
1016 tstart = dt_get_wtime();
1017 FILE *f = g_fopen(filename, "rb");
1018 if(f)
1019 {
1020 while(!feof(f))
1021 {
1022 int prog = -1;
1023 gchar *confline_pattern = g_strdup_printf("%%%" G_GSIZE_FORMAT "[^\n]\n", DT_PATH_MAX * sizeof(char) - 1);
1024 int rd = fscanf(f, confline_pattern, confentry);
1025 dt_free(confline_pattern);
1026 if(rd != 1) continue;
1027 // remove comments:
1028 size_t end = strlen(confentry);
1029 for(size_t pos = 0; pos < end; pos++)
1030 if(confentry[pos] == '#')
1031 {
1032 confentry[pos] = '\0';
1033 for(int l = pos - 1; l >= 0; l--)
1034 {
1035 if(confentry[l] == ' ')
1036 confentry[l] = '\0';
1037 else
1038 break;
1039 }
1040 break;
1041 }
1042 if(confentry[0] == '\0') continue;
1043
1044 const char *programname = NULL, *programnumber = NULL;
1045 gchar **tokens = g_strsplit_set(confentry, " \t", 2);
1046 if(tokens)
1047 {
1048 programname = tokens[0];
1049 if(tokens[0])
1050 programnumber = tokens[1]; // if the 0st wasn't NULL then we have at least the terminating NULL in [1]
1051 }
1052
1053 prog = programnumber ? strtol(programnumber, NULL, 10) : -1;
1054
1055 if(IS_NULL_PTR(programname) || programname[0] == '\0' || prog < 0)
1056 {
1057 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_device_init] malformed entry in programs.conf `%s'; ignoring it!\n", confentry);
1058 continue;
1059 }
1060 dt_concat_path_file(filename, kerneldir, programname);
1061 gchar *program_bin = g_strdup_printf("%s.bin", programname);
1062 dt_concat_path_file(binname, cachedir, program_bin);
1063 dt_free(program_bin);
1064
1065 dt_vprint(DT_DEBUG_OPENCL, "[dt_opencl_device_init] testing program `%s' ..\n", programname);
1066 int loaded_cached;
1067 char md5sum[33];
1068 if(dt_opencl_load_program(dev, prog, filename, binname, cachedir, md5sum, includemd5, &loaded_cached))
1069 {
1070 if(!loaded_cached)
1071 _opencl_splash_update_compile(programname);
1072
1073 if(dt_opencl_build_program(dev, prog, binname, cachedir, md5sum, loaded_cached) != CL_SUCCESS)
1074 {
1075 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_device_init] failed to compile program `%s'!\n", programname);
1076 fclose(f);
1077 g_strfreev(tokens);
1078 res = -1;
1079 goto end;
1080 }
1081 }
1082
1083 g_strfreev(tokens);
1084 }
1085
1086 fclose(f);
1087 tend = dt_get_wtime();
1088 tdiff = tend - tstart;
1089 dt_print_nts(DT_DEBUG_OPENCL, " KERNEL LOADING TIME: %2.4lf sec\n", tdiff);
1090 }
1091 else
1092 {
1093 dt_print_nts(DT_DEBUG_OPENCL, "[dt_opencl_device_init] could not open `%s'!\n", filename);
1094 res = -1;
1095 goto end;
1096 }
1097 for(int n = 0; n < DT_OPENCL_MAX_INCLUDES; n++) dt_free(includemd5[n]);
1098 res = 0;
1099
1100end:
1101 // we always write the device config to keep track of disabled devices
1103
1104 if(res != 0)
1105 {
1106 if(lock_initialized)
1107 {
1108 for(int n = 0; n < DT_OPENCL_MAX_KERNELS; n++)
1109 if(cl->dev[dev].kernel_used[n]) (cl->dlocl->symbols->dt_clReleaseKernel)(cl->dev[dev].kernel[n]);
1110 for(int n = 0; n < DT_OPENCL_MAX_PROGRAMS; n++)
1111 if(cl->dev[dev].program_used[n]) (cl->dlocl->symbols->dt_clReleaseProgram)(cl->dev[dev].program[n]);
1112 if(!IS_NULL_PTR(cl->dev[dev].cmd_queue))
1114 if(!IS_NULL_PTR(cl->dev[dev].context))
1115 (cl->dlocl->symbols->dt_clReleaseContext)(cl->dev[dev].context);
1117 }
1118
1119 dt_free(cl->dev[dev].vendor);
1120 dt_free(cl->dev[dev].name);
1121 dt_free(cl->dev[dev].cname);
1122 dt_free(cl->dev[dev].options);
1123 dt_free(cl->dev[dev].options_md5);
1124 }
1125
1126 dt_free(infostr);
1127 dt_free(cname);
1128 dt_free(vendor);
1129 dt_free(driverversion);
1130 dt_free(deviceversion);
1131
1132 dt_free(dtcache);
1133 dt_free(cachedir);
1134 dt_free(devname);
1135 dt_free(drvversion);
1136 dt_free(platform_name);
1137 dt_free(platform_vendor);
1138
1139 dt_free(filename);
1140 dt_free(confentry);
1141 dt_free(binname);
1142
1143 return res;
1144}
1145
1146/* OpenCL runtimes, by the name their shared object carries in a crash backtrace and the
1147 * CL_PLATFORM_NAME of the platform they publish.
1148 *
1149 * The module name is deliberately the RUNTIME's own object, never the ICD loader (OpenCL.dll /
1150 * libOpenCL.so): the loader is on the stack of every OpenCL crash, including ones that are
1151 * entirely ours.
1152 *
1153 * The key is the RUNTIME, not the hardware vendor. A runtime is what crashes, and a runtime is
1154 * what a device can be moved off; the vendor is neither. Mesa's Rusticl is what forces the
1155 * distinction (issue #1226): it drives AMD radeonsi and Intel iris cards alike, so a
1156 * vendor-keyed streak could neither cover both nor tell a Rusticl panic apart from a fault in
1157 * AMD's own amdocl on the very same card. A device belongs to exactly one platform and a
1158 * platform is published by exactly one runtime, so CL_PLATFORM_NAME is the honest way back
1159 * from a device to the thing that crashed.
1160 *
1161 * Rows may share a conf_suffix: one runtime can ship several objects, and either can be the one
1162 * on the stack (Intel's compiler and its runtime proper are separate libraries). The suffix,
1163 * not the row, is the identity; a platform lookup stops at the first row that matches.
1164 *
1165 * Platform matching is a case-insensitive substring test and it fails OPEN -- an unrecognised
1166 * platform gets no streak and is never disabled, which is what every platform did before this
1167 * table existed. That is the safe direction, but it means a runtime that renames its platform
1168 * silently stops being covered, so each device logs the runtime it resolved to under
1169 * `-d opencl` and a report tells us which string to add.
1170 *
1171 * The platform strings for rusticl, Intel, NVIDIA and Clover are sampled from clinfo; AMD's is
1172 * the long-standing name of its APP platform under both the proprietary stack and ROCm, and is
1173 * the one row here not read off a live machine. Nothing else publishes a platform name
1174 * containing "AMD", so the short substring costs no precision and buys coverage if AMD ever
1175 * decorates the rest of the string. */
1176typedef struct _gpu_runtime_t
1177{
1178 const char *module; // substring to look for in a crash backtrace
1179 const char *platform; // substring of the CL_PLATFORM_NAME it publishes
1180 const char *conf_suffix; // stable fragment of the per-runtime conf key
1182
1184 { "RusticlOpenCL", "rusticl", "rusticl" }, // issue #1226
1185 { "libMesaOpenCL", "Clover", "clover" }, // Rusticl's predecessor, same exposure
1186 { "amdocl", "AMD", "amd" }, // Sentry 129862572, 141634558
1187 { "libigdfcl", "Intel(R) OpenCL", "intel" }, // Sentry 129978857
1188 { "libigdrcl", "Intel(R) OpenCL", "intel" },
1189 { "intelocl", "Intel(R) OpenCL", "intel" },
1190 { "libnvidia-opencl", "NVIDIA", "nvidia" },
1191 { "nvopencl", "NVIDIA", "nvidia" },
1192 { NULL, NULL, NULL }
1193};
1194
1195/* The runtime publishing `platform_name`, as its conf-key suffix; NULL if we ship no rule for
1196 * it. Case-insensitive, following dt_opencl_check_driver_blacklist(). */
1197static const char *_gpu_runtime_of_platform(const char *platform_name)
1198{
1199 if(IS_NULL_PTR(platform_name)) return NULL;
1200
1201 gchar *haystack = g_ascii_strdown(platform_name, -1);
1202 const char *runtime = NULL;
1203 for(int i = 0; _gpu_runtimes[i].module && IS_NULL_PTR(runtime); i++)
1204 {
1205 gchar *needle = g_ascii_strdown(_gpu_runtimes[i].platform, -1);
1206 if(strstr(haystack, needle)) runtime = _gpu_runtimes[i].conf_suffix;
1207 g_free(needle);
1208 }
1209 g_free(haystack);
1210 return runtime;
1211}
1212
1213static int _gpu_runtime_crash_streak(const char *runtime)
1214{
1215 if(IS_NULL_PTR(runtime)) return 0;
1216 char key[128];
1217 snprintf(key, sizeof(key), "opencl_driver_crash_streak_%s", runtime);
1218 return dt_conf_get_int(key);
1219}
1220
1221static void _gpu_runtime_set_crash_streak(const char *runtime, int value)
1222{
1223 if(IS_NULL_PTR(runtime)) return;
1224 char key[128];
1225 snprintf(key, sizeof(key), "opencl_driver_crash_streak_%s", runtime);
1227}
1228
1229/* Path of the driver-crash record. Built at init, because dt_opencl_note_crash_backtrace()
1230 * runs in a crash handler and cannot allocate; empty until then, and that function no-ops
1231 * while it is. */
1233
1234static void _opencl_driver_crash_marker_path(char *buf, size_t buf_len)
1235{
1236 char cachedir[DT_PATH_MAX] = { 0 };
1237 dt_loc_get_user_cache_dir(cachedir, sizeof(cachedir));
1238 char *marker = g_build_filename(cachedir, "gpu-driver-crash", NULL);
1239 g_strlcpy(buf, marker, buf_len);
1240 g_free(marker);
1241}
1242
1243void dt_opencl_note_crash_backtrace(const char *backtrace, size_t backtrace_len)
1244{
1245 if(_driver_crash_marker[0] == '\0' || IS_NULL_PTR(backtrace) || backtrace_len == 0) return;
1246
1247 /* Record WHICH runtime, not just that one crashed: the next start disables only the devices
1248 * that runtime publishes. Writing the module's own compile-time string keeps this handler
1249 * free of any formatting -- the module is mapped back to its runtime at the next start, off
1250 * the crash path. */
1251 const char *culprit = NULL;
1252 for(int i = 0; _gpu_runtimes[i].module && IS_NULL_PTR(culprit); i++)
1253 if(strstr(backtrace, _gpu_runtimes[i].module)) culprit = _gpu_runtimes[i].module;
1254
1255 if(IS_NULL_PTR(culprit)) return;
1256
1257 /* open/write/close only: this runs on a dying process whose heap may be corrupt, so no
1258 * allocation, no locks, no conf. One line per crash. */
1259 const int fd = g_open(_driver_crash_marker, O_WRONLY | O_CREAT | O_APPEND, 0600);
1260 if(fd < 0) return;
1261 const ssize_t w1 = write(fd, culprit, strlen(culprit));
1262 const ssize_t w2 = write(fd, "\n", 1);
1263 (void)w1; (void)w2;
1264 close(fd);
1265}
1266
1267/* Fold the recorded driver crashes into the per-vendor streaks, consuming the record.
1268 *
1269 * Runs early in dt_opencl_init(), where allocation and conf are safe again. Each line names
1270 * the module that was on the crashing stack; it is mapped back to the runtime that ships it,
1271 * so the streak that grows is that runtime's alone. Lines written by an older build name the
1272 * same modules, so a marker left across an upgrade still folds correctly. */
1274{
1275 if(_driver_crash_marker[0] == '\0') return;
1276
1277 gchar *contents = NULL;
1278 gsize length = 0;
1279 if(!g_file_get_contents(_driver_crash_marker, &contents, &length, NULL)) return;
1280 g_unlink(_driver_crash_marker);
1281
1282 if(!IS_NULL_PTR(contents) && length > 0)
1283 {
1284 gchar **lines = g_strsplit(contents, "\n", -1);
1285 for(int l = 0; lines[l]; l++)
1286 {
1287 if(lines[l][0] == '\0') continue;
1288 for(int i = 0; _gpu_runtimes[i].module; i++)
1289 {
1290 if(strcmp(lines[l], _gpu_runtimes[i].module) != 0) continue;
1291 const char *runtime = _gpu_runtimes[i].conf_suffix;
1293 break;
1294 }
1295 }
1296 g_strfreev(lines);
1297 }
1298 g_free(contents);
1299}
1300
1301void dt_opencl_init(const gboolean exclude_opencl, const gboolean print_statistics)
1302{
1303 if(_opencl) return;
1304 _opencl = (dt_opencl_t *)calloc(1, sizeof(dt_opencl_t));
1305 if(IS_NULL_PTR(_opencl)) return;
1306 dt_opencl_t *cl = _opencl;
1307 dt_pthread_mutex_init(&cl->lock, NULL);
1309 cl->mem_sizes = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
1310 cl->inited = 0;
1311 cl->enabled = 0;
1312 cl->stopped = 0;
1313 cl->error_count = 0;
1314 cl->print_statistics = print_statistics;
1315
1316 /* NOTE: this block sits ABOVE the locale save below on purpose. It can return early, and a
1317 * plain return past that point would skip the finally: block that restores the locale,
1318 * leaving the whole session in "C" -- wrong number and date formatting everywhere, for
1319 * exactly the users already suffering driver crashes. Jumping to finally: instead is not an
1320 * option either: that label frees all_platforms, platform_name and friends, which are
1321 * declared further down, so a goto from here would jump over their initialisers and free
1322 * indeterminate pointers. Returning before anything needs unwinding avoids both. */
1323 /* Fold in any crash that happened inside a GPU driver last time.
1324 *
1325 * A vendor OpenCL runtime that faults on its own thread is not something this code can fix
1326 * -- the stack holds no frame of ours (Sentry 129862572: 169 crashes from 10 users entirely
1327 * inside amdocl64.dll; 129978857: 37 from 17 users, Intel's compiler longjmp-ing out of a
1328 * signal handler into glibc's fortify check). What it CAN do is stop walking into the same
1329 * driver every launch: ~17 and ~2 crashes per user means the same wall every start.
1330 *
1331 * The decision is per DEVICE, further down, once each device's vendor is known -- a machine
1332 * with an Intel iGPU and an NVIDIA dGPU must not lose the NVIDIA because Intel's compiler
1333 * faulted. Nothing is disabled here. */
1336
1337 cl->crc = 5781;
1338 cl->dlocl = NULL;
1339 cl->dev_priority_image = 0;
1340 cl->dev_priority_preview = 0;
1341 cl->dev_priority_export = 0;
1342 cl->dev_priority_thumbnail = 0;
1343 cl->num_detected_devs = 0;
1344 cl->detected_devs = NULL;
1345
1346 // Before the locale save: only finally: restores it.
1347 if(exclude_opencl) return;
1348
1349 // work-around to fix a bug in some AMD OpenCL compilers, which would fail parsing certain numerical
1350 // constants if locale is different from "C".
1351 // we save the current locale, set locale to "C", and restore the previous setting after OpenCL is
1352 // initialized
1353 char *locale = strdup(setlocale(LC_ALL, NULL));
1354 setlocale(LC_ALL, "C");
1355
1356 cl_platform_id *all_platforms = NULL;
1357 cl_uint *all_num_devices = NULL;
1358
1359 char *platform_name = calloc(DT_OPENCL_CBUFFSIZE, sizeof(char));
1360 char *platform_vendor = calloc(DT_OPENCL_CBUFFSIZE, sizeof(char));
1361
1362 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] opencl related configuration options:\n");
1363 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] opencl: %s\n", dt_conf_get_bool("opencl") ? "ON" : "OFF" );
1364 // look for explicit definition of opencl_runtime library in preferences
1365 const char *library = dt_conf_get_string_const("opencl_library");
1366 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] opencl_library: '%s'\n", (strlen(library) == 0) ? "default path" : library);
1367 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] opencl_mandatory_timeout: %d\n",
1368 dt_conf_get_int("opencl_mandatory_timeout"));
1369
1370 // dynamically load opencl runtime
1371 if((cl->dlocl = dt_dlopencl_init(library)) == NULL)
1372 {
1374 "[opencl_init] no working opencl library found. Continue with opencl disabled\n");
1375 goto finally;
1376 }
1377 else
1378 {
1379 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] opencl library '%s' found on your system and loaded\n",
1380 cl->dlocl->library);
1381 }
1382
1383 cl_int err;
1384 all_platforms = malloc(sizeof(cl_platform_id) * DT_OPENCL_MAX_PLATFORMS);
1385 all_num_devices = malloc(sizeof(cl_uint) * DT_OPENCL_MAX_PLATFORMS);
1386 cl_uint num_platforms = DT_OPENCL_MAX_PLATFORMS;
1387 err = (cl->dlocl->symbols->dt_clGetPlatformIDs)(DT_OPENCL_MAX_PLATFORMS, all_platforms, &num_platforms);
1388 if(err != CL_SUCCESS)
1389 {
1390 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] could not get platforms: %i\n", err);
1391 goto finally;
1392 }
1393
1394 if(num_platforms == 0)
1395 {
1396 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] no opencl platform available\n");
1397 goto finally;
1398 }
1399 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] found %d platform%s\n", num_platforms,
1400 num_platforms > 1 ? "s" : "");
1401
1402 for(int n = 0; n < num_platforms; n++)
1403 {
1404 cl_platform_id platform = all_platforms[n];
1405 // get the number of GPU devices available to the platforms
1406 // the other common option is CL_DEVICE_TYPE_GPU/CPU (but the latter doesn't work with the nvidia drivers)
1407 err = (cl->dlocl->symbols->dt_clGetDeviceIDs)(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &(all_num_devices[n]));
1408 if(err != CL_SUCCESS)
1409 {
1410 cl_int errv = (cl->dlocl->symbols->dt_clGetPlatformInfo)(platform, CL_PLATFORM_VENDOR, DT_OPENCL_CBUFFSIZE, platform_vendor, NULL);
1411 cl_int errn = (cl->dlocl->symbols->dt_clGetPlatformInfo)(platform, CL_PLATFORM_NAME, DT_OPENCL_CBUFFSIZE, platform_name, NULL);
1412 if((errn == CL_SUCCESS) && (errv == CL_SUCCESS))
1413 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] no devices found for %s (vendor) - %s (name)\n", platform_vendor, platform_name);
1414 else
1415 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] no devices found for unknown platform\n");
1416
1417 all_num_devices[n] = 0;
1418 }
1419 else
1420 {
1421 char profile[64] = { 0 };
1422 size_t profile_size;
1423 err = (cl->dlocl->symbols->dt_clGetPlatformInfo)(platform, CL_PLATFORM_PROFILE, 64, profile, &profile_size);
1424 if(err != CL_SUCCESS)
1425 {
1426 all_num_devices[n] = 0;
1427 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] could not get profile: %i\n", err);
1428 }
1429 else
1430 {
1431 // fprintf(stderr, "%s\n", profile);
1432 if(strcmp("FULL_PROFILE", profile) != 0)
1433 {
1434 all_num_devices[n] = 0;
1435 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] platform %i is not FULL_PROFILE\n", n);
1436 }
1437 }
1438 }
1439 }
1440
1441 cl_uint num_devices = 0;
1442 for(int n = 0; n < num_platforms; n++) num_devices += all_num_devices[n];
1443
1444 // create the device list
1445 cl_device_id *devices = 0;
1446 if(num_devices)
1447 {
1448 cl->dev = (dt_opencl_device_t *)malloc(sizeof(dt_opencl_device_t) * num_devices);
1449 devices = (cl_device_id *)malloc(sizeof(cl_device_id) * num_devices);
1450 if(IS_NULL_PTR(cl->dev) || IS_NULL_PTR(devices))
1451 {
1452 dt_free(cl->dev);
1453 dt_free(devices);
1454 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] could not allocate memory\n");
1455 goto finally;
1456 }
1457 }
1458
1459 cl_device_id *devs = devices;
1460 for(int n = 0; n < num_platforms; n++)
1461 {
1462 if(all_num_devices[n])
1463 {
1464 cl_platform_id platform = all_platforms[n];
1465 err = (cl->dlocl->symbols->dt_clGetDeviceIDs)(platform, CL_DEVICE_TYPE_ALL, all_num_devices[n], devs,
1466 NULL);
1467 if(err != CL_SUCCESS)
1468 {
1469 num_devices -= all_num_devices[n];
1470 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] could not get devices list: %i\n", err);
1471 }
1472 devs += all_num_devices[n];
1473 }
1474 }
1475 devs = NULL;
1476
1477 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] found %d device%s\n", num_devices, num_devices > 1 ? "s" : "");
1478 if(num_devices == 0)
1479 {
1480 if(devices)
1481 {
1482 dt_free(devices);
1483 }
1484 goto finally;
1485 }
1486
1487 int dev = 0;
1488 for(int k = 0; k < num_devices; k++)
1489 {
1490 const int res = dt_opencl_device_init(cl, dev, devices, k);
1491 if(res != 0)
1492 continue;
1493 // increase dev only if dt_opencl_device_init was successful (res == 0)
1494 ++dev;
1495 }
1496 dt_free(devices);
1497
1498 if(dev > 0)
1499 {
1500 cl->num_devs = dev;
1501 cl->inited = 1;
1502 cl->enabled = dt_conf_get_bool("opencl");
1503 memset(cl->mandatory, 0, sizeof(cl->mandatory));
1504 cl->dev_priority_image = (int *)malloc(sizeof(int) * (dev + 1));
1505 cl->dev_priority_preview = (int *)malloc(sizeof(int) * (dev + 1));
1506 cl->dev_priority_export = (int *)malloc(sizeof(int) * (dev + 1));
1507 cl->dev_priority_thumbnail = (int *)malloc(sizeof(int) * (dev + 1));
1508
1509 // only check successful malloc in debug mode; darktable will crash anyhow sooner or later if mallocs that
1510 // small would fail
1513
1514 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] OpenCL successfully initialized.\n");
1515 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] here are the internal numbers and names of OpenCL devices available to Ansel:\n");
1516 for(int i = 0; i < dev; i++) dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init]\t\t%d\t'%s'\n", i, cl->dev[i].name);
1517 }
1518 else
1519 {
1520 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] no suitable devices found.\n");
1521 }
1522
1523finally:
1524 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] FINALLY: opencl is %sAVAILABLE on this system.\n",
1525 cl->inited ? "" : "NOT ");
1526 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] initial status of opencl enabled flag is %s.\n",
1527 cl->enabled ? "ON" : "OFF");
1528
1529 char checksum[64];
1530 snprintf(checksum, sizeof(checksum), "%u", cl->crc);
1531
1532 if(cl->inited)
1533 {
1534 dt_capabilities_add("opencl");
1544 }
1545
1547
1548 if(!cl->inited)// initialization failed
1549 {
1550 for(int i = 0; cl->dev && i < cl->num_devs; i++) dt_opencl_cleanup_device(cl, i);
1551 }
1552
1553 dt_free(all_num_devices);
1554 dt_free(all_platforms);
1555 dt_free(platform_name);
1556 dt_free(platform_vendor);
1557
1558 if(locale)
1559 {
1560 setlocale(LC_ALL, locale);
1561 dt_free(locale);
1562 }
1563
1564 return;
1565}
1566
1568{
1570 for(int k = 0; k < DT_OPENCL_MAX_KERNELS; k++)
1571 if(cl->dev[i].kernel_used[k]) (cl->dlocl->symbols->dt_clReleaseKernel)(cl->dev[i].kernel[k]);
1572 for(int k = 0; k < DT_OPENCL_MAX_PROGRAMS; k++)
1573 if(cl->dev[i].program_used[k]) (cl->dlocl->symbols->dt_clReleaseProgram)(cl->dev[i].program[k]);
1574 if(!IS_NULL_PTR(cl->dev[i].cmd_queue))
1576 if(!IS_NULL_PTR(cl->dev[i].context))
1578
1580 {
1581 dt_print_nts(DT_DEBUG_OPENCL, " [opencl_summary_statistics] device '%s' (%d): peak memory usage %" G_GSIZE_FORMAT " bytes (%.1f MB)\n",
1582 cl->dev[i].name, i, cl->dev[i].peak_memory, (float)cl->dev[i].peak_memory/(1024*1024));
1583 }
1584
1585 if(cl->print_statistics && cl->dev[i].use_events)
1586 {
1587 if(cl->dev[i].totalevents)
1588 {
1589 dt_print_nts(DT_DEBUG_OPENCL, " [opencl_summary_statistics] device '%s' (%d): %d out of %d events were "
1590 "successful and %d events lost. max event=%d%s\n",
1591 cl->dev[i].name, i, cl->dev[i].totalsuccess, cl->dev[i].totalevents, cl->dev[i].totallost,
1592 cl->dev[i].maxeventslot, (cl->dev[i].maxeventslot > 1024) ? "\n *** Warning, slots > 1024" : "");
1593 }
1594 else
1595 {
1596 dt_print_nts(DT_DEBUG_OPENCL, " [opencl_summary_statistics] device '%s' (%d): NOT utilized\n",
1597 cl->dev[i].name, i);
1598 }
1599 }
1600
1601 if(cl->dev[i].use_events)
1602 {
1604
1605 dt_free(cl->dev[i].eventlist);
1606 dt_free(cl->dev[i].eventtags);
1607 }
1608
1609 dt_free(cl->dev[i].vendor);
1610 dt_free(cl->dev[i].name);
1611 dt_free(cl->dev[i].cname);
1612 dt_free(cl->dev[i].options);
1613 dt_free(cl->dev[i].options_md5);
1614}
1615
1617{
1618 /* Clear the driver-crash streak only if OpenCL actually RAN and we still reached a clean
1619 * shutdown: that is the one thing showing the driver behaving. Surviving with OpenCL
1620 * switched off proves nothing about it, and clearing on that would re-enable it next launch
1621 * and crash again -- halving the crash rate instead of stopping it.
1622 *
1623 * This touches conf, so it must run while conf is still alive -- i.e. BEFORE
1624 * dt_conf_cleanup(), which is why it is not part of dt_opencl_cleanup(): that one runs after
1625 * conf has been saved and freed, where a conf access is both a use-after-free and a write
1626 * that can never be persisted. */
1627 dt_opencl_t *cl = _opencl;
1628 if(IS_NULL_PTR(cl) || !cl->inited || !cl->enabled || IS_NULL_PTR(cl->dev)) return;
1629
1630 /* The counters are per runtime (the same keys _gpu_runtime_crash_streak() gates a device
1631 * on), and only a runtime whose device RAN is cleared: a device this session skipped because
1632 * of its own streak has not shown anything. */
1633 for(int i = 0; i < cl->num_devs; i++)
1634 {
1635 if(cl->dev[i].disabled) continue;
1636 const char *runtime = cl->dev[i].runtime_id;
1637 if(_gpu_runtime_crash_streak(runtime) != 0)
1639 }
1640}
1641
1643{
1644 dt_opencl_t *cl = _opencl;
1645 if(IS_NULL_PTR(cl)) return;
1646 if(cl->inited)
1647 {
1657
1658 for(int i = 0; i < cl->num_devs; i++)
1660
1665 }
1666
1667 if(cl->dlocl)
1668 {
1669 dt_free(cl->dlocl->symbols);
1670 dt_free(cl->dlocl->library);
1671 dt_free(cl->dlocl);
1672 }
1673
1674 for(int i = 0; i < cl->num_detected_devs; i++)
1675 {
1678 }
1680
1681 dt_free(cl->dev);
1682 if(cl->mem_sizes) g_hash_table_destroy(cl->mem_sizes);
1685
1687 _opencl = NULL;
1688}
1689
1690static const char *dt_opencl_get_vendor_by_id(unsigned int id)
1691{
1692 const char *vendor;
1693
1694 switch(id)
1695 {
1697 vendor = "AMD";
1698 break;
1700 vendor = "NVIDIA";
1701 break;
1703 vendor = "INTEL";
1704 break;
1705 default:
1706 vendor = "UNKNOWN";
1707 }
1708
1709 return vendor;
1710}
1711
1712gboolean dt_opencl_finish(const int devid)
1713{
1714 dt_opencl_t *cl = _opencl;
1715 if(!cl->inited || devid < 0) return FALSE;
1716
1717 cl_int err = (cl->dlocl->symbols->dt_clFinish)(cl->dev[devid].cmd_queue);
1718
1719 // take the opportunity to release some event handles, but without printing
1720 // summary statistics
1721 cl_int success = dt_opencl_events_flush(devid, 0);
1722
1723 return (err == CL_SUCCESS && success == CL_COMPLETE);
1724}
1725
1726int dt_opencl_enqueue_barrier(const int devid)
1727{
1728 dt_opencl_t *cl = _opencl;
1729 if(!cl->inited || devid < 0) return -1;
1730 return (cl->dlocl->symbols->dt_clEnqueueBarrier)(cl->dev[devid].cmd_queue);
1731}
1732
1733static int _take_from_list(int *list, int value)
1734{
1735 int result = -1;
1736
1737 while(*list != -1 && *list != value) list++;
1738 result = *list;
1739
1740 while(*list != -1)
1741 {
1742 *list = *(list + 1);
1743 list++;
1744 }
1745
1746 return result;
1747}
1748
1749
1750static int _device_by_cname(const char *name)
1751{
1752 dt_opencl_t *cl = _opencl;
1753 int devs = cl->num_devs;
1754 char tmp[2048] = { 0 };
1755 int result = -1;
1756
1757 _ascii_str_canonical(name, tmp, sizeof(tmp));
1758
1759 for(int i = 0; i < devs; i++)
1760 {
1761 if(!strcmp(tmp, cl->dev[i].cname))
1762 {
1763 result = i;
1764 break;
1765 }
1766 }
1767
1768 return result;
1769}
1770
1771
1772static char *_ascii_str_canonical(const char *in, char *out, int maxlen)
1773{
1774 if(IS_NULL_PTR(out))
1775 {
1776 maxlen = strlen(in) + 1;
1777 out = malloc(maxlen);
1778 if(IS_NULL_PTR(out)) return NULL;
1779 }
1780
1781 int len = 0;
1782
1783 while(*in != '\0' && len < maxlen - 1)
1784 {
1785 int n = strcspn(in, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
1786 in += n;
1787 if(n != 0) continue;
1788 out[len] = tolower(*in);
1789 len++;
1790 in++;
1791 }
1792 out[len] = '\0';
1793
1794 return out;
1795}
1796
1797// parse a single token of priority string and store priorities in priority_list
1798static void dt_opencl_priority_parse(dt_opencl_t *cl, char *configstr, int *priority_list, int *mandatory)
1799{
1800 int devs = cl->num_devs;
1801 int count = 0;
1802 int *full = malloc(sizeof(int) * (devs + 1));
1803 int mnd = 0;
1804
1805 // NULL or empty configstring?
1806 if(IS_NULL_PTR(configstr) || *configstr == '\0')
1807 {
1808 priority_list[0] = -1;
1809 *mandatory = 0;
1810 dt_free(full);
1811 return;
1812 }
1813
1814 // check if user wants us to force-use opencl device(s)
1815 if(configstr[0] == '+')
1816 {
1817 mnd = 1;
1818 configstr++;
1819 }
1820
1821 // first start with a full list of devices to take from
1822 for(int i = 0; i < devs; i++) full[i] = i;
1823 full[devs] = -1;
1824
1825 gchar **tokens = g_strsplit(configstr, ",", 0);
1826 gchar **tokens_ptr = tokens;
1827
1828 while(!IS_NULL_PTR(tokens) && !IS_NULL_PTR(*tokens_ptr) && count < devs + 1 && full[0] != -1)
1829 {
1830 gchar *str = *tokens_ptr;
1831 int not = 0;
1832 int all = 0;
1833
1834 switch(*str)
1835 {
1836 case '*':
1837 all = 1;
1838 break;
1839 case '!':
1840 not = 1;
1841 while(*str == '!') str++;
1842 break;
1843 }
1844
1845 if(all)
1846 {
1847 // copy all remaining device numbers from full to priority list
1848 for(int i = 0; i < devs && full[i] != -1; i++)
1849 {
1850 priority_list[count] = full[i];
1851 count++;
1852 }
1853 full[0] = -1; // mark full list as empty
1854 }
1855 else if(*str != '\0')
1856 {
1857 char *endptr = NULL;
1858
1859 // first check if str corresponds to an existing canonical device name
1860 long number = _device_by_cname(str);
1861
1862 // if not try to convert string into decimal device number
1863 if(number < 0) number = strtol(str, &endptr, 10);
1864
1865 // still not found or negative number given? set number to -1
1866 if(number < 0 || (number == 0 && endptr == str)) number = -1;
1867
1868 // try to take number out of remaining device list
1869 int dev_number = _take_from_list(full, number);
1870
1871 if(!not&&dev_number != -1)
1872 {
1873 priority_list[count] = dev_number;
1874 count++;
1875 }
1876 }
1877
1878 tokens_ptr++;
1879 }
1880
1881 g_strfreev(tokens);
1882
1883 // terminate priority list with -1
1884 while(count < devs + 1) priority_list[count++] = -1;
1885
1886 // opencl use can only be mandatory if at least one opencl device is given
1887 *mandatory = (priority_list[0] != -1) ? mnd : 0;
1888
1889 dt_free(full);
1890}
1891
1892// set device priorities according to config string
1894{
1895 dt_opencl_t *cl = _opencl;
1896 if(!cl->inited) return;
1897
1898 // Priority parsing iterates over the list of available devices.
1899 // If !cl->inited, that means we have no available device, so empty list.
1900 // Exit early of face a segfault
1901 char *darkroom = dt_conf_get_string("opencl_devid_darkroom");
1902 char *preview = dt_conf_get_string("opencl_devid_preview");
1903 char *export = dt_conf_get_string("opencl_devid_export");
1904 char *thumbnail = dt_conf_get_string("opencl_devid_thumbnail");
1905
1906 dt_opencl_priority_parse(cl, darkroom, cl->dev_priority_image, &cl->mandatory[0]);
1908 dt_opencl_priority_parse(cl, export, cl->dev_priority_export, &cl->mandatory[2]);
1909 dt_opencl_priority_parse(cl, thumbnail, cl->dev_priority_thumbnail, &cl->mandatory[3]);
1910
1911 dt_free(darkroom);
1913 dt_free(export);
1914 dt_free(thumbnail);
1915
1916 dt_print_nts(DT_DEBUG_OPENCL, "[dt_opencl_update_priorities] these are your device priorities:\n");
1917 dt_print_nts(DT_DEBUG_OPENCL, "[dt_opencl_update_priorities] \tid |\t\tIMAGE\tPREVIEW\tEXPORT\tTHUMBS\n");
1918 for(int i = 0; i < cl->num_devs; i++)
1919 dt_print_nts(DT_DEBUG_OPENCL, "[dt_opencl_update_priorities]\t%i |\t\t%d\t%d\t%d\t%d\n",
1920 i, cl->dev_priority_image[i],
1922 dt_print_nts(DT_DEBUG_OPENCL, "[dt_opencl_update_priorities] show if opencl use is mandatory for a given pixelpipe:\n");
1923 dt_print_nts(DT_DEBUG_OPENCL, "[dt_opencl_update_priorities] \t\tIMAGE\tPREVIEW\tEXPORT\tTHUMBS\n");
1924 dt_print_nts(DT_DEBUG_OPENCL, "[dt_opencl_update_priorities]\t\t%s\t%s\t%s\t%s\n", cl->mandatory[0] ? "yes" : "no",
1925 cl->mandatory[1] ? "yes" : "no", cl->mandatory[2] ? "yes" : "no", cl->mandatory[3] ? "yes" : "no");
1926}
1927
1929{
1930 dt_opencl_t *cl = _opencl;
1931 if(!cl->inited) return -1;
1932
1933
1935
1936 size_t prio_size = sizeof(int) * (cl->num_devs + 1);
1937 int *priority = (int *)malloc(prio_size);
1938 int mandatory;
1939
1940 switch(pipetype)
1941 {
1943 memcpy(priority, cl->dev_priority_image, prio_size);
1944 mandatory = cl->mandatory[0];
1945 break;
1947 memcpy(priority, cl->dev_priority_preview, prio_size);
1948 mandatory = cl->mandatory[1];
1949 break;
1951 memcpy(priority, cl->dev_priority_export, prio_size);
1952 mandatory = cl->mandatory[2];
1953 break;
1955 memcpy(priority, cl->dev_priority_thumbnail, prio_size);
1956 mandatory = cl->mandatory[3];
1957 break;
1958 default:
1959 dt_free(priority);
1960 mandatory = 0;
1961 }
1962
1964
1965 if(priority)
1966 {
1967 const int usec = 5000;
1968 const int nloop = MAX(0, dt_conf_get_int("opencl_mandatory_timeout"));
1969
1970 // check for free opencl device repeatedly if mandatory is TRUE, else give up after first try
1971 for(int n = 0; n < nloop; n++)
1972 {
1973 const int *prio = priority;
1974
1975 while(*prio != -1)
1976 {
1977 if(!dt_pthread_mutex_BAD_trylock(&cl->dev[*prio].lock))
1978 {
1979 int devid = *prio;
1980 dt_free(priority);
1981 return devid;
1982 }
1983 prio++;
1984 }
1985
1986 if(!mandatory)
1987 {
1988 dt_free(priority);
1989 return -1;
1990 }
1991
1992 dt_iop_nap(usec);
1993 }
1994 dt_print(DT_DEBUG_OPENCL, "[opencl_lock_device] reached opencl_mandatory_timeout trying to lock mandatory device, fallback to CPU\n");
1995 }
1996 else
1997 {
1998 // only a fallback if a new pipe type would be added and we forget to take care of it in opencl.c
1999 for(int try_dev = 0; try_dev < cl->num_devs; try_dev++)
2000 {
2001 // get first currently unused processor
2002 if(!dt_pthread_mutex_BAD_trylock(&cl->dev[try_dev].lock)) return try_dev;
2003 }
2004 }
2005
2006 dt_free(priority);
2007
2008 // no free GPU :(
2009 // use CPU processing, if no free device:
2010 return -1;
2011}
2012
2013void dt_opencl_release_device(const int devid)
2014{
2015 dt_opencl_t *cl = _opencl;
2016 if(!cl->inited) return;
2017 if(devid < 0 || devid >= cl->num_devs) return;
2019}
2020
2021/* The same per-device lock dt_opencl_reserve_device_for_pipe() takes, for callers that
2022 * already know which device they need -- typically to touch that device's cl_mem or its
2023 * eventlist, which races the pipe using it otherwise. */
2025{
2026 dt_opencl_t *cl = _opencl;
2027 if(!cl->inited) return;
2028 if(devid < 0 || devid >= cl->num_devs) return;
2029 // paired with dt_opencl_release_device()'s dt_pthread_mutex_BAD_unlock(): the lock is held
2030 // across this function boundary and released by a different function, which the analyzer
2031 // can't model -- same reason dt_opencl_try_reserve_device_by_id() already uses the BAD variant.
2032 dt_pthread_mutex_BAD_lock(&cl->dev[devid].lock);
2033}
2034
2036{
2037 dt_opencl_t *cl = _opencl;
2038 if(!cl->inited) return 1;
2039 if(devid < 0 || devid >= cl->num_devs) return 1;
2040 return dt_pthread_mutex_BAD_trylock(&cl->dev[devid].lock);
2041}
2042
2044{
2045 dt_opencl_t *cl = _opencl;
2046 if(!cl || !cl->inited) return 0;
2047 return cl->num_devs;
2048}
2049
2050const char *dt_opencl_get_device_name(const int devid)
2051{
2052 dt_opencl_t *cl = _opencl;
2053 if(!cl || !cl->inited || IS_NULL_PTR(cl->dev)) return NULL;
2054 if(devid < 0 || devid >= cl->num_devs) return NULL;
2055 return cl->dev[devid].name;
2056}
2057
2058gboolean dt_opencl_get_device_max_image_size(const int devid, int *width, int *height)
2059{
2060 dt_opencl_t *cl = _opencl;
2061 if(!cl || !cl->inited || IS_NULL_PTR(cl->dev)) return FALSE;
2062 if(devid < 0 || devid >= cl->num_devs) return FALSE;
2063 if(width) *width = cl->dev[devid].max_image_width;
2064 if(height) *height = cl->dev[devid].max_image_height;
2065 return TRUE;
2066}
2067
2069{
2070 dt_opencl_t *cl = _opencl;
2071 if(!cl || !cl->inited || IS_NULL_PTR(cl->dev)) return 0;
2072 if(devid < 0 || devid >= cl->num_devs) return 0;
2073 return (size_t)cl->dev[devid].max_global_mem;
2074}
2075
2077{
2078 dt_opencl_t *cl = _opencl;
2079 if(!cl || !cl->inited || IS_NULL_PTR(cl->dev)) return 0;
2080 if(devid < 0 || devid >= cl->num_devs) return 0;
2081 return cl->dev[devid].memory_in_use;
2082}
2083
2084size_t dt_opencl_get_device_headroom(const int devid)
2085{
2086 dt_opencl_t *cl = _opencl;
2087 if(!cl || !cl->inited || IS_NULL_PTR(cl->dev)) return 0;
2088 if(devid < 0 || devid >= cl->num_devs) return 0;
2089 // In MiB, as dt_opencl_check_tuning() reads it.
2090 return cl->dev[devid].forced_headroom * 1024 * 1024;
2091}
2092
2094{
2095 dt_opencl_t *cl = _opencl;
2096 if(!cl) return 2;
2097
2098 cl->error_count++;
2099 if(cl->error_count < DT_OPENCL_MAX_ERRORS) return 1;
2100
2101 /* Too many failures: OpenCL is finished for this session. */
2102 cl->stopped = 1;
2103 dt_capabilities_remove("opencl");
2104 return 2;
2105}
2106
2107static FILE *fopen_stat(const char *filename, struct stat *st)
2108{
2109 FILE *f = g_fopen(filename, "rb");
2110 if(IS_NULL_PTR(f))
2111 {
2112 dt_print(DT_DEBUG_OPENCL, "[opencl_fopen_stat] could not open file `%s'!\n", filename);
2113 return NULL;
2114 }
2115 int fd = fileno(f);
2116 if(fstat(fd, st) < 0)
2117 {
2118 dt_print(DT_DEBUG_OPENCL, "[opencl_fopen_stat] could not stat file `%s'!\n", filename);
2119 fclose(f); // the open succeeded; only the stat failed, and the handle is still ours
2120 return NULL;
2121 }
2122 return f;
2123}
2124
2125
2126void dt_opencl_md5sum(const char **files, char **md5sums)
2127{
2128 char kerneldir[DT_PATH_MAX] = { 0 };
2129 char filename[DT_PATH_MAX] = { 0 };
2130 dt_loc_get_kerneldir(kerneldir, sizeof(kerneldir));
2131
2132 for(int n = 0; n < DT_OPENCL_MAX_INCLUDES; n++, files++, md5sums++)
2133 {
2134 if(!*files)
2135 {
2136 *md5sums = NULL;
2137 continue;
2138 }
2139
2140 dt_concat_path_file(filename, kerneldir, *files);
2141
2142 struct stat filestat;
2143 FILE *f = fopen_stat(filename, &filestat);
2144
2145 if(IS_NULL_PTR(f))
2146 {
2147 dt_print(DT_DEBUG_OPENCL, "[opencl_md5sums] could not open file `%s'!\n", filename);
2148 *md5sums = NULL;
2149 continue;
2150 }
2151
2152 size_t filesize = filestat.st_size;
2153 char *file = (char *)malloc(filesize);
2154
2155 if(IS_NULL_PTR(file))
2156 {
2157 dt_print(DT_DEBUG_OPENCL, "[opencl_md5sums] could not allocate buffer for file `%s'!\n", filename);
2158 *md5sums = NULL;
2159 fclose(f);
2160 continue;
2161 }
2162
2163 size_t rd = fread(file, sizeof(char), filesize, f);
2164 fclose(f);
2165
2166 if(rd != filesize)
2167 {
2168 dt_free(file);
2169 dt_print(DT_DEBUG_OPENCL, "[opencl_md5sums] could not read all of file `%s'!\n", filename);
2170 *md5sums = NULL;
2171 continue;
2172 }
2173
2174 *md5sums = g_compute_checksum_for_data(G_CHECKSUM_MD5, (guchar *)file, filesize);
2175
2176 dt_free(file);
2177 }
2178}
2179
2180int dt_opencl_load_program(const int dev, const int prog, const char *filename, const char *binname,
2181 const char *cachedir, char *md5sum, char **includemd5, int *loaded_cached)
2182{
2183 cl_int err;
2184 dt_opencl_t *cl = _opencl;
2185
2186 struct stat filestat, cachedstat;
2187 *loaded_cached = 0;
2188
2189 if(prog < 0 || prog >= DT_OPENCL_MAX_PROGRAMS)
2190 {
2191 dt_print(DT_DEBUG_OPENCL, "[opencl_load_source] invalid program number `%d' of file `%s'!\n", prog,
2192 filename);
2193 return 0;
2194 }
2195
2196 if(cl->dev[dev].program_used[prog])
2197 {
2199 "[opencl_load_source] program number `%d' already in use when loading file `%s'!\n", prog,
2200 filename);
2201 return 0;
2202 }
2203
2204 FILE *f = fopen_stat(filename, &filestat);
2205 if(IS_NULL_PTR(f)) return 0;
2206
2207 size_t filesize = filestat.st_size;
2208 char *file = (char *)malloc(filesize + 2048);
2209 size_t rd = fread(file, sizeof(char), filesize, f);
2210 fclose(f);
2211 if(rd != filesize)
2212 {
2213 dt_free(file);
2214 dt_print(DT_DEBUG_OPENCL, "[opencl_load_source] could not read all of file `%s'!\n", filename);
2215 return 0;
2216 }
2217
2218 char *start = file + filesize;
2219 char *end = start + 2048;
2220 size_t len;
2221
2222 cl_device_id devid = cl->dev[dev].devid;
2223 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DRIVER_VERSION, end - start, start, &len);
2224 start += len;
2225
2226 cl_platform_id platform;
2227 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &platform, NULL);
2228
2229 (cl->dlocl->symbols->dt_clGetPlatformInfo)(platform, CL_PLATFORM_VERSION, end - start, start, &len);
2230 start += len;
2231
2232 const char *options_md5 = cl->dev[dev].options_md5 ? cl->dev[dev].options_md5 : cl->dev[dev].options;
2233 len = g_strlcpy(start, options_md5, end - start);
2234 start += len;
2235
2236 /* make sure that the md5sums of all the includes are applied as well */
2237 for(int n = 0; n < DT_OPENCL_MAX_INCLUDES; n++)
2238 {
2239 if(!includemd5[n]) continue;
2240 len = g_strlcpy(start, includemd5[n], end - start);
2241 start += len;
2242 }
2243
2244 char *source_md5 = g_compute_checksum_for_data(G_CHECKSUM_MD5, (guchar *)file, start - file);
2245 g_strlcpy(md5sum, source_md5, 33);
2246 dt_free(source_md5);
2247
2248 file[filesize] = '\0';
2249
2250 char linkedfile[DT_PATH_MAX] = { 0 };
2251 ssize_t linkedfile_len = 0;
2252
2253#if defined(_WIN32)
2254 // No symlinks on Windows
2255 // Have to figure out the name using the filename + md5sum
2256 char dup[DT_PATH_MAX] = { 0 };
2257 snprintf(dup, sizeof(dup), "%s.%s", binname, md5sum);
2258 FILE *cached = fopen_stat(dup, &cachedstat);
2259 g_strlcpy(linkedfile, md5sum, sizeof(linkedfile));
2260 linkedfile_len = strlen(md5sum);
2261#else
2262 FILE *cached = fopen_stat(binname, &cachedstat);
2263#endif
2264
2265 if(cached)
2266 {
2267#if !defined(_WIN32)
2268 linkedfile_len = readlink(binname, linkedfile, sizeof(linkedfile) - 1);
2269#endif // !defined(_WIN32)
2270 if(linkedfile_len > 0)
2271 {
2272 linkedfile[linkedfile_len] = '\0';
2273
2274 if(strncmp(linkedfile, md5sum, 33) == 0)
2275 {
2276 // md5sum matches, load cached binary
2277 size_t cached_filesize = cachedstat.st_size;
2278
2279 unsigned char *cached_content = (unsigned char *)malloc(cached_filesize + 1);
2280 if(IS_NULL_PTR(cached_content))
2281 {
2283 "[opencl_load_program] could not allocate %zu bytes for cached binary '%s'!\n",
2284 cached_filesize + 1, binname);
2285 fclose(cached);
2286 return 0;
2287 }
2288 rd = fread(cached_content, sizeof(char), cached_filesize, cached);
2289 if(rd != cached_filesize)
2290 {
2291 dt_print(DT_DEBUG_OPENCL, "[opencl_load_program] could not read all of file '%s' MD5: %s!\n", binname, md5sum);
2292 }
2293 else
2294 {
2295 cl->dev[dev].program[prog] = (cl->dlocl->symbols->dt_clCreateProgramWithBinary)(
2296 cl->dev[dev].context, 1, &(cl->dev[dev].devid), &cached_filesize,
2297 (const unsigned char **)&cached_content, NULL, &err);
2298 if(err != CL_SUCCESS)
2299 {
2301 "[opencl_load_program] could not load cached binary program from file '%s' MD5: '%s'! (%i)\n",
2302 binname, md5sum, err);
2303 }
2304 else
2305 {
2306 cl->dev[dev].program_used[prog] = 1;
2307 *loaded_cached = 1;
2308 }
2309 }
2310 dt_free(cached_content);
2311 }
2312 }
2313 fclose(cached);
2314 }
2315
2316
2317 if(*loaded_cached == 0)
2318 {
2319 // if loading cached was unsuccessful for whatever reason,
2320 // try to remove cached binary & link
2321#if !defined(_WIN32)
2322 if(linkedfile_len > 0)
2323 {
2324 char link_dest[DT_PATH_MAX] = { 0 };
2325 dt_concat_path_file(link_dest, cachedir, linkedfile);
2326 g_unlink(link_dest);
2327 }
2328 g_unlink(binname);
2329#else
2330 // delete the file which contains the MD5 name
2331 g_unlink(dup);
2332#endif
2333
2335 "[opencl_load_program] could not load cached binary program, trying to compile source\n");
2336
2337 cl->dev[dev].program[prog] = (cl->dlocl->symbols->dt_clCreateProgramWithSource)(
2338 cl->dev[dev].context, 1, (const char **)&file, &filesize, &err);
2339 dt_free(file);
2340 if((err != CL_SUCCESS) || (cl->dev[dev].program[prog] == NULL))
2341 {
2342 dt_print(DT_DEBUG_OPENCL, "[opencl_load_source] could not create program from file `%s'! (%i)\n",
2343 filename, err);
2344 return 0;
2345 }
2346 else
2347 {
2348 cl->dev[dev].program_used[prog] = 1;
2349 }
2350 }
2351 else
2352 {
2353 dt_free(file);
2354 dt_vprint(DT_DEBUG_OPENCL, "[opencl_load_program] loaded cached binary program from file '%s' MD5: '%s' \n", binname, md5sum);
2355 }
2356
2357 dt_vprint(DT_DEBUG_OPENCL, "[opencl_load_program] successfully loaded program from '%s' MD5: '%s'\n", filename, md5sum);
2358
2359 return 1;
2360}
2361
2362int dt_opencl_build_program(const int dev, const int prog, const char *binname, const char *cachedir,
2363 char *md5sum, int loaded_cached)
2364{
2365 if(prog < 0 || prog >= DT_OPENCL_MAX_PROGRAMS) return -1;
2366 dt_opencl_t *cl = _opencl;
2367 cl_program program = cl->dev[dev].program[prog];
2368 cl_int err = (cl->dlocl->symbols->dt_clBuildProgram)(program, 1, &(cl->dev[dev].devid), cl->dev[dev].options, 0, 0);
2369
2370 if(err != CL_SUCCESS)
2371 dt_print(DT_DEBUG_OPENCL, "[opencl_build_program] could not build program: %i\n", err);
2372 else
2373 dt_vprint(DT_DEBUG_OPENCL, "[opencl_build_program] successfully built program\n");
2374
2375 cl_build_status build_status;
2376 (cl->dlocl->symbols->dt_clGetProgramBuildInfo)(program, cl->dev[dev].devid, CL_PROGRAM_BUILD_STATUS,
2377 sizeof(cl_build_status), &build_status, NULL);
2378 dt_vprint(DT_DEBUG_OPENCL, "[opencl_build_program] BUILD STATUS: %d\n", build_status);
2379
2380 char *build_log;
2381 size_t ret_val_size;
2382 (cl->dlocl->symbols->dt_clGetProgramBuildInfo)(program, cl->dev[dev].devid, CL_PROGRAM_BUILD_LOG, 0, NULL,
2383 &ret_val_size);
2384 if(ret_val_size != SIZE_MAX)
2385 {
2386 build_log = (char *)malloc(sizeof(char) * (ret_val_size + 1));
2387 if(build_log)
2388 {
2389 (cl->dlocl->symbols->dt_clGetProgramBuildInfo)(program, cl->dev[dev].devid, CL_PROGRAM_BUILD_LOG,
2390 ret_val_size, build_log, NULL);
2391
2392 build_log[ret_val_size] = '\0';
2393
2394 dt_vprint(DT_DEBUG_OPENCL, "BUILD LOG:\n");
2395 dt_vprint(DT_DEBUG_OPENCL, "%s\n", build_log);
2396
2397 dt_free(build_log);
2398 }
2399 }
2400
2401 if(err != CL_SUCCESS)
2402 return err;
2403 else
2404 {
2405 if(!loaded_cached)
2406 {
2407 dt_vprint(DT_DEBUG_OPENCL, "[opencl_build_program] saving binary\n");
2408
2409 cl_uint numdev = 0;
2410 err = (cl->dlocl->symbols->dt_clGetProgramInfo)(program, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint),
2411 &numdev, NULL);
2412 if(err != CL_SUCCESS)
2413 {
2414 dt_print(DT_DEBUG_OPENCL, "[opencl_build_program] CL_PROGRAM_NUM_DEVICES failed: %i\n", err);
2415 return CL_SUCCESS;
2416 }
2417
2418 cl_device_id *devices = malloc(sizeof(cl_device_id) * numdev);
2419 err = (cl->dlocl->symbols->dt_clGetProgramInfo)(program, CL_PROGRAM_DEVICES,
2420 sizeof(cl_device_id) * numdev, devices, NULL);
2421 if(err != CL_SUCCESS)
2422 {
2423 dt_print(DT_DEBUG_OPENCL, "[opencl_build_program] CL_PROGRAM_DEVICES failed: %i\n", err);
2424 dt_free(devices);
2425 return CL_SUCCESS;
2426 }
2427
2428 size_t *binary_sizes = malloc(sizeof(size_t) * numdev);
2429 err = (cl->dlocl->symbols->dt_clGetProgramInfo)(program, CL_PROGRAM_BINARY_SIZES,
2430 sizeof(size_t) * numdev, binary_sizes, NULL);
2431 if(err != CL_SUCCESS)
2432 {
2433 dt_print(DT_DEBUG_OPENCL, "[opencl_build_program] CL_PROGRAM_BINARY_SIZES failed: %i\n", err);
2434 dt_free(binary_sizes);
2435 dt_free(devices);
2436 return CL_SUCCESS;
2437 }
2438
2439 unsigned char **binaries = malloc(sizeof(unsigned char *) * numdev);
2440 for(int i = 0; i < numdev; i++) binaries[i] = (unsigned char *)malloc(binary_sizes[i]);
2441 err = (cl->dlocl->symbols->dt_clGetProgramInfo)(program, CL_PROGRAM_BINARIES,
2442 sizeof(unsigned char *) * numdev, binaries, NULL);
2443 if(err != CL_SUCCESS)
2444 {
2445 dt_print(DT_DEBUG_OPENCL, "[opencl_build_program] CL_PROGRAM_BINARIES failed: %i\n", err);
2446 goto ret;
2447 }
2448
2449 for(int i = 0; i < numdev; i++)
2450 if(cl->dev[dev].devid == devices[i])
2451 {
2452 // save opencl compiled binary as md5sum-named file
2453 char link_dest[DT_PATH_MAX] = { 0 };
2454 snprintf(link_dest, sizeof(link_dest), "%s" G_DIR_SEPARATOR_S "%s", cachedir, md5sum);
2455 FILE *f = g_fopen(link_dest, "wb");
2456 if(IS_NULL_PTR(f)) goto ret;
2457 const size_t bytes_written = fwrite(binaries[i], sizeof(char), binary_sizes[i], f);
2458 fclose(f);
2459 if(bytes_written != binary_sizes[i]) goto ret;
2460
2461 /* Name the binary after the program (e.g. basic.cl.bin), pointing at the
2462 * md5sum-named file we just wrote.
2463 *
2464 * This used to chdir() into cachedir so it could name the link by its basename
2465 * alone, and chdir() back afterwards. Two things were wrong with that. The
2466 * working directory is process-global state, and this runs on whichever thread
2467 * is building kernels while the rest of the application is live; and the
2468 * restoring chdir() sat AFTER two `goto ret' paths, so any failure in between
2469 * left the whole process parked in the kernel cache directory for the rest of
2470 * the session. Neither is needed: only the LINK path has to be absolute, while
2471 * the symlink target stays relative -- which is what the chdir was buying. */
2472 gchar *bname = g_path_get_basename(binname);
2473 char link_name[DT_PATH_MAX] = { 0 };
2474 snprintf(link_name, sizeof(link_name), "%s" G_DIR_SEPARATOR_S "%s", cachedir, bname);
2475#if defined(_WIN32)
2476 /* CreateSymbolicLink() needs admin privileges on Windows, which we neither
2477 * want nor need, so the cached binary is simply renamed into place. */
2478 char final_name[DT_PATH_MAX] = { 0 };
2479 snprintf(final_name, sizeof(final_name), "%s.%s", link_name, md5sum);
2480 const int link_failed = (g_rename(link_dest, final_name) != 0);
2481#else
2482 /* Relative target, absolute link path: the link keeps working if the cache
2483 * directory is ever moved, and we never touch the working directory. */
2484 g_unlink(link_name);
2485 const int link_failed = (symlink(md5sum, link_name) != 0);
2486#endif
2487 g_free(bname);
2488 if(link_failed)
2489 {
2490 dt_print(DT_DEBUG_OPENCL, "[opencl_build_program] could not name the cached binary `%s': %s\n",
2491 link_name, strerror(errno));
2492 goto ret;
2493 }
2494 }
2495
2496 ret:
2497 for(int i = 0; i < numdev; i++) dt_free(binaries[i]);
2498 dt_free(binaries);
2499 dt_free(binary_sizes);
2500 dt_free(devices);
2501 }
2502 return CL_SUCCESS;
2503 }
2504}
2505
2506int dt_opencl_create_kernel(const int prog, const char *name)
2507{
2508 dt_opencl_t *cl = _opencl;
2509 if(!cl->inited) return -1;
2510 if(prog < 0 || prog >= DT_OPENCL_MAX_PROGRAMS) return -1;
2512 int k = 0;
2513 for(int dev = 0; dev < cl->num_devs; dev++)
2514 {
2515 cl_int err;
2516 for(; k < DT_OPENCL_MAX_KERNELS; k++)
2517 if(!cl->dev[dev].kernel_used[k])
2518 {
2519 cl->dev[dev].kernel_used[k] = 1;
2520 cl->dev[dev].kernel[k]
2521 = (cl->dlocl->symbols->dt_clCreateKernel)(cl->dev[dev].program[prog], name, &err);
2522 if(err != CL_SUCCESS)
2523 {
2524 dt_print(DT_DEBUG_OPENCL, "[opencl_create_kernel] could not create kernel `%s'! (%i)\n", name, err);
2525 cl->dev[dev].kernel_used[k] = 0;
2526 goto error;
2527 }
2528 else
2529 break;
2530 }
2532 {
2533 dt_vprint(DT_DEBUG_OPENCL, "[opencl_create_kernel] successfully loaded kernel `%s' (%d) for device %d\n",
2534 name, k, dev);
2535 }
2536 else
2537 {
2538 dt_print(DT_DEBUG_OPENCL, "[opencl_create_kernel] too many kernels! can't create kernel `%s'\n", name);
2539 goto error;
2540 }
2541 }
2543 return k;
2544error:
2546 return -1;
2547}
2548
2550{
2551 dt_opencl_t *cl = _opencl;
2552 if(!cl->inited) return;
2553 if(kernel < 0 || kernel >= DT_OPENCL_MAX_KERNELS) return;
2555 for(int dev = 0; dev < cl->num_devs; dev++)
2556 {
2557 cl->dev[dev].kernel_used[kernel] = 0;
2558 (cl->dlocl->symbols->dt_clReleaseKernel)(cl->dev[dev].kernel[kernel]);
2559 }
2561}
2562
2563int dt_opencl_get_max_work_item_sizes(const int dev, size_t *sizes)
2564{
2565 dt_opencl_t *cl = _opencl;
2566 if(!cl->inited || dev < 0) return -1;
2567 return (cl->dlocl->symbols->dt_clGetDeviceInfo)(cl->dev[dev].devid, CL_DEVICE_MAX_WORK_ITEM_SIZES,
2568 sizeof(size_t) * 3, sizes, NULL);
2569}
2570
2571int dt_opencl_get_work_group_limits(const int dev, size_t *sizes, size_t *workgroupsize,
2572 unsigned long *localmemsize)
2573{
2574 dt_opencl_t *cl = _opencl;
2575 if(!cl->inited || dev < 0) return -1;
2576 cl_ulong lmemsize;
2577 cl_int err = (cl->dlocl->symbols->dt_clGetDeviceInfo)(cl->dev[dev].devid, CL_DEVICE_LOCAL_MEM_SIZE,
2578 sizeof(cl_ulong), &lmemsize, NULL);
2579 if(err != CL_SUCCESS) return err;
2580
2581 *localmemsize = lmemsize;
2582
2583 err = (cl->dlocl->symbols->dt_clGetDeviceInfo)(cl->dev[dev].devid, CL_DEVICE_MAX_WORK_GROUP_SIZE,
2584 sizeof(size_t), workgroupsize, NULL);
2585 if(err != CL_SUCCESS) return err;
2586
2587 return dt_opencl_get_max_work_item_sizes(dev, sizes);
2588}
2589
2590
2591int dt_opencl_get_kernel_work_group_size(const int dev, const int kernel, size_t *kernelworkgroupsize)
2592{
2593 dt_opencl_t *cl = _opencl;
2594 if(!cl->inited || dev < 0) return -1;
2595 if(kernel < 0 || kernel >= DT_OPENCL_MAX_KERNELS) return -1;
2596
2597 return (cl->dlocl->symbols->dt_clGetKernelWorkGroupInfo)(cl->dev[dev].kernel[kernel], cl->dev[dev].devid,
2598 CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t),
2599 kernelworkgroupsize, NULL);
2600}
2601
2602
2603int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size,
2604 const void *arg)
2605{
2606 dt_opencl_t *cl = _opencl;
2607 if(!cl->inited || dev < 0) return -1;
2608 if(kernel < 0 || kernel >= DT_OPENCL_MAX_KERNELS) return -1;
2609 return (cl->dlocl->symbols->dt_clSetKernelArg)(cl->dev[dev].kernel[kernel], num, size, arg);
2610}
2611
2612int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
2613{
2614 return dt_opencl_enqueue_kernel_2d_with_local(dev, kernel, sizes, NULL);
2615}
2616
2617
2618int dt_opencl_enqueue_kernel_2d_with_local(const int dev, const int kernel, const size_t *sizes,
2619 const size_t *local)
2620{
2621 dt_opencl_t *cl = _opencl;
2622 if(!cl->inited || dev < 0) return -1;
2623 if(kernel < 0 || kernel >= DT_OPENCL_MAX_KERNELS) return -1;
2624
2625 char buf[256];
2626 buf[0] = '\0';
2628 (cl->dlocl->symbols->dt_clGetKernelInfo)(cl->dev[dev].kernel[kernel], CL_KERNEL_FUNCTION_NAME, 256, buf, NULL);
2629 cl_event *eventp = dt_opencl_events_get_slot(dev, buf);
2630 cl_int err = (cl->dlocl->symbols->dt_clEnqueueNDRangeKernel)(cl->dev[dev].cmd_queue, cl->dev[dev].kernel[kernel],
2631 2, NULL, sizes, local, 0, NULL, eventp);
2632
2633 if(err != CL_SUCCESS)
2634 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_enqueue_kernel_2d_with_local] kernel %i (%s) on device %d: %i\n", kernel, buf, dev, err);
2635
2636 return err;
2637}
2638
2639int dt_opencl_copy_device_to_host(const int devid, void *host, void *device, const int width,
2640 const int height, const int bpp)
2641{
2642 return dt_opencl_read_host_from_device(devid, host, device, width, height, bpp);
2643}
2644
2645int dt_opencl_read_host_from_device(const int devid, void *host, void *device, const int width,
2646 const int height, const int bpp)
2647{
2648 return dt_opencl_read_host_from_device_rowpitch(devid, host, device, width, height, bpp * width);
2649}
2650
2651int dt_opencl_read_host_from_device_rowpitch(const int devid, void *host, void *device, const int width,
2652 const int height, const int rowpitch)
2653{
2654 if(!(_opencl && _opencl->inited) || devid < 0) return -1;
2655 const size_t origin[] = { 0, 0, 0 };
2656 const size_t region[] = { width, height, 1 };
2657 // blocking.
2658 return dt_opencl_read_host_from_device_raw(devid, host, device, origin, region, rowpitch, CL_TRUE);
2659}
2660
2661int dt_opencl_read_host_from_device_non_blocking(const int devid, void *host, void *device, const int width,
2662 const int height, const int bpp)
2663{
2665 bpp * width);
2666}
2667
2668int dt_opencl_read_host_from_device_rowpitch_non_blocking(const int devid, void *host, void *device,
2669 const int width, const int height,
2670 const int rowpitch)
2671{
2672 if(!(_opencl && _opencl->inited) || devid < 0) return -1;
2673 const size_t origin[] = { 0, 0, 0 };
2674 const size_t region[] = { width, height, 1 };
2675 // non-blocking.
2676 return dt_opencl_read_host_from_device_raw(devid, host, device, origin, region, rowpitch, CL_FALSE);
2677}
2678
2679
2680int dt_opencl_read_host_from_device_raw(const int devid, void *host, void *device, const size_t *origin,
2681 const size_t *region, const int rowpitch, const int blocking)
2682{
2683 if(!(_opencl && _opencl->inited)) return -1;
2684
2685 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Read Image (from device to host)]");
2686
2688 device, blocking ? CL_TRUE : CL_FALSE, origin, region, rowpitch,
2689 0, host, 0, NULL, eventp);
2690}
2691
2692int dt_opencl_write_host_to_device(const int devid, void *host, void *device, const int width,
2693 const int height, const int bpp)
2694{
2695 return dt_opencl_write_host_to_device_rowpitch(devid, host, device, width, height, width * bpp);
2696}
2697
2698int dt_opencl_write_host_to_device_rowpitch(const int devid, void *host, void *device, const int width,
2699 const int height, const int rowpitch)
2700{
2701 if(!(_opencl && _opencl->inited) || devid < 0) return -1;
2702 const size_t origin[] = { 0, 0, 0 };
2703 const size_t region[] = { width, height, 1 };
2704 // blocking.
2705 return dt_opencl_write_host_to_device_raw(devid, host, device, origin, region, rowpitch, CL_TRUE);
2706}
2707
2708int dt_opencl_write_host_to_device_non_blocking(const int devid, void *host, void *device, const int width,
2709 const int height, const int bpp)
2710{
2712}
2713
2714int dt_opencl_write_host_to_device_rowpitch_non_blocking(const int devid, void *host, void *device,
2715 const int width, const int height,
2716 const int rowpitch)
2717{
2718 if(!(_opencl && _opencl->inited) || devid < 0) return -1;
2719 const size_t origin[] = { 0, 0, 0 };
2720 const size_t region[] = { width, height, 1 };
2721 // non-blocking.
2722 return dt_opencl_write_host_to_device_raw(devid, host, device, origin, region, rowpitch, CL_FALSE);
2723}
2724
2725int dt_opencl_write_host_to_device_raw(const int devid, const void *host, void *device, const size_t *origin,
2726 const size_t *region, const int rowpitch, const int blocking)
2727{
2728 if(!(_opencl && _opencl->inited)) return -1;
2729
2730 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Write Image (from host to device)]");
2731
2733 device, blocking ? CL_TRUE : CL_FALSE, origin, region,
2734 rowpitch, 0, host, 0, NULL, eventp);
2735}
2736
2737int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst,
2738 size_t *region)
2739{
2740 if(!(_opencl && _opencl->inited) || devid < 0) return -1;
2741 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Copy Image (on device)]");
2742 cl_int err = (_opencl->dlocl->symbols->dt_clEnqueueCopyImage)(
2743 _opencl->dev[devid].cmd_queue, src, dst, orig_src, orig_dst, region, 0, NULL, eventp);
2744 if(err != CL_SUCCESS) dt_print(DT_DEBUG_OPENCL, "[opencl copy_image] could not copy image on device %d: %i\n", devid, err);
2745 return err;
2746}
2747
2748int dt_opencl_enqueue_copy_image_to_buffer(const int devid, cl_mem src_image, cl_mem dst_buffer,
2749 size_t *origin, size_t *region, size_t offset)
2750{
2751 if(!(_opencl && _opencl->inited)) return -1;
2752 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Copy Image to Buffer (on device)]");
2754 _opencl->dev[devid].cmd_queue, src_image, dst_buffer, origin, region, offset, 0, NULL, eventp);
2755 if(err != CL_SUCCESS)
2756 dt_print(DT_DEBUG_OPENCL, "[opencl copy_image_to_buffer] could not copy image on device %d: %i\n", devid, err);
2757 return err;
2758}
2759
2760int dt_opencl_enqueue_copy_buffer_to_image(const int devid, cl_mem src_buffer, cl_mem dst_image,
2761 size_t offset, size_t *origin, size_t *region)
2762{
2763 if(!(_opencl && _opencl->inited)) return -1;
2764 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Copy Buffer to Image (on device)]");
2766 _opencl->dev[devid].cmd_queue, src_buffer, dst_image, offset, origin, region, 0, NULL, eventp);
2767 if(err != CL_SUCCESS)
2768 dt_print(DT_DEBUG_OPENCL, "[opencl copy_buffer_to_image] could not copy buffer on device %d: %i\n", devid, err);
2769 return err;
2770}
2771
2772int dt_opencl_enqueue_copy_buffer_to_buffer(const int devid, cl_mem src_buffer, cl_mem dst_buffer,
2773 size_t srcoffset, size_t dstoffset, size_t size)
2774{
2775 if(!(_opencl && _opencl->inited)) return -1;
2776 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Copy Buffer to Buffer (on device)]");
2778 src_buffer, dst_buffer, srcoffset,
2779 dstoffset, size, 0, NULL, eventp);
2780 if(err != CL_SUCCESS)
2781 dt_print(DT_DEBUG_OPENCL, "[opencl copy_buffer_to_buffer] could not copy buffer on device %d: %i\n", devid, err);
2782 return err;
2783}
2784
2785int dt_opencl_read_buffer_from_device(const int devid, void *host, void *device, const size_t offset,
2786 const size_t size, const int blocking)
2787{
2788 if(!(_opencl && _opencl->inited)) return -1;
2789
2790 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Read Buffer (from device to host)]");
2791
2793 _opencl->dev[devid].cmd_queue, device, blocking ? CL_TRUE : CL_FALSE, offset, size, host, 0, NULL, eventp);
2794}
2795
2796int dt_opencl_write_buffer_to_device(const int devid, void *host, void *device, const size_t offset,
2797 const size_t size, const int blocking)
2798{
2799 if(!(_opencl && _opencl->inited)) return -1;
2800
2801 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Write Buffer (from host to device)]");
2802
2804 _opencl->dev[devid].cmd_queue, device, blocking ? CL_TRUE : CL_FALSE, offset, size, host, 0, NULL, eventp);
2805}
2806
2807
2808void *dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
2809{
2810 if(!(_opencl && _opencl->inited) || devid < 0) return NULL;
2811 cl_int err;
2812 cl_mem dev = (_opencl->dlocl->symbols->dt_clCreateBuffer)(
2813 _opencl->dev[devid].context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, size, host, &err);
2814 if(err != CL_SUCCESS)
2816 "[opencl copy_host_to_device_constant] could not alloc buffer on device %d: %i\n", devid, err);
2817
2818 if(err == CL_SUCCESS) dt_opencl_memory_statistics(devid, dev, size, OPENCL_MEMORY_ADD);
2819
2820 return dev;
2821}
2822
2823void *dt_opencl_copy_host_to_device(const int devid, void *host, const int width, const int height,
2824 const int bpp)
2825{
2826 return dt_opencl_copy_host_to_device_rowpitch(devid, host, width, height, bpp, 0);
2827}
2828
2829void *dt_opencl_copy_host_to_device_rowpitch(const int devid, void *host, const int width, const int height,
2830 const int bpp, const int rowpitch)
2831{
2832 if(!(_opencl && _opencl->inited) || devid < 0) return NULL;
2833 cl_int err;
2834 cl_image_format fmt;
2835 // guess pixel format from bytes per pixel
2836 if(bpp == 4 * sizeof(float))
2837 fmt = (cl_image_format){ CL_RGBA, CL_FLOAT };
2838 else if(bpp == sizeof(float))
2839 fmt = (cl_image_format){ CL_R, CL_FLOAT };
2840 else if(bpp == sizeof(uint16_t))
2841 fmt = (cl_image_format){ CL_R, CL_UNSIGNED_INT16 };
2842 else
2843 return NULL;
2844
2845 // TODO: if fmt = uint16_t, blow up to 4xuint16_t and copy manually!
2846 cl_mem dev = (_opencl->dlocl->symbols->dt_clCreateImage2D)(
2847 _opencl->dev[devid].context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, &fmt, width, height,
2848 rowpitch, host, &err);
2849 if(err != CL_SUCCESS)
2851 "[opencl copy_host_to_device] could not alloc/copy img buffer on device %d: %i\n", devid, err);
2852
2853 if(err == CL_SUCCESS)
2854 {
2855 const size_t bytes = (size_t)(rowpitch ? rowpitch : width * bpp) * height;
2857 }
2858
2859 return dev;
2860}
2861
2862
2864{
2865 if(!(_opencl && _opencl->inited)) return;
2866
2867 // the OpenCL specs are not absolutely clear if clReleaseMemObject(NULL) is a no-op. we take care of the
2868 // case in a centralized way at this place
2869 if(IS_NULL_PTR(mem)) return;
2870
2872
2874}
2875
2876void *dt_opencl_map_buffer(const int devid, cl_mem buffer, const int blocking, const int flags, size_t offset,
2877 size_t size)
2878{
2879 if(!(_opencl && _opencl->inited)) return NULL;
2880 cl_int err;
2881 void *ptr;
2882 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Map Buffer]");
2884 _opencl->dev[devid].cmd_queue, buffer, blocking ? CL_TRUE : CL_FALSE, flags, offset, size, 0, NULL, eventp, &err);
2885 if(err != CL_SUCCESS) dt_print(DT_DEBUG_OPENCL, "[opencl map buffer] could not map buffer on device %d: %i\n", devid, err);
2886 return ptr;
2887}
2888
2889
2890void *dt_opencl_map_image(const int devid, cl_mem buffer, const int blocking, const int flags, size_t width, size_t height, int bpp)
2891{
2892 if(!(_opencl && _opencl->inited)) return NULL;
2893 cl_int err;
2894 void *ptr;
2895 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Map Image 2D]");
2896 size_t origin[3] = {0, 0, 0};
2897 size_t region[3] = {width, height, 1};
2898 size_t mapped_row_pitch;
2899
2901 _opencl->dev[devid].cmd_queue, buffer, blocking ? CL_TRUE : CL_FALSE, flags, origin, region,
2902 &mapped_row_pitch, NULL, 0, NULL, eventp, &err);
2903
2904 if(err != CL_SUCCESS)
2905 dt_print(DT_DEBUG_OPENCL, "[opencl map buffer] could not map image on device %d: %i\n", devid, err);
2906 return ptr;
2907}
2908
2909
2910int dt_opencl_unmap_mem_object(const int devid, cl_mem mem_object, void *mapped_ptr)
2911{
2912 if(!(_opencl && _opencl->inited)) return -1;
2913 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Unmap Mem Object]");
2915 _opencl->dev[devid].cmd_queue, mem_object, mapped_ptr, 0, NULL, eventp);
2916 if(err != CL_SUCCESS)
2917 dt_print(DT_DEBUG_OPENCL, "[opencl unmap mem object] could not unmap mem object on device %d: %i\n", devid, err);
2918 return err;
2919}
2920
2921static inline void *_dt_opencl_alloc_image2d(const int devid, const int width, const int height,
2922 const size_t bytes, const cl_mem_flags flags,
2923 const cl_image_format fmt, void *host,
2924 const char *const context)
2925{
2926 if(!(_opencl && _opencl->inited) || devid < 0) return NULL;
2927 cl_int err;
2928 cl_mem dev = NULL;
2929 for(int attempt = 0; attempt < 2; attempt++)
2930 {
2932 &fmt, width, height, 0, host, &err);
2933 if(err == CL_SUCCESS) break;
2934 if(attempt == 0 && (err == CL_MEM_OBJECT_ALLOCATION_FAILURE || err == CL_OUT_OF_RESOURCES))
2935 {
2937 "[opencl %s] out of memory on device %d, flushing cached pinned buffers and retrying\n",
2938 context, devid);
2940 continue;
2941 }
2942 break;
2943 }
2944
2945 if(err != CL_SUCCESS)
2946 dt_print(DT_DEBUG_OPENCL, "[opencl %s] could not alloc img buffer on device %d: %i\n", context, devid, err);
2947
2948 if(err == CL_SUCCESS) dt_opencl_memory_statistics(devid, dev, bytes, OPENCL_MEMORY_ADD);
2949 return dev;
2950}
2951
2952void *dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
2953{
2954 const int effective_bpp = DT_OPENCL_BPP_DECODE(bpp);
2955 const gboolean rgba8 = DT_OPENCL_BPP_IS_RGBA8(bpp);
2956 cl_image_format fmt;
2957 // guess pixel format from bytes per pixel (+ optional format tag for ambiguous 4-byte formats)
2958 if(rgba8 && effective_bpp == 4 * sizeof(uint8_t))
2959 fmt = (cl_image_format){ CL_RGBA, CL_UNSIGNED_INT8 };
2960 else if(effective_bpp == 4 * sizeof(float))
2961 fmt = (cl_image_format){ CL_RGBA, CL_FLOAT };
2962 else if(effective_bpp == sizeof(float))
2963 fmt = (cl_image_format){ CL_R, CL_FLOAT };
2964 else if(effective_bpp == sizeof(uint16_t))
2965 fmt = (cl_image_format){ CL_R, CL_UNSIGNED_INT16 };
2966 else if(effective_bpp == sizeof(uint8_t))
2967 fmt = (cl_image_format){ CL_R, CL_UNSIGNED_INT8 };
2968 else
2969 return NULL;
2970
2971 const size_t bytes = (size_t)width * height * effective_bpp;
2972 return _dt_opencl_alloc_image2d(devid, width, height, bytes, CL_MEM_READ_WRITE, fmt, NULL, "alloc_device");
2973}
2974
2975void *dt_opencl_alloc_device_use_host_pointer(const int devid, const int width, const int height,
2976 const int bpp, void *host, const int flags)
2977{
2978 const int effective_bpp = DT_OPENCL_BPP_DECODE(bpp);
2979 const gboolean rgba8 = DT_OPENCL_BPP_IS_RGBA8(bpp);
2980 cl_image_format fmt;
2981 // guess pixel format from bytes per pixel (+ optional format tag for ambiguous 4-byte formats)
2982 if(rgba8 && effective_bpp == 4 * sizeof(uint8_t))
2983 fmt = (cl_image_format){ CL_RGBA, CL_UNSIGNED_INT8 };
2984 else if(effective_bpp == 4 * sizeof(float))
2985 fmt = (cl_image_format){ CL_RGBA, CL_FLOAT };
2986 else if(effective_bpp == sizeof(float))
2987 fmt = (cl_image_format){ CL_R, CL_FLOAT };
2988 else if(effective_bpp == sizeof(uint16_t))
2989 fmt = (cl_image_format){ CL_R, CL_UNSIGNED_INT16 };
2990 else
2991 return NULL;
2992
2993 const size_t bytes = (size_t)width * height * effective_bpp;
2994 return _dt_opencl_alloc_image2d(devid, width, height, bytes, flags, fmt, host,
2995 "alloc_device_use_host_pointer");
2996}
2997
2998void *dt_opencl_alloc_device_buffer_with_flags(const int devid, const size_t size, const int flags, void *host_ptr)
2999{
3000 if(!(_opencl && _opencl->inited)) return NULL;
3001 cl_int err;
3002 cl_mem buf = NULL;
3003 for(int attempt = 0; attempt < 2; attempt++)
3004 {
3006 flags, size, host_ptr, &err);
3007 if(err == CL_SUCCESS) break;
3008 if(attempt == 0 && (err == CL_MEM_OBJECT_ALLOCATION_FAILURE || err == CL_OUT_OF_RESOURCES))
3009 {
3011 "[opencl alloc_device_buffer] out of memory on device %d, flushing cached pinned buffers and retrying\n",
3012 devid);
3014 continue;
3015 }
3016 break;
3017 }
3018 if(err != CL_SUCCESS)
3019 dt_print(DT_DEBUG_OPENCL, "[opencl alloc_device_buffer] could not alloc buffer on device %d: %d\n", devid,
3020 err);
3021
3022 if(err == CL_SUCCESS) dt_opencl_memory_statistics(devid, buf, size, OPENCL_MEMORY_ADD);
3023
3024 return buf;
3025}
3026
3027
3028void *dt_opencl_alloc_device_buffer(const int devid, const size_t size)
3029{
3030 return dt_opencl_alloc_device_buffer_with_flags(devid, size, CL_MEM_READ_WRITE, NULL);
3031}
3032
3033
3035{
3036 size_t size;
3037 if(IS_NULL_PTR(mem)) return 0;
3038
3039 cl_int err = (_opencl->dlocl->symbols->dt_clGetMemObjectInfo)(mem, CL_MEM_SIZE, sizeof(size), &size, NULL);
3040
3041 return (err == CL_SUCCESS) ? size : 0;
3042}
3043
3045{
3046 cl_context context;
3047 if(IS_NULL_PTR(mem)) return -1;
3048
3049 cl_int err = (_opencl->dlocl->symbols->dt_clGetMemObjectInfo)(mem, CL_MEM_CONTEXT, sizeof(context), &context, NULL);
3050 if(err != CL_SUCCESS)
3051 return -1;
3052
3053 for(int devid = 0; devid < _opencl->num_devs; devid++)
3054 {
3055 if(_opencl->dev[devid].context == context)
3056 return devid;
3057 }
3058
3059 return -1;
3060}
3061
3062cl_mem_flags dt_opencl_get_mem_flags(cl_mem mem)
3063{
3064 if(!(_opencl && _opencl->inited) || IS_NULL_PTR(mem)) return 0;
3065 cl_mem_flags flags = 0;
3066 cl_int err = (_opencl->dlocl->symbols->dt_clGetMemObjectInfo)(mem, CL_MEM_FLAGS, sizeof(flags), &flags, NULL);
3067 if(err != CL_SUCCESS) return 0;
3068 return flags;
3069}
3070
3072{
3073 size_t size;
3074 if(IS_NULL_PTR(mem)) return 0;
3075
3076 cl_int err = (_opencl->dlocl->symbols->dt_clGetImageInfo)(mem, CL_IMAGE_WIDTH, sizeof(size), &size, NULL);
3077 if(size > INT_MAX) size = 0;
3078
3079 return (err == CL_SUCCESS) ? (int)size : 0;
3080}
3081
3083{
3084 size_t size;
3085 if(IS_NULL_PTR(mem)) return 0;
3086
3087 cl_int err = (_opencl->dlocl->symbols->dt_clGetImageInfo)(mem, CL_IMAGE_HEIGHT, sizeof(size), &size, NULL);
3088 if(size > INT_MAX) size = 0;
3089
3090 return (err == CL_SUCCESS) ? (int)size : 0;
3091}
3092
3094{
3095 size_t size;
3096 if(IS_NULL_PTR(mem)) return 0;
3097
3098 cl_int err = (_opencl->dlocl->symbols->dt_clGetImageInfo)(mem, CL_IMAGE_ELEMENT_SIZE, sizeof(size), &size,
3099 NULL);
3100 if(size > INT_MAX) size = 0;
3101
3102 return (err == CL_SUCCESS) ? (int)size : 0;
3103}
3104
3110
3111void dt_opencl_memory_statistics(int devid, cl_mem mem, size_t size, dt_opencl_memory_t action)
3112{
3113 if(IS_NULL_PTR(mem)) return;
3114
3115 if(action == OPENCL_MEMORY_ADD)
3116 {
3117 // devid and size are known at allocation time -- record them so the release
3118 // path can undo the exact same amount without querying the driver.
3119 if(devid < 0) return;
3121 rec->devid = devid;
3122 rec->size = size;
3124 // g_hash_table_insert frees the previous value (g_free) if the key already
3125 // exists, so re-inserting the same cl_mem pointer never leaks.
3126 g_hash_table_insert(_opencl->mem_sizes, mem, rec);
3128 }
3129 else
3130 {
3131 // Look up what we recorded on ADD. Never ask the driver about the object here
3132 // either: on some Windows drivers clGetMemObjectInfo faults under vRAM
3133 // pressure (issues #130221119 / #130557353), aborting the process.
3135 dt_opencl_mem_record_t *rec = (dt_opencl_mem_record_t *)g_hash_table_lookup(_opencl->mem_sizes, mem);
3136 if(rec)
3137 {
3138 devid = rec->devid;
3139 size = rec->size;
3140 g_hash_table_remove(_opencl->mem_sizes, mem);
3141 }
3142 else
3143 {
3144 // Untracked object (allocated before this bookkeeping, or via a path that
3145 // did not register). Nothing reliable to subtract; leave the counter be.
3146 devid = -1;
3147 }
3149 }
3150
3151 if(devid < 0)
3152 return;
3153
3154 if(action == OPENCL_MEMORY_ADD)
3155 _opencl->dev[devid].memory_in_use += size;
3156 else
3157 _opencl->dev[devid].memory_in_use =
3158 (_opencl->dev[devid].memory_in_use > size)
3159 ? (_opencl->dev[devid].memory_in_use - size)
3160 : 0;
3161
3162 _opencl->dev[devid].peak_memory = MAX(_opencl->dev[devid].peak_memory,
3163 _opencl->dev[devid].memory_in_use);
3164
3167 "[opencl memory] device %d: %" G_GSIZE_FORMAT " bytes (%.1f MB) in use\n", devid, _opencl->dev[devid].memory_in_use,
3168 (float)_opencl->dev[devid].memory_in_use/(1024*1024));
3169}
3170
3171gboolean dt_opencl_get_mem_record(cl_mem mem, int *devid, size_t *size)
3172{
3173 if(IS_NULL_PTR(mem) || !(_opencl && _opencl->inited)) return FALSE;
3175 const dt_opencl_mem_record_t *rec = (const dt_opencl_mem_record_t *)g_hash_table_lookup(_opencl->mem_sizes, mem);
3176 const gboolean found = !IS_NULL_PTR(rec);
3177 if(found)
3178 {
3179 *devid = rec->devid;
3180 *size = rec->size;
3181 }
3183 return found;
3184}
3185
3186void dt_opencl_check_tuning(const int devid)
3187{
3188 dt_opencl_t *cl = _opencl;
3189 if(!cl->inited || devid < 0) return;
3190
3191 // Apply the headroom read from this device configuration. Older configs without
3192 // a per-device key are migrated from the global default during device init.
3193 size_t headroom = cl->dev[devid].forced_headroom;
3194
3195 cl->dev[devid].used_available = MAX(0ul, cl->dev[devid].max_global_mem - headroom * 1024 * 1024);
3196
3198 "[dt_opencl_check_tuning] use %" G_GSIZE_FORMAT " MiB on device `%s' id=%i\n",
3199 cl->dev[devid].used_available / (1024 * 1024),
3200 cl->dev[devid].name, devid);
3201}
3202
3203cl_ulong dt_opencl_get_device_available(const int devid)
3204{
3205 if(!(_opencl && _opencl->inited) || devid < 0) return 0;
3206 const cl_ulong limit = _opencl->dev[devid].used_available;
3207 const size_t in_use = _opencl->dev[devid].memory_in_use;
3208 cl_ulong available = (limit > in_use) ? (limit - in_use) : 0;
3209
3210 /* A host-unified device is bounded by two DIFFERENT things, and they must not be conflated.
3211 *
3212 * 1. Free space. Its "vRAM" is system RAM, shared with every other process and with the host
3213 * side of our own pipeline, so max_global_mem is the size of the machine rather than a
3214 * budget -- a P630 reports 28.75 GiB on a 31 GiB box. dt_get_system_available_mem() already
3215 * measures what is actually left (free plus reclaimable, cgroup limits included), so clamp
3216 * to it. A 0 return means the platform will not say; that is "no information", not "no
3217 * memory", so the device's own accounting stands.
3218 *
3219 * 2. How much the driver can have in flight at once, which is NOT a free-space question and
3220 * does not get better when RAM is free. Measured on the P630 with 22 GiB genuinely
3221 * available: an ~8 GiB working set fails, the pipe loses OpenCL entirely and drops to CPU;
3222 * ~4 GiB fails mid-tile; ~2 GiB completes. The ceiling is the GPU aperture / address space
3223 * per context, which OpenCL publishes no query for. max_mem_alloc is the closest thing it
3224 * does publish -- NEO reports min(global/4, 4 GiB), which tracks that aperture -- so half
3225 * of it is used as a working-set ceiling. It is a proxy chosen to match the measurement,
3226 * not a measurement of anything, and it is written here as its own clamp so it cannot be
3227 * misread as free space.
3228 *
3229 * This lives in the reader rather than in dt_opencl_check_tuning() because the tilers and the
3230 * fit checks call it while deciding: limit 1 is then re-probed at each decision instead of
3231 * frozen once per pipe run, before any of the allocations it governs. The probe caches for
3232 * tens of milliseconds, which is what makes that affordable.
3233 *
3234 * Discrete devices never enter here: their max_global_mem really is dedicated vRAM. */
3235 if(_opencl->dev[devid].host_unified_memory)
3236 {
3237 const size_t reserved = (size_t)_opencl->dev[devid].forced_headroom * 1024 * 1024;
3238
3239 const size_t system_available = dt_get_system_available_mem();
3240 if(system_available > 0)
3241 available = MIN(available, (cl_ulong)((system_available > reserved) ? system_available - reserved : 0));
3242
3243 available = MIN(available, (cl_ulong)(_opencl->dev[devid].max_mem_alloc / 2));
3244 }
3245 return available;
3246}
3247
3248static cl_ulong _opencl_get_device_memalloc(const int devid)
3249{
3250 return _opencl->dev[devid].max_mem_alloc;
3251}
3252
3253cl_ulong dt_opencl_get_device_memalloc(const int devid)
3254{
3255 if(!(_opencl && _opencl->inited) || devid < 0) return 0;
3256 return _opencl_get_device_memalloc(devid);
3257}
3258
3260 const size_t height, const unsigned bpp, const float factor,
3261 const size_t overhead, size_t *needed, size_t *limit)
3262{
3263 size_t n = 0, l = 0;
3265
3266 dt_opencl_t *cl = _opencl;
3267 if(!cl->inited || devid < 0)
3268 {
3269 reason = DT_OPENCL_FIT_UNINITED;
3270 }
3271 else
3272 {
3273 const size_t required = width * height * bpp;
3274 const size_t total = (size_t)ceilf((float)required * factor) + overhead;
3275
3276 if(cl->dev[devid].max_image_width < width || cl->dev[devid].max_image_height < height)
3277 {
3278 // dimension limit: compared quantities are pixel counts, not bytes -> leave n/l at 0
3279 reason = DT_OPENCL_FIT_DIMENSION;
3280 }
3281 else if(_opencl_get_device_memalloc(devid) < required)
3282 {
3283 n = required;
3284 l = _opencl_get_device_memalloc(devid);
3286 "[opencl] trying to allocate %" PRIu64 " MiB of memory while the vRAM has %" PRIu64
3287 " MiB total\n",
3288 (uint64_t)(n / (1024 * 1024)), (uint64_t)(l / (1024 * 1024)));
3290 }
3291 else if(dt_opencl_get_device_available(devid) < total)
3292 {
3293 n = total;
3296 "[opencl] trying to allocate %" PRIu64 " MiB of memory while the vRAM has %" PRIu64
3297 " MiB left\n",
3298 (uint64_t)(n / (1024 * 1024)), (uint64_t)(l / (1024 * 1024)));
3299 reason = DT_OPENCL_FIT_AVAILABLE;
3300 }
3301 }
3302
3303 if(needed) *needed = n;
3304 if(limit) *limit = l;
3305 return reason;
3306}
3307
3308gboolean dt_opencl_image_fits_device(const int devid, const size_t width, const size_t height, const unsigned bpp,
3309 const float factor, const size_t overhead)
3310{
3311 return dt_opencl_image_fits_device_reason(devid, width, height, bpp, factor, overhead, NULL, NULL)
3313}
3314
3316int dt_opencl_dev_roundup_width(int size, const int devid)
3317{
3318 const int roundup = _opencl->dev[devid].clroundup_wd;
3319 return (size % roundup == 0 ? size : (size / roundup + 1) * roundup);
3320}
3321int dt_opencl_dev_roundup_height(int size, const int devid)
3322{
3323 const int roundup = _opencl->dev[devid].clroundup_ht;
3324 return (size % roundup == 0 ? size : (size / roundup + 1) * roundup);
3325}
3326
3329{
3330 return (_opencl && _opencl->inited);
3331}
3332
3333
3336{
3337 if(!(_opencl && _opencl->inited)) return FALSE;
3338 return _opencl->enabled;
3339}
3340
3341
3344{
3345 if(!(_opencl && _opencl->inited)) return;
3347 dt_conf_set_bool("opencl", FALSE);
3348}
3349
3350
3353{
3354 dt_opencl_t *cl = _opencl;
3355 // FIXME: This pulls in prefs every time the pixelpipe runs. Instead have a callback for DT_SIGNAL_PREFERENCES_CHANGE?
3356 if(!cl->inited) return FALSE;
3357 const int prefs = dt_conf_get_bool("opencl");
3358
3359 if(cl->enabled != prefs)
3360 {
3361 cl->enabled = prefs;
3362 cl->stopped = 0;
3363 cl->error_count = 0;
3364 dt_print(DT_DEBUG_OPENCL, "[opencl_update_enabled] enabled flag set to %s\n", prefs ? "ON" : "OFF");
3365 }
3366
3367 return (cl->enabled && !cl->stopped);
3368}
3369
3370
3373{
3375 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_synchronization_timeout] synchronization timeout set to %d\n", value);
3376}
3377
3386
3387
3391cl_event *dt_opencl_events_get_slot(const int devid, const char *tag)
3392{
3393 dt_opencl_t *cl = _opencl;
3394 if(!cl->inited || devid < 0) return NULL;
3395 if(!cl->dev[devid].use_events) return NULL;
3396
3397 static const cl_event zeroevent[1]; // implicitly initialized to zero
3398 cl_event **eventlist = &(cl->dev[devid].eventlist);
3399 dt_opencl_eventtag_t **eventtags = &(cl->dev[devid].eventtags);
3400 int *numevents = &(cl->dev[devid].numevents);
3401 int *maxevents = &(cl->dev[devid].maxevents);
3402 int *eventsconsolidated = &(cl->dev[devid].eventsconsolidated);
3403 int *lostevents = &(cl->dev[devid].lostevents);
3404 int *totalevents = &(cl->dev[devid].totalevents);
3405 int *totallost = &(cl->dev[devid].totallost);
3406 int *maxeventslot = &(cl->dev[devid].maxeventslot);
3407 // if first time called: allocate initial buffers
3408 if(IS_NULL_PTR(*eventlist))
3409 {
3410 int newevents = DT_OPENCL_EVENTLISTSIZE;
3411 *eventlist = calloc(newevents, sizeof(cl_event));
3412 *eventtags = calloc(newevents, sizeof(dt_opencl_eventtag_t));
3413 if(!*eventlist || !*eventtags)
3414 {
3415 dt_free(*eventlist);
3416 dt_free(*eventtags);
3417 *eventlist = NULL;
3418 *eventtags = NULL;
3419 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_events_get_slot] NO eventlist for device %i\n", devid);
3420 return NULL;
3421 }
3422 *maxevents = newevents;
3423 }
3424
3425 // check if currently highest event slot was actually consumed. If not use it again
3426 if(*numevents > 0 && !memcmp((*eventlist) + *numevents - 1, zeroevent, sizeof(cl_event)))
3427 {
3428 (*lostevents)++;
3429 (*totallost)++;
3430 if(!IS_NULL_PTR(tag))
3431 {
3432 g_strlcpy((*eventtags)[*numevents - 1].tag, tag, DT_OPENCL_EVENTNAMELENGTH);
3433 }
3434 else
3435 {
3436 (*eventtags)[*numevents - 1].tag[0] = '\0';
3437 }
3438
3439 (*totalevents)++;
3440 return (*eventlist) + *numevents - 1;
3441 }
3442
3443 // check if we would exceed the number of available event handles. In that case first flush existing handles
3444 if((*numevents - *eventsconsolidated + 1 > cl->dev[devid].event_handles) || (*numevents == *maxevents))
3445 (void)dt_opencl_events_flush(devid, 0);
3446
3447 // if no more space left in eventlist: grow buffer
3448 if(*numevents == *maxevents)
3449 {
3450 int newevents = *maxevents + DT_OPENCL_EVENTLISTSIZE;
3451 cl_event *neweventlist = calloc(newevents, sizeof(cl_event));
3452 dt_opencl_eventtag_t *neweventtags = calloc(newevents, sizeof(dt_opencl_eventtag_t));
3453 if(!neweventlist || IS_NULL_PTR(neweventtags))
3454 {
3455 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_events_get_slot] NO new eventlist with size %i for device %i\n",
3456 newevents, devid);
3457 dt_free(neweventlist);
3458 dt_free(neweventtags);
3459 return NULL;
3460 }
3461 memcpy(neweventlist, *eventlist, sizeof(cl_event) * *maxevents);
3462 memcpy(neweventtags, *eventtags, sizeof(dt_opencl_eventtag_t) * *maxevents);
3463 dt_free(*eventlist);
3464 dt_free(*eventtags);
3465 *eventlist = neweventlist;
3466 *eventtags = neweventtags;
3467 *maxevents = newevents;
3468 }
3469
3470 // init next event slot and return it
3471 (*numevents)++;
3472 memcpy((*eventlist) + *numevents - 1, zeroevent, sizeof(cl_event));
3473 if(!IS_NULL_PTR(tag))
3474 {
3475 g_strlcpy((*eventtags)[*numevents - 1].tag, tag, DT_OPENCL_EVENTNAMELENGTH);
3476 }
3477 else
3478 {
3479 (*eventtags)[*numevents - 1].tag[0] = '\0';
3480 }
3481
3482 (*totalevents)++;
3483 *maxeventslot = MAX(*maxeventslot, *numevents - 1);
3484 return (*eventlist) + *numevents - 1;
3485}
3486
3487
3489void dt_opencl_events_reset(const int devid)
3490{
3491 dt_opencl_t *cl = _opencl;
3492 if(!cl->inited || devid < 0) return;
3493 if(!cl->dev[devid].use_events) return;
3494
3495 cl_event **eventlist = &(cl->dev[devid].eventlist);
3496 dt_opencl_eventtag_t **eventtags = &(cl->dev[devid].eventtags);
3497 int *numevents = &(cl->dev[devid].numevents);
3498 int *maxevents = &(cl->dev[devid].maxevents);
3499 int *eventsconsolidated = &(cl->dev[devid].eventsconsolidated);
3500 int *lostevents = &(cl->dev[devid].lostevents);
3501 cl_int *summary = &(cl->dev[devid].summary);
3502
3503 if(IS_NULL_PTR(*eventlist) || *numevents == 0) return; // nothing to do
3504
3505 static const cl_event zeroevent[1]; // implicitly initialized to zero
3506
3507 // release all remaining events in eventlist, not to waste resources.
3508 // Skip NULL handles left behind by failed enqueues: releasing them is
3509 // pointless and crashes some drivers.
3510 for(int k = *eventsconsolidated; k < *numevents; k++)
3511 {
3512 if(memcmp((*eventlist) + k, zeroevent, sizeof(cl_event)))
3513 (cl->dlocl->symbols->dt_clReleaseEvent)((*eventlist)[k]);
3514 }
3515
3516 memset(*eventtags, 0, sizeof(dt_opencl_eventtag_t) * *maxevents);
3517 *numevents = 0;
3518 *eventsconsolidated = 0;
3519 *lostevents = 0;
3520 *summary = CL_COMPLETE;
3521 return;
3522}
3523
3524
3527void dt_opencl_events_wait_for(const int devid)
3528{
3529 dt_opencl_t *cl = _opencl;
3530 if(!cl->inited || devid < 0) return;
3531 if(!cl->dev[devid].use_events) return;
3532
3533 static const cl_event zeroevent[1]; // implicitly initialized to zero
3534 cl_event **eventlist = &(cl->dev[devid].eventlist);
3535 int *numevents = &(cl->dev[devid].numevents);
3536 int *lostevents = &(cl->dev[devid].lostevents);
3537 int *totallost = &(cl->dev[devid].totallost);
3538 int *eventsconsolidated = &(cl->dev[devid].eventsconsolidated);
3539
3540 if(IS_NULL_PTR(*eventlist) || *numevents == 0) return; // nothing to do
3541
3542 // check if last event slot was actually used and correct numevents if needed
3543 if(!memcmp((*eventlist) + *numevents - 1, zeroevent, sizeof(cl_event)))
3544 {
3545 (*numevents)--;
3546 (*lostevents)++;
3547 (*totallost)++;
3548 }
3549
3550 if(*numevents == *eventsconsolidated) return; // nothing to do
3551
3552 assert(*numevents > *eventsconsolidated);
3553
3554 // Wait for all remaining events to terminate, skipping NULL handles. A reserved
3555 // slot can hold a NULL handle when its enqueue failed (the event is never
3556 // created, but get_slot had already counted the slot). Passing NULL to
3557 // clWaitForEvents crashes some drivers and, on those that merely return an
3558 // error, would abort a batched wait and leave the valid events that follow
3559 // un-waited-for before flush checks/releases them. We wait on each handle
3560 // individually rather than gathering them into a temporary array: a heap
3561 // allocation could fail under the very memory pressure that creates these NULL
3562 // slots, and returning early on that failure would skip the wait entirely.
3563 // Risk: might never return in case of OpenCL blocks or endless loops
3564 // TODO: run clWaitForEvents in separate thread and implement watchdog timer
3565 for(int k = *eventsconsolidated; k < *numevents; k++)
3566 {
3567 if(!memcmp((*eventlist) + k, zeroevent, sizeof(cl_event)))
3568 continue; // NULL handle from a failed enqueue
3569
3570 cl_int err = (cl->dlocl->symbols->dt_clWaitForEvents)(1, &((*eventlist)[k]));
3571 if((err != CL_SUCCESS) && (err != CL_INVALID_VALUE))
3572 dt_vprint(DT_DEBUG_OPENCL, "[dt_opencl_events_wait_for] reported %i for device %i\n",
3573 err, devid);
3574 }
3575}
3576
3577
3584cl_int dt_opencl_events_flush(const int devid, const int reset)
3585{
3586 dt_opencl_t *cl = _opencl;
3587 if(!cl->inited || devid < 0) return FALSE;
3588 if(!cl->dev[devid].use_events) return FALSE;
3589
3590 cl_event **eventlist = &(cl->dev[devid].eventlist);
3591 dt_opencl_eventtag_t **eventtags = &(cl->dev[devid].eventtags);
3592 int *numevents = &(cl->dev[devid].numevents);
3593 int *eventsconsolidated = &(cl->dev[devid].eventsconsolidated);
3594 int *lostevents = &(cl->dev[devid].lostevents);
3595 int *totalsuccess = &(cl->dev[devid].totalsuccess);
3596
3597 cl_int *summary = &(cl->dev[devid].summary);
3598
3599 static const cl_event zeroevent[1]; // implicitly initialized to zero
3600
3601 if(IS_NULL_PTR(*eventlist) || *numevents == 0) return CL_COMPLETE; // nothing to do, no news is good news
3602
3603 // Wait for command queue to terminate (side effect: might adjust *numevents)
3605
3606 // now check return status and profiling data of all newly terminated events
3607 for(int k = *eventsconsolidated; k < *numevents; k++)
3608 {
3609 // A reserved slot can still hold a NULL handle when the matching enqueue
3610 // failed: OpenCL does not create the event in that case, but get_slot had
3611 // already counted the slot. Passing such a NULL handle to the driver
3612 // crashes some implementations (e.g. NVIDIA on Windows), so treat it as a
3613 // lost event and skip it.
3614 if(!memcmp((*eventlist) + k, zeroevent, sizeof(cl_event)))
3615 {
3616 (*lostevents)++;
3617 (*eventsconsolidated)++;
3618 continue;
3619 }
3620
3621 cl_int err;
3622 char *tag = (*eventtags)[k].tag;
3623 cl_int *retval = &((*eventtags)[k].retval);
3624
3625 // get return value of event
3626 err = (cl->dlocl->symbols->dt_clGetEventInfo)((*eventlist)[k], CL_EVENT_COMMAND_EXECUTION_STATUS,
3627 sizeof(cl_int), retval, NULL);
3628 if(err != CL_SUCCESS)
3629 {
3630 dt_print(DT_DEBUG_OPENCL, "[opencl_events_flush] could not get event info for '%s': %i\n",
3631 tag[0] == '\0' ? "<?>" : tag, err);
3632 }
3633 else if(*retval != CL_COMPLETE)
3634 {
3635 dt_print(DT_DEBUG_OPENCL, "[opencl_events_flush] execution of '%s' %s: %d\n",
3636 tag[0] == '\0' ? "<?>" : tag, *retval == CL_COMPLETE ? "was successful" : "failed", *retval);
3637 *summary = *retval;
3638 }
3639 else
3640 (*totalsuccess)++;
3641
3643 {
3644 // get profiling info of event (only if darktable was called with '-d perf')
3645 cl_ulong start;
3646 cl_ulong end;
3647 cl_int errs = (cl->dlocl->symbols->dt_clGetEventProfilingInfo)(
3648 (*eventlist)[k], CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, NULL);
3649 cl_int erre = (cl->dlocl->symbols->dt_clGetEventProfilingInfo)((*eventlist)[k], CL_PROFILING_COMMAND_END,
3650 sizeof(cl_ulong), &end, NULL);
3651 if(errs == CL_SUCCESS && erre == CL_SUCCESS)
3652 {
3653 (*eventtags)[k].timelapsed = end - start;
3654 }
3655 else
3656 {
3657 (*eventtags)[k].timelapsed = 0;
3658 (*lostevents)++;
3659 }
3660 }
3661 else
3662 (*eventtags)[k].timelapsed = 0;
3663
3664 // finally release event to be re-used by driver
3665 (cl->dlocl->symbols->dt_clReleaseEvent)((*eventlist)[k]);
3666 (*eventsconsolidated)++;
3667 }
3668
3669 cl_int result = *summary;
3670
3671 // do we want to get rid of all stored info?
3672 if(reset)
3673 {
3674 // output profiling info if wanted
3676
3677 // reset eventlist structures to empty state
3679 }
3680
3681 return result == CL_COMPLETE ? 0 : result;
3682}
3683
3684
3687void dt_opencl_events_profiling(const int devid, const int aggregated)
3688{
3689 dt_opencl_t *cl = _opencl;
3690 if(!cl->inited || devid < 0) return;
3691 if(!cl->dev[devid].use_events) return;
3692
3693 cl_event **eventlist = &(cl->dev[devid].eventlist);
3694 dt_opencl_eventtag_t **eventtags = &(cl->dev[devid].eventtags);
3695 int *numevents = &(cl->dev[devid].numevents);
3696 int *eventsconsolidated = &(cl->dev[devid].eventsconsolidated);
3697 int *lostevents = &(cl->dev[devid].lostevents);
3698
3699 if(IS_NULL_PTR(*eventlist) || *numevents == 0 || IS_NULL_PTR(*eventtags) || *eventsconsolidated == 0)
3700 return; // nothing to do
3701
3702 char **tags = malloc(sizeof(char *) * (*eventsconsolidated + 1));
3703 float *timings = malloc(sizeof(float) * (*eventsconsolidated + 1));
3704 int items = 1;
3705 tags[0] = "";
3706 timings[0] = 0.0f;
3707
3708 // get profiling info and arrange it
3709 for(int k = 0; k < *eventsconsolidated; k++)
3710 {
3711 // if aggregated is TRUE, try to sum up timings for multiple runs of each kernel
3712 if(aggregated)
3713 {
3714 // linear search: this is not efficient at all but acceptable given the limited
3715 // number of events (ca. 10 - 20)
3716 int tagfound = -1;
3717 for(int i = 0; i < items; i++)
3718 {
3719 if(!strncmp(tags[i], (*eventtags)[k].tag, DT_OPENCL_EVENTNAMELENGTH))
3720 {
3721 tagfound = i;
3722 break;
3723 }
3724 }
3725
3726 if(tagfound >= 0) // tag was already detected before
3727 {
3728 // sum up timings
3729 timings[tagfound] += (*eventtags)[k].timelapsed * 1e-9;
3730 }
3731 else // tag is new
3732 {
3733 // make new entry
3734 items++;
3735 tags[items - 1] = (*eventtags)[k].tag;
3736 timings[items - 1] = (*eventtags)[k].timelapsed * 1e-9;
3737 }
3738 }
3739
3740 else // no aggregated info wanted -> arrange event by event
3741 {
3742 items++;
3743 tags[items - 1] = (*eventtags)[k].tag;
3744 timings[items - 1] = (*eventtags)[k].timelapsed * 1e-9;
3745 }
3746 }
3747
3748 // now display profiling info
3750 "[opencl_profiling] profiling device %d ('%s'):\n", devid, cl->dev[devid].name);
3751
3752 float total = 0.0f;
3753 for(int i = 1; i < items; i++)
3754 {
3755 dt_print(DT_DEBUG_OPENCL, "[opencl_profiling] spent %7.4f seconds in %s\n", (double)timings[i],
3756 tags[i][0] == '\0' ? "<?>" : tags[i]);
3757 total += timings[i];
3758 }
3759 // aggregated timing info for items without tag (if any)
3760 if(timings[0] != 0.0f)
3761 {
3762 dt_print(DT_DEBUG_OPENCL, "[opencl_profiling] spent %7.4f seconds (unallocated)\n", (double)timings[0]);
3763 total += timings[0];
3764 }
3765
3767 "[opencl_profiling] spent %7.4f seconds totally in command queue (with %d event%s missing)\n",
3768 (double)total, *lostevents, *lostevents == 1 ? "" : "s");
3769
3770 dt_free(timings);
3771 dt_free(tags);
3772
3773 return;
3774}
3775
3776static int nextpow2(int n)
3777{
3778 int k = 1;
3779 while (k < n)
3780 k <<= 1;
3781 return k;
3782}
3783
3784// utility function to calculate optimal work group dimensions for a given kernel
3785// taking device specific restrictions and local memory limitations into account
3786int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
3787{
3788 dt_opencl_t *cl = _opencl;
3789 if(!cl->inited || devid < 0) return FALSE;
3790
3791 size_t maxsizes[3] = { 0 }; // the maximum dimensions for a work group
3792 size_t workgroupsize = 0; // the maximum number of items in a work group
3793 unsigned long localmemsize = 0; // the maximum amount of local memory we can use
3794 size_t kernelworkgroupsize = 0; // the maximum amount of items in work group for this kernel
3795
3796 int *blocksizex = &factors->sizex;
3797 int *blocksizey = &factors->sizey;
3798
3799 // initial values must be supplied in sizex and sizey.
3800 // we make sure that these are a power of 2 and lie within reasonable limits.
3801 *blocksizex = CLAMP(nextpow2(*blocksizex), 1, 1 << 16);
3802 *blocksizey = CLAMP(nextpow2(*blocksizey), 1, 1 << 16);
3803
3804 if(dt_opencl_get_work_group_limits(devid, maxsizes, &workgroupsize, &localmemsize) == CL_SUCCESS
3805 && dt_opencl_get_kernel_work_group_size(devid, kernel, &kernelworkgroupsize) == CL_SUCCESS)
3806 {
3807 while(maxsizes[0] < *blocksizex || maxsizes[1] < *blocksizey
3808 || localmemsize < ((factors->xfactor * (*blocksizex) + factors->xoffset) *
3809 (factors->yfactor * (*blocksizey) + factors->yoffset)) * factors->cellsize + factors->overhead
3810 || workgroupsize < (size_t)(*blocksizex) * (*blocksizey) || kernelworkgroupsize < (size_t)(*blocksizex) * (*blocksizey))
3811 {
3812 if(*blocksizex == 1 && *blocksizey == 1) return FALSE;
3813
3814 if(*blocksizex > *blocksizey)
3815 *blocksizex >>= 1;
3816 else
3817 *blocksizey >>= 1;
3818 }
3819 }
3820 else
3821 {
3822 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_local_buffer_opt] can not identify resource limits for device %d\n", devid);
3823 return FALSE;
3824 }
3825
3826 return TRUE;
3827}
3828
3829
3830#endif
3831
3832// clang-format off
3833// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
3834// vim: shiftwidth=2 expandtab tabstop=2 cindent
3835// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
3836// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_bilateral_init_cl_global(void)
Definition bilateralcl.c:46
void dt_bilateral_free_cl_global(void)
void dt_develop_blend_free_cl_global(void)
Definition blend.c:1695
void dt_develop_blend_init_cl_global(void)
Definition blend.c:1664
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_colorspaces_init_cl_global(void)
Compile the colorspace kernels. Called once by common/opencl.c at device init.
void dt_colorspaces_free_cl_global(void)
Release the kernels and the struct from dt_colorspaces_init_cl_global(). NULL-safe.
const float f
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_conf_set_bool(const char *name, int val)
int dt_conf_flush(void)
Write the settings to their file now. Overridden keys keep their stored value.
int dt_conf_get_bool(const char *name)
int dt_conf_key_exists(const char *key)
Does key have a value?
gchar * dt_conf_get_string(const char *name)
Read the stored string for name as a private copy.
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
int64_t dt_conf_get_int64(const char *name)
64-bit integer for name, clamped to its declared bounds.
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
Borrow the stored string for name without copying it.
gboolean dt_conf_key_not_empty(const char *name)
void reset(dt_view_t *self)
Definition darkroom.c:1222
size_t dt_get_system_available_mem(void)
Definition darktable.c:2348
void dt_capabilities_remove(char *capability)
Definition darktable.c:2578
void dt_capabilities_add(char *capability)
Definition darktable.c:2567
dt_dlopencl_t * dt_dlopencl_init(const char *name)
Definition dlopencl.c:65
GtkWidget * preview
what the selected row actually captures
gboolean enabled
–doc was passed on the command line
static int dt_pthread_mutex_BAD_lock(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:367
static int dt_pthread_mutex_BAD_trylock(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:372
static int dt_pthread_mutex_BAD_unlock(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:377
const int res
Definition dtpthread.h:351
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:127
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 ...
Definition dtpthread.h:104
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:132
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:117
void dt_dwt_init_cl_global(void)
Definition dwt.c:548
void dt_dwt_free_cl_global(void)
Definition dwt.c:561
void dt_loc_get_user_cache_dir(char *cachedir, size_t bufsize)
void dt_loc_get_kerneldir(char *kerneldir, size_t bufsize)
const dt_collection_sort_t items[]
Definition filter.c:102
void dt_gaussian_free_cl_global(void)
Definition gaussian.c:586
void dt_gaussian_init_cl_global(void)
Definition gaussian.c:353
void dt_guided_filter_init_cl_global(void)
void dt_guided_filter_free_cl_global(void)
void dt_heal_free_cl_global(void)
Definition heal.c:456
void dt_heal_init_cl_global(void)
Definition heal.c:449
int bpp
void dt_iop_nap(int32_t usec)
Definition imageop.c:1669
void dt_interpolation_free_cl_global(void)
void dt_interpolation_init_cl_global(void)
static float kernel(const float *x, const float *y)
#define w2
Definition lmmse.c:60
#define w1
Definition lmmse.c:59
void dt_local_laplacian_init_cl_global(void)
void dt_local_laplacian_free_cl_global(void)
_lib_location_type_t type
Definition location.c:1
@ DT_DEBUG_OPENCL
Definition logging.h:57
@ DT_DEBUG_MEMORY
Definition logging.h:59
@ DT_DEBUG_PERF
Definition logging.h:55
@ DT_DEBUG_ALWAYS
Definition logging.h:49
int32_t dt_get_debug_flags(void)
Definition darktable.c:2094
void void dt_print_nts(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
dt_print() without the timestamp prefix (nts = no time stamp).
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.
void void void dt_vprint(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
dt_print() that additionally requires DT_DEBUG_VERBOSE to be enabled, i.e. both -d <channel> and -d v...
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...
Definition macros.h:96
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
char * key
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
static int dt_nvidia_gpu_supports_sm_20(const char *model)
cl_ulong dt_opencl_get_device_available(const int devid)
Definition opencl.c:3203
int dt_opencl_get_kernel_work_group_size(const int dev, const int kernel, size_t *kernelworkgroupsize)
Definition opencl.c:2591
cl_event * dt_opencl_events_get_slot(const int devid, const char *tag)
Definition opencl.c:3391
static void * _dt_opencl_alloc_image2d(const int devid, const int width, const int height, const size_t bytes, const cl_mem_flags flags, const cl_image_format fmt, void *host, const char *const context)
Definition opencl.c:2921
int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
Definition opencl.c:3786
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2612
static void dt_opencl_update_priorities()
Definition opencl.c:1893
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
Definition opencl.c:3028
const char * dt_opencl_get_device_name(const int devid)
Human-readable device name, owned by the OpenCL module.
Definition opencl.c:2050
dt_opencl_fit_reason_t dt_opencl_image_fits_device_reason(const int devid, const size_t width, const size_t height, const unsigned bpp, const float factor, const size_t overhead, size_t *needed, size_t *limit)
Definition opencl.c:3259
int dt_opencl_read_host_from_device_rowpitch(const int devid, void *host, void *device, const int width, const int height, const int rowpitch)
Definition opencl.c:2651
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)
Definition opencl.c:2975
size_t dt_opencl_get_mem_object_size(cl_mem mem)
Definition opencl.c:3034
gboolean dt_opencl_is_pinned_memory(cl_mem mem)
Definition opencl.c:238
static char * _ascii_str_canonical(const char *in, char *out, int maxlen)
Definition opencl.c:1772
int dt_opencl_enqueue_copy_buffer_to_image(const int devid, cl_mem src_buffer, cl_mem dst_image, size_t offset, size_t *origin, size_t *region)
Definition opencl.c:2760
void dt_opencl_events_reset(const int devid)
Definition opencl.c:3489
cl_int dt_opencl_events_flush(const int devid, const int reset)
Definition opencl.c:3584
void dt_opencl_note_crash_backtrace(const char *backtrace, size_t backtrace_len)
Tell the OpenCL module that the process crashed, and let it judge whether the crash was its driver's ...
Definition opencl.c:1243
int dt_opencl_copy_device_to_host(const int devid, void *host, void *device, const int width, const int height, const int bpp)
Definition opencl.c:2639
gboolean dt_opencl_read_device_config(const int devid)
Definition opencl.c:294
void dt_opencl_check_tuning(const int devid)
Definition opencl.c:3186
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2952
int dt_opencl_is_inited(void)
Definition opencl.c:3328
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2506
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2808
int dt_opencl_dev_roundup_height(int size, const int devid)
Definition opencl.c:3321
void * dt_opencl_copy_host_to_device_rowpitch(const int devid, void *host, const int width, const int height, const int bpp, const int rowpitch)
Definition opencl.c:2829
int dt_opencl_write_host_to_device_rowpitch(const int devid, void *host, void *device, const int width, const int height, const int rowpitch)
Definition opencl.c:2698
int dt_opencl_dev_roundup_width(int size, const int devid)
Definition opencl.c:3316
static const _gpu_runtime_t _gpu_runtimes[]
Definition opencl.c:1183
void dt_opencl_write_device_config(const int devid)
Definition opencl.c:244
static void dt_opencl_set_synchronization_timeout(int value)
Definition opencl.c:3372
static int dt_opencl_device_init(dt_opencl_t *cl, const int dev, cl_device_id *devices, const int k)
Definition opencl.c:532
void dt_opencl_cleanup(void)
Definition opencl.c:1642
static void _opencl_driver_crash_marker_path(char *buf, size_t buf_len)
Definition opencl.c:1234
int dt_opencl_get_mem_context_id(cl_mem mem)
Definition opencl.c:3044
int dt_opencl_write_host_to_device_non_blocking(const int devid, void *host, void *device, const int width, const int height, const int bpp)
Definition opencl.c:2708
int dt_opencl_load_program(const int dev, const int prog, const char *filename, const char *binname, const char *cachedir, char *md5sum, char **includemd5, int *loaded_cached)
Definition opencl.c:2180
static char _driver_crash_marker[DT_PATH_MAX]
Definition opencl.c:1232
void * dt_opencl_map_buffer(const int devid, cl_mem buffer, const int blocking, const int flags, size_t offset, size_t size)
Definition opencl.c:2876
static void _gpu_runtime_set_crash_streak(const char *runtime, int value)
Definition opencl.c:1221
static void dt_opencl_apply_scheduling_profile()
Definition opencl.c:3379
static int _dt_opencl_get_conf_int(const gchar *key_device, const gchar *conf_name, gboolean *safety_ok)
Definition opencl.c:277
int dt_opencl_report_pipe_error(void)
Record that a pipe run failed on OpenCL, and decide whether to give up on it.
Definition opencl.c:2093
int dt_opencl_get_image_height(cl_mem mem)
Definition opencl.c:3082
void dt_opencl_reserve_device_by_id(const int devid)
Reserve a device the caller has already identified, blocking until it is free.
Definition opencl.c:2024
size_t dt_opencl_get_device_headroom(const int devid)
Bytes of the device left to other applications (its forced_headroom, from its own config key or memor...
Definition opencl.c:2084
int dt_opencl_read_host_from_device_rowpitch_non_blocking(const int devid, void *host, void *device, const int width, const int height, const int rowpitch)
Definition opencl.c:2668
int dt_opencl_write_buffer_to_device(const int devid, void *host, void *device, const size_t offset, const size_t size, const int blocking)
Definition opencl.c:2796
int dt_opencl_micro_nap(const int devid)
Definition opencl.c:225
size_t dt_opencl_get_device_memory_in_use(const int devid)
Bytes Ansel holds on the device by its own accounting (dt_opencl_memory_statistics()),...
Definition opencl.c:2076
static cl_ulong _opencl_get_device_memalloc(const int devid)
Definition opencl.c:3248
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
Definition opencl.c:2737
static int _take_from_list(int *list, int value)
Definition opencl.c:1733
gboolean dt_opencl_get_device_max_image_size(const int devid, int *width, int *height)
Largest 2D image the device will accept, which is what bounds tile size.
Definition opencl.c:2058
int dt_opencl_set_detected_device_enabled(const int detected, const gboolean enabled)
Definition opencl.c:428
static const char * _gpu_runtime_of_platform(const char *platform_name)
Definition opencl.c:1197
int dt_opencl_try_reserve_device_by_id(const int devid)
Reserve a device only if it is free right now.
Definition opencl.c:2035
int dt_opencl_read_buffer_from_device(const int devid, void *host, void *device, const size_t offset, const size_t size, const int blocking)
Definition opencl.c:2785
int dt_opencl_build_program(const int dev, const int prog, const char *binname, const char *cachedir, char *md5sum, int loaded_cached)
Definition opencl.c:2362
int dt_opencl_get_max_work_item_sizes(const int dev, size_t *sizes)
Definition opencl.c:2563
static void _opencl_fold_driver_crashes(void)
Definition opencl.c:1273
void dt_opencl_clear_driver_crash_streak(void)
Definition opencl.c:1616
int dt_opencl_enqueue_barrier(const int devid)
Definition opencl.c:1726
static FILE * fopen_stat(const char *filename, struct stat *st)
Definition opencl.c:2107
gboolean dt_opencl_image_fits_device(const int devid, const size_t width, const size_t height, const unsigned bpp, const float factor, const size_t overhead)
Definition opencl.c:3308
static void dt_opencl_cleanup_device(dt_opencl_t *cl, int i)
Definition opencl.c:1567
int dt_opencl_unmap_mem_object(const int devid, cl_mem mem_object, void *mapped_ptr)
Definition opencl.c:2910
int dt_opencl_read_host_from_device_raw(const int devid, void *host, void *device, const size_t *origin, const size_t *region, const int rowpitch, const int blocking)
Definition opencl.c:2680
gboolean dt_opencl_detected_device_pinned_memory(const int detected)
Definition opencl.c:460
int dt_opencl_reserve_device_for_pipe(const int pipetype)
Reserve a device for a pipe run: choose a free one by the pipe's priority list and take its lock....
Definition opencl.c:1928
int dt_opencl_set_detected_device_headroom(const int detected, const size_t headroom)
Definition opencl.c:506
int dt_opencl_is_enabled(void)
Definition opencl.c:3335
void dt_opencl_memory_statistics(int devid, cl_mem mem, size_t size, dt_opencl_memory_t action)
Definition opencl.c:3111
void dt_opencl_md5sum(const char **files, char **md5sums)
Definition opencl.c:2126
static int nextpow2(int n)
Definition opencl.c:3776
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2549
gboolean dt_opencl_use_pinned_memory(const int devid)
Definition opencl.c:231
int dt_opencl_get_image_width(cl_mem mem)
Definition opencl.c:3071
cl_ulong dt_opencl_get_device_memalloc(const int devid)
Definition opencl.c:3253
static dt_opencl_t * _opencl
Definition opencl.c:131
static int _gpu_runtime_crash_streak(const char *runtime)
Definition opencl.c:1213
int dt_opencl_read_host_from_device_non_blocking(const int devid, void *host, void *device, const int width, const int height, const int bpp)
Definition opencl.c:2661
int dt_opencl_get_detected_device_count(void)
Definition opencl.c:399
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)
Definition opencl.c:2890
void * dt_opencl_alloc_device_buffer_with_flags(const int devid, const size_t size, const int flags, void *host_ptr)
Definition opencl.c:2998
int dt_opencl_write_host_to_device_rowpitch_non_blocking(const int devid, void *host, void *device, const int width, const int height, const int rowpitch)
Definition opencl.c:2714
static void dt_opencl_priority_parse(dt_opencl_t *cl, char *configstr, int *priority_list, int *mandatory)
Definition opencl.c:1798
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
Definition opencl.c:2603
gboolean dt_opencl_finish(const int devid)
Definition opencl.c:1712
int dt_opencl_enqueue_copy_image_to_buffer(const int devid, cl_mem src_image, cl_mem dst_buffer, size_t *origin, size_t *region, size_t offset)
Definition opencl.c:2748
static void _opencl_splash_update_compile(const char *programname)
Definition opencl.c:136
int dt_opencl_update_settings(void)
Definition opencl.c:3352
size_t dt_opencl_get_device_max_global_mem(const int devid)
Total device memory in bytes, or 0 for an out-of-range id.
Definition opencl.c:2068
void dt_opencl_events_wait_for(const int devid)
Definition opencl.c:3527
int dt_opencl_set_detected_device_pinned_memory(const int detected, const gboolean enabled)
Definition opencl.c:473
int dt_opencl_read_host_from_device(const int devid, void *host, void *device, const int width, const int height, const int bpp)
Definition opencl.c:2645
void dt_opencl_events_profiling(const int devid, const int aggregated)
Definition opencl.c:3687
void dt_opencl_release_device(const int devid)
Release a device reserved by either reserve function.
Definition opencl.c:2013
int dt_opencl_get_work_group_limits(const int dev, size_t *sizes, size_t *workgroupsize, unsigned long *localmemsize)
Definition opencl.c:2571
int dt_opencl_enqueue_kernel_2d_with_local(const int dev, const int kernel, const size_t *sizes, const size_t *local)
Definition opencl.c:2618
cl_mem_flags dt_opencl_get_mem_flags(cl_mem mem)
Definition opencl.c:3062
int dt_opencl_enqueue_copy_buffer_to_buffer(const int devid, cl_mem src_buffer, cl_mem dst_buffer, size_t srcoffset, size_t dstoffset, size_t size)
Definition opencl.c:2772
static int dt_opencl_get_device_info(dt_opencl_t *cl, cl_device_id device, cl_device_info param_name, void **param_value, size_t *param_value_size)
Definition opencl.c:162
const dt_opencl_detected_device_t * dt_opencl_get_detected_device(const int detected)
Definition opencl.c:407
void * dt_opencl_copy_host_to_device(const int devid, void *host, const int width, const int height, const int bpp)
Definition opencl.c:2823
int dt_opencl_write_host_to_device_raw(const int devid, const void *host, void *device, const size_t *origin, const size_t *region, const int rowpitch, const int blocking)
Definition opencl.c:2725
size_t dt_opencl_detected_device_headroom(const int detected)
Definition opencl.c:494
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2863
void dt_opencl_init(const gboolean exclude_opencl, const gboolean print_statistics)
Definition opencl.c:1301
static int _device_by_cname(const char *name)
Definition opencl.c:1750
int dt_opencl_get_image_element_size(cl_mem mem)
Definition opencl.c:3093
int dt_opencl_get_num_devices(void)
Number of usable OpenCL devices; 0 when OpenCL is unavailable.
Definition opencl.c:2043
gboolean dt_opencl_detected_device_enabled(const int detected)
Definition opencl.c:415
static const char * dt_opencl_get_vendor_by_id(unsigned int id)
Definition opencl.c:1690
gboolean dt_opencl_get_mem_record(cl_mem mem, int *devid, size_t *size)
Definition opencl.c:3171
int dt_opencl_avoid_atomics(const int devid)
Definition opencl.c:219
int dt_opencl_write_host_to_device(const int devid, void *host, void *device, const int width, const int height, const int bpp)
Definition opencl.c:2692
void dt_opencl_disable(void)
Definition opencl.c:3343
#define DT_OPENCL_MAX_INCLUDES
Definition opencl.h:54
dt_opencl_memory_t
Definition opencl.h:142
@ OPENCL_MEMORY_ADD
Definition opencl.h:143
@ OPENCL_MEMORY_SUB
Definition opencl.h:144
#define DT_OPENCL_EVENTLISTSIZE
Definition opencl.h:48
#define DT_OPENCL_BPP_DECODE(bpp)
Definition opencl.h:91
@ DT_OPENCL_PINNING_DISABLED
Definition opencl.h:161
@ DT_OPENCL_PINNING_OFF
Definition opencl.h:159
@ DT_OPENCL_PINNING_ON
Definition opencl.h:160
dt_opencl_fit_reason_t
Definition opencl.h:169
@ DT_OPENCL_FIT_ALLOC_LIMIT
Definition opencl.h:172
@ DT_OPENCL_FIT_AVAILABLE
Definition opencl.h:173
@ DT_OPENCL_FIT_DIMENSION
Definition opencl.h:171
@ DT_OPENCL_FIT_UNINITED
Definition opencl.h:174
@ DT_OPENCL_FIT_OK
Definition opencl.h:170
#define DT_OPENCL_DEFAULT_COMPILE
Definition opencl.h:138
#define DT_OPENCL_DEFAULT_COMPILE_INTEL
Definition opencl.h:135
#define DT_OPENCL_MAX_ERRORS
Definition opencl.h:50
#define DT_OPENCL_BPP_IS_RGBA8(bpp)
Definition opencl.h:90
#define DT_OPENCL_CBUFFSIZE
Definition opencl.h:58
#define DT_OPENCL_EVENTNAMELENGTH
Definition opencl.h:49
#define DT_OPENCL_VENDOR_INTEL
Definition opencl.h:57
#define DT_OPENCL_MAX_PROGRAMS
Definition opencl.h:46
#define DT_OPENCL_MAX_PLATFORMS
Definition opencl.h:45
#define DT_CLDEVICE_HEAD
Definition opencl.h:139
#define DT_OPENCL_DEFAULT_COMPILE_AMD
Definition opencl.h:136
#define DT_OPENCL_DEFAULT_COMPILE_NVIDIA
Definition opencl.h:137
#define DT_OPENCL_VENDOR_NVIDIA
Definition opencl.h:56
#define DT_OPENCL_VENDOR_AMD
Definition opencl.h:55
#define DT_OPENCL_MAX_KERNELS
Definition opencl.h:47
static gboolean dt_opencl_check_driver_blacklist(const char *device_version)
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
void dt_concat_path_file(char destination[4096], const char path[4096], const char *const file)
Append a constant filename to a variable, stack-based, fixed-sized, directory, and add a / in-between...
Definition darktable.c:2683
const float factor
Definition pdf.h:91
const char * name
Definition pdf.h:90
@ DT_DEV_PIXELPIPE_THUMBNAIL
Definition pixelpipe.h:45
@ DT_DEV_PIXELPIPE_EXPORT
Definition pixelpipe.h:42
@ DT_DEV_PIXELPIPE_PREVIEW
Definition pixelpipe.h:44
@ DT_DEV_PIXELPIPE_FULL
Definition pixelpipe.h:43
void dt_dev_pixelpipe_cache_flush_clmem(const int devid)
Release cached OpenCL buffers for a single device.
Pixelpipe cache for storing intermediate results in the pixelpipe.
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
void dt_startup_progress_report(const char *format,...)
unsigned __int64 uint64_t
Definition strptime.c:75
const char *const char * platform
Definition opencl.c:1179
const char * conf_suffix
Definition opencl.c:1180
dt_clEnqueueReadImage_t dt_clEnqueueReadImage
Definition dlopencl.h:211
dt_clGetEventInfo_t dt_clGetEventInfo
Definition dlopencl.h:196
dt_clReleaseCommandQueue_t dt_clReleaseCommandQueue
Definition dlopencl.h:163
dt_clEnqueueUnmapMemObject_t dt_clEnqueueUnmapMemObject
Definition dlopencl.h:218
dt_clGetKernelInfo_t dt_clGetKernelInfo
Definition dlopencl.h:193
dt_clGetEventProfilingInfo_t dt_clGetEventProfilingInfo
Definition dlopencl.h:202
dt_clCreateCommandQueue_t dt_clCreateCommandQueue
Definition dlopencl.h:161
dt_clCreateImage2D_t dt_clCreateImage2D
Definition dlopencl.h:168
dt_clEnqueueCopyBuffer_t dt_clEnqueueCopyBuffer
Definition dlopencl.h:209
dt_clGetPlatformInfo_t dt_clGetPlatformInfo
Definition dlopencl.h:153
dt_clBuildProgram_t dt_clBuildProgram
Definition dlopencl.h:184
dt_clEnqueueWriteBuffer_t dt_clEnqueueWriteBuffer
Definition dlopencl.h:207
dt_clCreateContext_t dt_clCreateContext
Definition dlopencl.h:156
dt_clGetDeviceIDs_t dt_clGetDeviceIDs
Definition dlopencl.h:154
dt_clGetMemObjectInfo_t dt_clGetMemObjectInfo
Definition dlopencl.h:173
dt_clEnqueueCopyImage_t dt_clEnqueueCopyImage
Definition dlopencl.h:213
dt_clReleaseContext_t dt_clReleaseContext
Definition dlopencl.h:159
dt_clFinish_t dt_clFinish
Definition dlopencl.h:204
dt_clGetDeviceInfo_t dt_clGetDeviceInfo
Definition dlopencl.h:155
dt_clEnqueueCopyImageToBuffer_t dt_clEnqueueCopyImageToBuffer
Definition dlopencl.h:214
dt_clGetImageInfo_t dt_clGetImageInfo
Definition dlopencl.h:174
dt_clCreateBuffer_t dt_clCreateBuffer
Definition dlopencl.h:166
dt_clCreateProgramWithBinary_t dt_clCreateProgramWithBinary
Definition dlopencl.h:181
dt_clReleaseKernel_t dt_clReleaseKernel
Definition dlopencl.h:191
dt_clEnqueueWriteImage_t dt_clEnqueueWriteImage
Definition dlopencl.h:212
dt_clSetKernelArg_t dt_clSetKernelArg
Definition dlopencl.h:192
dt_clReleaseEvent_t dt_clReleaseEvent
Definition dlopencl.h:199
dt_clEnqueueMapImage_t dt_clEnqueueMapImage
Definition dlopencl.h:217
dt_clEnqueueBarrier_t dt_clEnqueueBarrier
Definition dlopencl.h:224
dt_clGetPlatformIDs_t dt_clGetPlatformIDs
Definition dlopencl.h:152
dt_clGetProgramInfo_t dt_clGetProgramInfo
Definition dlopencl.h:186
dt_clGetKernelWorkGroupInfo_t dt_clGetKernelWorkGroupInfo
Definition dlopencl.h:194
dt_clReleaseMemObject_t dt_clReleaseMemObject
Definition dlopencl.h:171
dt_clGetProgramBuildInfo_t dt_clGetProgramBuildInfo
Definition dlopencl.h:187
dt_clReleaseProgram_t dt_clReleaseProgram
Definition dlopencl.h:183
dt_clEnqueueNDRangeKernel_t dt_clEnqueueNDRangeKernel
Definition dlopencl.h:219
dt_clWaitForEvents_t dt_clWaitForEvents
Definition dlopencl.h:195
dt_clEnqueueReadBuffer_t dt_clEnqueueReadBuffer
Definition dlopencl.h:205
dt_clEnqueueCopyBufferToImage_t dt_clEnqueueCopyBufferToImage
Definition dlopencl.h:215
dt_clEnqueueMapBuffer_t dt_clEnqueueMapBuffer
Definition dlopencl.h:216
dt_clCreateKernel_t dt_clCreateKernel
Definition dlopencl.h:188
dt_clCreateProgramWithSource_t dt_clCreateProgramWithSource
Definition dlopencl.h:180
dt_dlopencl_symbols_t * symbols
Definition dlopencl.h:232
char * library
Definition dlopencl.h:233
size_t forced_headroom
Definition opencl.h:283
gboolean host_unified_memory
Definition opencl.h:279
unsigned int cltype
Definition opencl.h:256
const char * runtime_id
Definition opencl.h:216
const char * name
Definition opencl.h:217
size_t used_available
Definition opencl.h:224
cl_event * eventlist
Definition opencl.h:196
cl_command_queue cmd_queue
Definition opencl.h:186
cl_context context
Definition opencl.h:185
const char * options_md5
Definition opencl.h:220
cl_ulong max_mem_alloc
Definition opencl.h:189
cl_ulong max_global_mem
Definition opencl.h:190
size_t max_image_width
Definition opencl.h:187
cl_ulong used_global_mem
Definition opencl.h:191
cl_device_id devid
Definition opencl.h:184
int program_used[256]
Definition opencl.h:194
dt_pthread_mutex_t lock
Definition opencl.h:183
size_t peak_memory
Definition opencl.h:223
cl_kernel kernel[512]
Definition opencl.h:193
int kernel_used[512]
Definition opencl.h:195
size_t max_image_height
Definition opencl.h:188
cl_program program[256]
Definition opencl.h:192
size_t memory_in_use
Definition opencl.h:222
const char * vendor
Definition opencl.h:207
dt_opencl_eventtag_t * eventtags
Definition opencl.h:197
const char * options
Definition opencl.h:219
unsigned int vendor_id
Definition opencl.h:210
const char * cname
Definition opencl.h:218
const size_t cellsize
Definition opencl.h:330
const size_t overhead
Definition opencl.h:331
int num_devs
Definition opencl.c:97
int print_statistics
Definition opencl.c:94
int * dev_priority_image
Definition opencl.c:103
int error_count
Definition opencl.c:99
int opencl_synchronization_timeout
Definition opencl.c:100
int * dev_priority_preview
Definition opencl.c:104
dt_opencl_device_t * dev
Definition opencl.c:107
GHashTable * mem_sizes
Definition opencl.c:121
int stopped
Definition opencl.c:96
int enabled
Definition opencl.c:95
int mandatory[5]
Definition opencl.c:102
dt_pthread_mutex_t lock
Definition opencl.c:92
int * dev_priority_export
Definition opencl.c:105
int inited
Definition opencl.c:93
dt_pthread_mutex_t mem_sizes_lock
Definition opencl.c:122
dt_opencl_detected_device_t * detected_devs
Definition opencl.c:108
dt_dlopencl_t * dlocl
Definition opencl.c:109
int num_detected_devs
Definition opencl.c:98
int * dev_priority_thumbnail
Definition opencl.c:106
uint32_t crc
Definition opencl.c:101
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
static double dt_get_wtime(void)
Definition times.h:43
gchar * dt_util_str_replace(const gchar *string, const gchar *pattern, const gchar *substitute)
Definition utility.c:163