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.
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_*(). */
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
163 size_t *param_value_size)
164{
166
167 // 1. figure out how much memory is needed
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?
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",
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",
196 goto error;
197 }
198
199 // allocation succeeded, update pointer.
200 *param_value = ptr;
201 }
202
203 // 4. actually get the value
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:
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{
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);
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);
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);
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 }
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);
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
414
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
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
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
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
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
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);
516
517 dt_opencl_t *cl = _opencl;
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;
526 dt_opencl_check_tuning(device->config_id);
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;
599 cl_uint vendor_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:
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;
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
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
646 cname = malloc(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
655 if(err != CL_SUCCESS)
656 {
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 {
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);
668 }
669
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);
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
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
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
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);
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
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
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
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. */
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. */
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,
810 cl->dev[dev].disabled |= 1;
811 res = -1;
812 goto end;
813 }
814
816
817 // disable device for now if this is the first time detected and blacklisted too.
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);
833 dt_print_nts(DT_DEBUG_OPENCL, " MAX WORK GROUP SIZE: %" G_GSIZE_FORMAT "\n", infoint);
835 dt_print_nts(DT_DEBUG_OPENCL, " MAX WORK ITEM DIMENSIONS: %" G_GSIZE_FORMAT "\n", infoint);
836
837 size_t 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]);
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
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
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
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;
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++)
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
955 else
956 {
957 switch(vendor_id)
958 {
961 break;
964 break;
967 break;
968 default:
970 }
971 }
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" : ""),
979 // Keep kernel checksum stable when the runtime kernel path changes (e.g. AppImage mount point).
980 const char *kerneldir_token = "<ansel-kernels>";
982#ifndef __APPLE__
984#else
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" : ""),
991
992 dt_print_nts(DT_DEBUG_OPENCL, " CL COMPILER OPTION: %s\n", my_option);
993
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 };
1007
1008 if(newdevice) // so far the device seems to be ok. Make sure to write&export the conf database to
1009 {
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);
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
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);
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)
1072
1074 {
1075 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_device_init] failed to compile program `%s'!\n", programname);
1076 fclose(f);
1078 res = -1;
1079 goto end;
1080 }
1081 }
1082
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 {
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
1127 dt_free(cname);
1128 dt_free(vendor);
1131
1133 dt_free(cachedir);
1138
1139 dt_free(filename);
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
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);
1207 g_free(needle);
1208 }
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
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++)
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;
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 }
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;
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
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;
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)
1408 if(err != CL_SUCCESS)
1409 {
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 {
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);
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];
1466 NULL);
1467 if(err != CL_SUCCESS)
1468 {
1470 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_init] could not get devices list: %i\n", err);
1471 }
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 {
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 }
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
1557
1558 if(locale)
1559 {
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);
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
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]);
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 {
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
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
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) return 2;
2080
2081 cl->error_count++;
2082 if(cl->error_count < DT_OPENCL_MAX_ERRORS) return 1;
2083
2084 /* Too many failures: OpenCL is finished for this session. */
2085 cl->stopped = 1;
2086 dt_capabilities_remove("opencl");
2087 return 2;
2088}
2089
2090static FILE *fopen_stat(const char *filename, struct stat *st)
2091{
2092 FILE *f = g_fopen(filename, "rb");
2093 if(IS_NULL_PTR(f))
2094 {
2095 dt_print(DT_DEBUG_OPENCL, "[opencl_fopen_stat] could not open file `%s'!\n", filename);
2096 return NULL;
2097 }
2098 int fd = fileno(f);
2099 if(fstat(fd, st) < 0)
2100 {
2101 dt_print(DT_DEBUG_OPENCL, "[opencl_fopen_stat] could not stat file `%s'!\n", filename);
2102 fclose(f); // the open succeeded; only the stat failed, and the handle is still ours
2103 return NULL;
2104 }
2105 return f;
2106}
2107
2108
2109void dt_opencl_md5sum(const char **files, char **md5sums)
2110{
2111 char kerneldir[DT_PATH_MAX] = { 0 };
2112 char filename[DT_PATH_MAX] = { 0 };
2113 dt_loc_get_kerneldir(kerneldir, sizeof(kerneldir));
2114
2115 for(int n = 0; n < DT_OPENCL_MAX_INCLUDES; n++, files++, md5sums++)
2116 {
2117 if(!*files)
2118 {
2119 *md5sums = NULL;
2120 continue;
2121 }
2122
2123 dt_concat_path_file(filename, kerneldir, *files);
2124
2125 struct stat filestat;
2126 FILE *f = fopen_stat(filename, &filestat);
2127
2128 if(IS_NULL_PTR(f))
2129 {
2130 dt_print(DT_DEBUG_OPENCL, "[opencl_md5sums] could not open file `%s'!\n", filename);
2131 *md5sums = NULL;
2132 continue;
2133 }
2134
2135 size_t filesize = filestat.st_size;
2136 char *file = (char *)malloc(filesize);
2137
2138 if(IS_NULL_PTR(file))
2139 {
2140 dt_print(DT_DEBUG_OPENCL, "[opencl_md5sums] could not allocate buffer for file `%s'!\n", filename);
2141 *md5sums = NULL;
2142 fclose(f);
2143 continue;
2144 }
2145
2146 size_t rd = fread(file, sizeof(char), filesize, f);
2147 fclose(f);
2148
2149 if(rd != filesize)
2150 {
2151 dt_free(file);
2152 dt_print(DT_DEBUG_OPENCL, "[opencl_md5sums] could not read all of file `%s'!\n", filename);
2153 *md5sums = NULL;
2154 continue;
2155 }
2156
2158
2159 dt_free(file);
2160 }
2161}
2162
2163int dt_opencl_load_program(const int dev, const int prog, const char *filename, const char *binname,
2164 const char *cachedir, char *md5sum, char **includemd5, int *loaded_cached)
2165{
2166 cl_int err;
2167 dt_opencl_t *cl = _opencl;
2168
2169 struct stat filestat, cachedstat;
2170 *loaded_cached = 0;
2171
2173 {
2174 dt_print(DT_DEBUG_OPENCL, "[opencl_load_source] invalid program number `%d' of file `%s'!\n", prog,
2175 filename);
2176 return 0;
2177 }
2178
2179 if(cl->dev[dev].program_used[prog])
2180 {
2182 "[opencl_load_source] program number `%d' already in use when loading file `%s'!\n", prog,
2183 filename);
2184 return 0;
2185 }
2186
2187 FILE *f = fopen_stat(filename, &filestat);
2188 if(IS_NULL_PTR(f)) return 0;
2189
2190 size_t filesize = filestat.st_size;
2191 char *file = (char *)malloc(filesize + 2048);
2192 size_t rd = fread(file, sizeof(char), filesize, f);
2193 fclose(f);
2194 if(rd != filesize)
2195 {
2196 dt_free(file);
2197 dt_print(DT_DEBUG_OPENCL, "[opencl_load_source] could not read all of file `%s'!\n", filename);
2198 return 0;
2199 }
2200
2201 char *start = file + filesize;
2202 char *end = start + 2048;
2203 size_t len;
2204
2205 cl_device_id devid = cl->dev[dev].devid;
2206 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DRIVER_VERSION, end - start, start, &len);
2207 start += len;
2208
2209 cl_platform_id platform;
2210 (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &platform, NULL);
2211
2212 (cl->dlocl->symbols->dt_clGetPlatformInfo)(platform, CL_PLATFORM_VERSION, end - start, start, &len);
2213 start += len;
2214
2215 const char *options_md5 = cl->dev[dev].options_md5 ? cl->dev[dev].options_md5 : cl->dev[dev].options;
2216 len = g_strlcpy(start, options_md5, end - start);
2217 start += len;
2218
2219 /* make sure that the md5sums of all the includes are applied as well */
2220 for(int n = 0; n < DT_OPENCL_MAX_INCLUDES; n++)
2221 {
2222 if(!includemd5[n]) continue;
2223 len = g_strlcpy(start, includemd5[n], end - start);
2224 start += len;
2225 }
2226
2227 char *source_md5 = g_compute_checksum_for_data(G_CHECKSUM_MD5, (guchar *)file, start - file);
2230
2231 file[filesize] = '\0';
2232
2233 char linkedfile[DT_PATH_MAX] = { 0 };
2235
2236#if defined(_WIN32)
2237 // No symlinks on Windows
2238 // Have to figure out the name using the filename + md5sum
2239 char dup[DT_PATH_MAX] = { 0 };
2240 snprintf(dup, sizeof(dup), "%s.%s", binname, md5sum);
2244#else
2246#endif
2247
2248 if(cached)
2249 {
2250#if !defined(_WIN32)
2252#endif // !defined(_WIN32)
2253 if(linkedfile_len > 0)
2254 {
2255 linkedfile[linkedfile_len] = '\0';
2256
2257 if(strncmp(linkedfile, md5sum, 33) == 0)
2258 {
2259 // md5sum matches, load cached binary
2260 size_t cached_filesize = cachedstat.st_size;
2261
2262 unsigned char *cached_content = (unsigned char *)malloc(cached_filesize + 1);
2264 {
2266 "[opencl_load_program] could not allocate %zu bytes for cached binary '%s'!\n",
2268 fclose(cached);
2269 return 0;
2270 }
2271 rd = fread(cached_content, sizeof(char), cached_filesize, cached);
2272 if(rd != cached_filesize)
2273 {
2274 dt_print(DT_DEBUG_OPENCL, "[opencl_load_program] could not read all of file '%s' MD5: %s!\n", binname, md5sum);
2275 }
2276 else
2277 {
2279 cl->dev[dev].context, 1, &(cl->dev[dev].devid), &cached_filesize,
2280 (const unsigned char **)&cached_content, NULL, &err);
2281 if(err != CL_SUCCESS)
2282 {
2284 "[opencl_load_program] could not load cached binary program from file '%s' MD5: '%s'! (%i)\n",
2285 binname, md5sum, err);
2286 }
2287 else
2288 {
2289 cl->dev[dev].program_used[prog] = 1;
2290 *loaded_cached = 1;
2291 }
2292 }
2294 }
2295 }
2296 fclose(cached);
2297 }
2298
2299
2300 if(*loaded_cached == 0)
2301 {
2302 // if loading cached was unsuccessful for whatever reason,
2303 // try to remove cached binary & link
2304#if !defined(_WIN32)
2305 if(linkedfile_len > 0)
2306 {
2307 char link_dest[DT_PATH_MAX] = { 0 };
2310 }
2312#else
2313 // delete the file which contains the MD5 name
2314 g_unlink(dup);
2315#endif
2316
2318 "[opencl_load_program] could not load cached binary program, trying to compile source\n");
2319
2321 cl->dev[dev].context, 1, (const char **)&file, &filesize, &err);
2322 dt_free(file);
2323 if((err != CL_SUCCESS) || (cl->dev[dev].program[prog] == NULL))
2324 {
2325 dt_print(DT_DEBUG_OPENCL, "[opencl_load_source] could not create program from file `%s'! (%i)\n",
2326 filename, err);
2327 return 0;
2328 }
2329 else
2330 {
2331 cl->dev[dev].program_used[prog] = 1;
2332 }
2333 }
2334 else
2335 {
2336 dt_free(file);
2337 dt_vprint(DT_DEBUG_OPENCL, "[opencl_load_program] loaded cached binary program from file '%s' MD5: '%s' \n", binname, md5sum);
2338 }
2339
2340 dt_vprint(DT_DEBUG_OPENCL, "[opencl_load_program] successfully loaded program from '%s' MD5: '%s'\n", filename, md5sum);
2341
2342 return 1;
2343}
2344
2345int dt_opencl_build_program(const int dev, const int prog, const char *binname, const char *cachedir,
2346 char *md5sum, int loaded_cached)
2347{
2349 dt_opencl_t *cl = _opencl;
2350 cl_program program = cl->dev[dev].program[prog];
2351 cl_int err = (cl->dlocl->symbols->dt_clBuildProgram)(program, 1, &(cl->dev[dev].devid), cl->dev[dev].options, 0, 0);
2352
2353 if(err != CL_SUCCESS)
2354 dt_print(DT_DEBUG_OPENCL, "[opencl_build_program] could not build program: %i\n", err);
2355 else
2356 dt_vprint(DT_DEBUG_OPENCL, "[opencl_build_program] successfully built program\n");
2357
2360 sizeof(cl_build_status), &build_status, NULL);
2361 dt_vprint(DT_DEBUG_OPENCL, "[opencl_build_program] BUILD STATUS: %d\n", build_status);
2362
2363 char *build_log;
2364 size_t ret_val_size;
2366 &ret_val_size);
2367 if(ret_val_size != SIZE_MAX)
2368 {
2369 build_log = (char *)malloc(sizeof(char) * (ret_val_size + 1));
2370 if(build_log)
2371 {
2374
2375 build_log[ret_val_size] = '\0';
2376
2377 dt_vprint(DT_DEBUG_OPENCL, "BUILD LOG:\n");
2379
2381 }
2382 }
2383
2384 if(err != CL_SUCCESS)
2385 return err;
2386 else
2387 {
2388 if(!loaded_cached)
2389 {
2390 dt_vprint(DT_DEBUG_OPENCL, "[opencl_build_program] saving binary\n");
2391
2392 cl_uint numdev = 0;
2394 &numdev, NULL);
2395 if(err != CL_SUCCESS)
2396 {
2397 dt_print(DT_DEBUG_OPENCL, "[opencl_build_program] CL_PROGRAM_NUM_DEVICES failed: %i\n", err);
2398 return CL_SUCCESS;
2399 }
2400
2401 cl_device_id *devices = malloc(sizeof(cl_device_id) * numdev);
2403 sizeof(cl_device_id) * numdev, devices, NULL);
2404 if(err != CL_SUCCESS)
2405 {
2406 dt_print(DT_DEBUG_OPENCL, "[opencl_build_program] CL_PROGRAM_DEVICES failed: %i\n", err);
2408 return CL_SUCCESS;
2409 }
2410
2411 size_t *binary_sizes = malloc(sizeof(size_t) * numdev);
2413 sizeof(size_t) * numdev, binary_sizes, NULL);
2414 if(err != CL_SUCCESS)
2415 {
2416 dt_print(DT_DEBUG_OPENCL, "[opencl_build_program] CL_PROGRAM_BINARY_SIZES failed: %i\n", err);
2419 return CL_SUCCESS;
2420 }
2421
2422 unsigned char **binaries = malloc(sizeof(unsigned char *) * numdev);
2423 for(int i = 0; i < numdev; i++) binaries[i] = (unsigned char *)malloc(binary_sizes[i]);
2425 sizeof(unsigned char *) * numdev, binaries, NULL);
2426 if(err != CL_SUCCESS)
2427 {
2428 dt_print(DT_DEBUG_OPENCL, "[opencl_build_program] CL_PROGRAM_BINARIES failed: %i\n", err);
2429 goto ret;
2430 }
2431
2432 for(int i = 0; i < numdev; i++)
2433 if(cl->dev[dev].devid == devices[i])
2434 {
2435 // save opencl compiled binary as md5sum-named file
2436 char link_dest[DT_PATH_MAX] = { 0 };
2437 snprintf(link_dest, sizeof(link_dest), "%s" G_DIR_SEPARATOR_S "%s", cachedir, md5sum);
2438 FILE *f = g_fopen(link_dest, "wb");
2439 if(IS_NULL_PTR(f)) goto ret;
2440 const size_t bytes_written = fwrite(binaries[i], sizeof(char), binary_sizes[i], f);
2441 fclose(f);
2442 if(bytes_written != binary_sizes[i]) goto ret;
2443
2444 /* Name the binary after the program (e.g. basic.cl.bin), pointing at the
2445 * md5sum-named file we just wrote.
2446 *
2447 * This used to chdir() into cachedir so it could name the link by its basename
2448 * alone, and chdir() back afterwards. Two things were wrong with that. The
2449 * working directory is process-global state, and this runs on whichever thread
2450 * is building kernels while the rest of the application is live; and the
2451 * restoring chdir() sat AFTER two `goto ret' paths, so any failure in between
2452 * left the whole process parked in the kernel cache directory for the rest of
2453 * the session. Neither is needed: only the LINK path has to be absolute, while
2454 * the symlink target stays relative -- which is what the chdir was buying. */
2456 char link_name[DT_PATH_MAX] = { 0 };
2457 snprintf(link_name, sizeof(link_name), "%s" G_DIR_SEPARATOR_S "%s", cachedir, bname);
2458#if defined(_WIN32)
2459 /* CreateSymbolicLink() needs admin privileges on Windows, which we neither
2460 * want nor need, so the cached binary is simply renamed into place. */
2461 char final_name[DT_PATH_MAX] = { 0 };
2462 snprintf(final_name, sizeof(final_name), "%s.%s", link_name, md5sum);
2463 const int link_failed = (g_rename(link_dest, final_name) != 0);
2464#else
2465 /* Relative target, absolute link path: the link keeps working if the cache
2466 * directory is ever moved, and we never touch the working directory. */
2468 const int link_failed = (symlink(md5sum, link_name) != 0);
2469#endif
2470 g_free(bname);
2471 if(link_failed)
2472 {
2473 dt_print(DT_DEBUG_OPENCL, "[opencl_build_program] could not name the cached binary `%s': %s\n",
2475 goto ret;
2476 }
2477 }
2478
2479 ret:
2480 for(int i = 0; i < numdev; i++) dt_free(binaries[i]);
2484 }
2485 return CL_SUCCESS;
2486 }
2487}
2488
2489int dt_opencl_create_kernel(const int prog, const char *name)
2490{
2491 dt_opencl_t *cl = _opencl;
2492 if(!cl->inited) return -1;
2495 int k = 0;
2496 for(int dev = 0; dev < cl->num_devs; dev++)
2497 {
2498 cl_int err;
2499 for(; k < DT_OPENCL_MAX_KERNELS; k++)
2500 if(!cl->dev[dev].kernel_used[k])
2501 {
2502 cl->dev[dev].kernel_used[k] = 1;
2503 cl->dev[dev].kernel[k]
2504 = (cl->dlocl->symbols->dt_clCreateKernel)(cl->dev[dev].program[prog], name, &err);
2505 if(err != CL_SUCCESS)
2506 {
2507 dt_print(DT_DEBUG_OPENCL, "[opencl_create_kernel] could not create kernel `%s'! (%i)\n", name, err);
2508 cl->dev[dev].kernel_used[k] = 0;
2509 goto error;
2510 }
2511 else
2512 break;
2513 }
2515 {
2516 dt_vprint(DT_DEBUG_OPENCL, "[opencl_create_kernel] successfully loaded kernel `%s' (%d) for device %d\n",
2517 name, k, dev);
2518 }
2519 else
2520 {
2521 dt_print(DT_DEBUG_OPENCL, "[opencl_create_kernel] too many kernels! can't create kernel `%s'\n", name);
2522 goto error;
2523 }
2524 }
2526 return k;
2527error:
2529 return -1;
2530}
2531
2533{
2534 dt_opencl_t *cl = _opencl;
2535 if(!cl->inited) return;
2538 for(int dev = 0; dev < cl->num_devs; dev++)
2539 {
2540 cl->dev[dev].kernel_used[kernel] = 0;
2541 (cl->dlocl->symbols->dt_clReleaseKernel)(cl->dev[dev].kernel[kernel]);
2542 }
2544}
2545
2546int dt_opencl_get_max_work_item_sizes(const int dev, size_t *sizes)
2547{
2548 dt_opencl_t *cl = _opencl;
2549 if(!cl->inited || dev < 0) return -1;
2551 sizeof(size_t) * 3, sizes, NULL);
2552}
2553
2554int dt_opencl_get_work_group_limits(const int dev, size_t *sizes, size_t *workgroupsize,
2555 unsigned long *localmemsize)
2556{
2557 dt_opencl_t *cl = _opencl;
2558 if(!cl->inited || dev < 0) return -1;
2559 cl_ulong lmemsize;
2561 sizeof(cl_ulong), &lmemsize, NULL);
2562 if(err != CL_SUCCESS) return err;
2563
2565
2567 sizeof(size_t), workgroupsize, NULL);
2568 if(err != CL_SUCCESS) return err;
2569
2571}
2572
2573
2575{
2576 dt_opencl_t *cl = _opencl;
2577 if(!cl->inited || dev < 0) return -1;
2579
2580 return (cl->dlocl->symbols->dt_clGetKernelWorkGroupInfo)(cl->dev[dev].kernel[kernel], cl->dev[dev].devid,
2581 CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t),
2583}
2584
2585
2586int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size,
2587 const void *arg)
2588{
2589 dt_opencl_t *cl = _opencl;
2590 if(!cl->inited || dev < 0) return -1;
2592 return (cl->dlocl->symbols->dt_clSetKernelArg)(cl->dev[dev].kernel[kernel], num, size, arg);
2593}
2594
2595int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
2596{
2598}
2599
2600
2601int dt_opencl_enqueue_kernel_2d_with_local(const int dev, const int kernel, const size_t *sizes,
2602 const size_t *local)
2603{
2604 dt_opencl_t *cl = _opencl;
2605 if(!cl->inited || dev < 0) return -1;
2607
2608 char buf[256];
2609 buf[0] = '\0';
2613 cl_int err = (cl->dlocl->symbols->dt_clEnqueueNDRangeKernel)(cl->dev[dev].cmd_queue, cl->dev[dev].kernel[kernel],
2614 2, NULL, sizes, local, 0, NULL, eventp);
2615
2616 if(err != CL_SUCCESS)
2617 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_enqueue_kernel_2d_with_local] kernel %i (%s) on device %d: %i\n", kernel, buf, dev, err);
2618
2619 return err;
2620}
2621
2622int dt_opencl_copy_device_to_host(const int devid, void *host, void *device, const int width,
2623 const int height, const int bpp)
2624{
2626}
2627
2628int dt_opencl_read_host_from_device(const int devid, void *host, void *device, const int width,
2629 const int height, const int bpp)
2630{
2632}
2633
2634int dt_opencl_read_host_from_device_rowpitch(const int devid, void *host, void *device, const int width,
2635 const int height, const int rowpitch)
2636{
2637 if(!(_opencl && _opencl->inited) || devid < 0) return -1;
2638 const size_t origin[] = { 0, 0, 0 };
2639 const size_t region[] = { width, height, 1 };
2640 // blocking.
2642}
2643
2644int dt_opencl_read_host_from_device_non_blocking(const int devid, void *host, void *device, const int width,
2645 const int height, const int bpp)
2646{
2648 bpp * width);
2649}
2650
2652 const int width, const int height,
2653 const int rowpitch)
2654{
2655 if(!(_opencl && _opencl->inited) || devid < 0) return -1;
2656 const size_t origin[] = { 0, 0, 0 };
2657 const size_t region[] = { width, height, 1 };
2658 // non-blocking.
2660}
2661
2662
2663int dt_opencl_read_host_from_device_raw(const int devid, void *host, void *device, const size_t *origin,
2664 const size_t *region, const int rowpitch, const int blocking)
2665{
2666 if(!(_opencl && _opencl->inited)) return -1;
2667
2668 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Read Image (from device to host)]");
2669
2672 0, host, 0, NULL, eventp);
2673}
2674
2675int dt_opencl_write_host_to_device(const int devid, void *host, void *device, const int width,
2676 const int height, const int bpp)
2677{
2679}
2680
2681int dt_opencl_write_host_to_device_rowpitch(const int devid, void *host, void *device, const int width,
2682 const int height, const int rowpitch)
2683{
2684 if(!(_opencl && _opencl->inited) || devid < 0) return -1;
2685 const size_t origin[] = { 0, 0, 0 };
2686 const size_t region[] = { width, height, 1 };
2687 // blocking.
2689}
2690
2691int dt_opencl_write_host_to_device_non_blocking(const int devid, void *host, void *device, const int width,
2692 const int height, const int bpp)
2693{
2695}
2696
2698 const int width, const int height,
2699 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 // non-blocking.
2706}
2707
2708int dt_opencl_write_host_to_device_raw(const int devid, const void *host, void *device, const size_t *origin,
2709 const size_t *region, const int rowpitch, const int blocking)
2710{
2711 if(!(_opencl && _opencl->inited)) return -1;
2712
2713 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Write Image (from host to device)]");
2714
2716 device, blocking ? CL_TRUE : CL_FALSE, origin, region,
2717 rowpitch, 0, host, 0, NULL, eventp);
2718}
2719
2720int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst,
2721 size_t *region)
2722{
2723 if(!(_opencl && _opencl->inited) || devid < 0) return -1;
2724 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Copy Image (on device)]");
2726 _opencl->dev[devid].cmd_queue, src, dst, orig_src, orig_dst, region, 0, NULL, eventp);
2727 if(err != CL_SUCCESS) dt_print(DT_DEBUG_OPENCL, "[opencl copy_image] could not copy image on device %d: %i\n", devid, err);
2728 return err;
2729}
2730
2732 size_t *origin, size_t *region, size_t offset)
2733{
2734 if(!(_opencl && _opencl->inited)) return -1;
2735 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Copy Image to Buffer (on device)]");
2737 _opencl->dev[devid].cmd_queue, src_image, dst_buffer, origin, region, offset, 0, NULL, eventp);
2738 if(err != CL_SUCCESS)
2739 dt_print(DT_DEBUG_OPENCL, "[opencl copy_image_to_buffer] could not copy image on device %d: %i\n", devid, err);
2740 return err;
2741}
2742
2744 size_t offset, size_t *origin, size_t *region)
2745{
2746 if(!(_opencl && _opencl->inited)) return -1;
2747 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Copy Buffer to Image (on device)]");
2749 _opencl->dev[devid].cmd_queue, src_buffer, dst_image, offset, origin, region, 0, NULL, eventp);
2750 if(err != CL_SUCCESS)
2751 dt_print(DT_DEBUG_OPENCL, "[opencl copy_buffer_to_image] could not copy buffer on device %d: %i\n", devid, err);
2752 return err;
2753}
2754
2756 size_t srcoffset, size_t dstoffset, size_t size)
2757{
2758 if(!(_opencl && _opencl->inited)) return -1;
2759 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Copy Buffer to Buffer (on device)]");
2762 dstoffset, size, 0, NULL, eventp);
2763 if(err != CL_SUCCESS)
2764 dt_print(DT_DEBUG_OPENCL, "[opencl copy_buffer_to_buffer] could not copy buffer on device %d: %i\n", devid, err);
2765 return err;
2766}
2767
2768int dt_opencl_read_buffer_from_device(const int devid, void *host, void *device, const size_t offset,
2769 const size_t size, const int blocking)
2770{
2771 if(!(_opencl && _opencl->inited)) return -1;
2772
2773 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Read Buffer (from device to host)]");
2774
2776 _opencl->dev[devid].cmd_queue, device, blocking ? CL_TRUE : CL_FALSE, offset, size, host, 0, NULL, eventp);
2777}
2778
2779int dt_opencl_write_buffer_to_device(const int devid, void *host, void *device, const size_t offset,
2780 const size_t size, const int blocking)
2781{
2782 if(!(_opencl && _opencl->inited)) return -1;
2783
2784 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Write Buffer (from host to device)]");
2785
2787 _opencl->dev[devid].cmd_queue, device, blocking ? CL_TRUE : CL_FALSE, offset, size, host, 0, NULL, eventp);
2788}
2789
2790
2791void *dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
2792{
2793 if(!(_opencl && _opencl->inited) || devid < 0) return NULL;
2794 cl_int err;
2795 cl_mem dev = (_opencl->dlocl->symbols->dt_clCreateBuffer)(
2797 if(err != CL_SUCCESS)
2799 "[opencl copy_host_to_device_constant] could not alloc buffer on device %d: %i\n", devid, err);
2800
2802
2803 return dev;
2804}
2805
2806void *dt_opencl_copy_host_to_device(const int devid, void *host, const int width, const int height,
2807 const int bpp)
2808{
2810}
2811
2812void *dt_opencl_copy_host_to_device_rowpitch(const int devid, void *host, const int width, const int height,
2813 const int bpp, const int rowpitch)
2814{
2815 if(!(_opencl && _opencl->inited) || devid < 0) return NULL;
2816 cl_int err;
2818 // guess pixel format from bytes per pixel
2819 if(bpp == 4 * sizeof(float))
2821 else if(bpp == sizeof(float))
2823 else if(bpp == sizeof(uint16_t))
2825 else
2826 return NULL;
2827
2828 // TODO: if fmt = uint16_t, blow up to 4xuint16_t and copy manually!
2829 cl_mem dev = (_opencl->dlocl->symbols->dt_clCreateImage2D)(
2831 rowpitch, host, &err);
2832 if(err != CL_SUCCESS)
2834 "[opencl copy_host_to_device] could not alloc/copy img buffer on device %d: %i\n", devid, err);
2835
2836 if(err == CL_SUCCESS)
2837 {
2838 const size_t bytes = (size_t)(rowpitch ? rowpitch : width * bpp) * height;
2840 }
2841
2842 return dev;
2843}
2844
2845
2847{
2848 if(!(_opencl && _opencl->inited)) return;
2849
2850 // the OpenCL specs are not absolutely clear if clReleaseMemObject(NULL) is a no-op. we take care of the
2851 // case in a centralized way at this place
2852 if(IS_NULL_PTR(mem)) return;
2853
2855
2857}
2858
2859void *dt_opencl_map_buffer(const int devid, cl_mem buffer, const int blocking, const int flags, size_t offset,
2860 size_t size)
2861{
2862 if(!(_opencl && _opencl->inited)) return NULL;
2863 cl_int err;
2864 void *ptr;
2865 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Map Buffer]");
2867 _opencl->dev[devid].cmd_queue, buffer, blocking ? CL_TRUE : CL_FALSE, flags, offset, size, 0, NULL, eventp, &err);
2868 if(err != CL_SUCCESS) dt_print(DT_DEBUG_OPENCL, "[opencl map buffer] could not map buffer on device %d: %i\n", devid, err);
2869 return ptr;
2870}
2871
2872
2873void *dt_opencl_map_image(const int devid, cl_mem buffer, const int blocking, const int flags, size_t width, size_t height, int bpp)
2874{
2875 if(!(_opencl && _opencl->inited)) return NULL;
2876 cl_int err;
2877 void *ptr;
2878 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Map Image 2D]");
2879 size_t origin[3] = {0, 0, 0};
2880 size_t region[3] = {width, height, 1};
2881 size_t mapped_row_pitch;
2882
2884 _opencl->dev[devid].cmd_queue, buffer, blocking ? CL_TRUE : CL_FALSE, flags, origin, region,
2886
2887 if(err != CL_SUCCESS)
2888 dt_print(DT_DEBUG_OPENCL, "[opencl map buffer] could not map image on device %d: %i\n", devid, err);
2889 return ptr;
2890}
2891
2892
2893int dt_opencl_unmap_mem_object(const int devid, cl_mem mem_object, void *mapped_ptr)
2894{
2895 if(!(_opencl && _opencl->inited)) return -1;
2896 cl_event *eventp = dt_opencl_events_get_slot(devid, "[Unmap Mem Object]");
2899 if(err != CL_SUCCESS)
2900 dt_print(DT_DEBUG_OPENCL, "[opencl unmap mem object] could not unmap mem object on device %d: %i\n", devid, err);
2901 return err;
2902}
2903
2904static inline void *_dt_opencl_alloc_image2d(const int devid, const int width, const int height,
2905 const size_t bytes, const cl_mem_flags flags,
2906 const cl_image_format fmt, void *host,
2907 const char *const context)
2908{
2909 if(!(_opencl && _opencl->inited) || devid < 0) return NULL;
2910 cl_int err;
2911 cl_mem dev = NULL;
2912 for(int attempt = 0; attempt < 2; attempt++)
2913 {
2915 &fmt, width, height, 0, host, &err);
2916 if(err == CL_SUCCESS) break;
2918 {
2920 "[opencl %s] out of memory on device %d, flushing cached pinned buffers and retrying\n",
2921 context, devid);
2923 continue;
2924 }
2925 break;
2926 }
2927
2928 if(err != CL_SUCCESS)
2929 dt_print(DT_DEBUG_OPENCL, "[opencl %s] could not alloc img buffer on device %d: %i\n", context, devid, err);
2930
2932 return dev;
2933}
2934
2935void *dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
2936{
2938 const gboolean rgba8 = DT_OPENCL_BPP_IS_RGBA8(bpp);
2940 // guess pixel format from bytes per pixel (+ optional format tag for ambiguous 4-byte formats)
2941 if(rgba8 && effective_bpp == 4 * sizeof(uint8_t))
2943 else if(effective_bpp == 4 * sizeof(float))
2945 else if(effective_bpp == sizeof(float))
2947 else if(effective_bpp == sizeof(uint16_t))
2949 else if(effective_bpp == sizeof(uint8_t))
2951 else
2952 return NULL;
2953
2954 const size_t bytes = (size_t)width * height * effective_bpp;
2955 return _dt_opencl_alloc_image2d(devid, width, height, bytes, CL_MEM_READ_WRITE, fmt, NULL, "alloc_device");
2956}
2957
2958void *dt_opencl_alloc_device_use_host_pointer(const int devid, const int width, const int height,
2959 const int bpp, void *host, const int flags)
2960{
2962 const gboolean rgba8 = DT_OPENCL_BPP_IS_RGBA8(bpp);
2964 // guess pixel format from bytes per pixel (+ optional format tag for ambiguous 4-byte formats)
2965 if(rgba8 && effective_bpp == 4 * sizeof(uint8_t))
2967 else if(effective_bpp == 4 * sizeof(float))
2969 else if(effective_bpp == sizeof(float))
2971 else if(effective_bpp == sizeof(uint16_t))
2973 else
2974 return NULL;
2975
2976 const size_t bytes = (size_t)width * height * effective_bpp;
2978 "alloc_device_use_host_pointer");
2979}
2980
2981void *dt_opencl_alloc_device_buffer_with_flags(const int devid, const size_t size, const int flags, void *host_ptr)
2982{
2983 if(!(_opencl && _opencl->inited)) return NULL;
2984 cl_int err;
2985 cl_mem buf = NULL;
2986 for(int attempt = 0; attempt < 2; attempt++)
2987 {
2989 flags, size, host_ptr, &err);
2990 if(err == CL_SUCCESS) break;
2992 {
2994 "[opencl alloc_device_buffer] out of memory on device %d, flushing cached pinned buffers and retrying\n",
2995 devid);
2997 continue;
2998 }
2999 break;
3000 }
3001 if(err != CL_SUCCESS)
3002 dt_print(DT_DEBUG_OPENCL, "[opencl alloc_device_buffer] could not alloc buffer on device %d: %d\n", devid,
3003 err);
3004
3006
3007 return buf;
3008}
3009
3010
3011void *dt_opencl_alloc_device_buffer(const int devid, const size_t size)
3012{
3014}
3015
3016
3018{
3019 size_t size;
3020 if(IS_NULL_PTR(mem)) return 0;
3021
3022 cl_int err = (_opencl->dlocl->symbols->dt_clGetMemObjectInfo)(mem, CL_MEM_SIZE, sizeof(size), &size, NULL);
3023
3024 return (err == CL_SUCCESS) ? size : 0;
3025}
3026
3028{
3029 cl_context context;
3030 if(IS_NULL_PTR(mem)) return -1;
3031
3032 cl_int err = (_opencl->dlocl->symbols->dt_clGetMemObjectInfo)(mem, CL_MEM_CONTEXT, sizeof(context), &context, NULL);
3033 if(err != CL_SUCCESS)
3034 return -1;
3035
3036 for(int devid = 0; devid < _opencl->num_devs; devid++)
3037 {
3038 if(_opencl->dev[devid].context == context)
3039 return devid;
3040 }
3041
3042 return -1;
3043}
3044
3046{
3047 if(!(_opencl && _opencl->inited) || IS_NULL_PTR(mem)) return 0;
3048 cl_mem_flags flags = 0;
3049 cl_int err = (_opencl->dlocl->symbols->dt_clGetMemObjectInfo)(mem, CL_MEM_FLAGS, sizeof(flags), &flags, NULL);
3050 if(err != CL_SUCCESS) return 0;
3051 return flags;
3052}
3053
3055{
3056 size_t size;
3057 if(IS_NULL_PTR(mem)) return 0;
3058
3059 cl_int err = (_opencl->dlocl->symbols->dt_clGetImageInfo)(mem, CL_IMAGE_WIDTH, sizeof(size), &size, NULL);
3060 if(size > INT_MAX) size = 0;
3061
3062 return (err == CL_SUCCESS) ? (int)size : 0;
3063}
3064
3066{
3067 size_t size;
3068 if(IS_NULL_PTR(mem)) return 0;
3069
3070 cl_int err = (_opencl->dlocl->symbols->dt_clGetImageInfo)(mem, CL_IMAGE_HEIGHT, sizeof(size), &size, NULL);
3071 if(size > INT_MAX) size = 0;
3072
3073 return (err == CL_SUCCESS) ? (int)size : 0;
3074}
3075
3077{
3078 size_t size;
3079 if(IS_NULL_PTR(mem)) return 0;
3080
3082 NULL);
3083 if(size > INT_MAX) size = 0;
3084
3085 return (err == CL_SUCCESS) ? (int)size : 0;
3086}
3087
3093
3094void dt_opencl_memory_statistics(int devid, cl_mem mem, size_t size, dt_opencl_memory_t action)
3095{
3096 if(IS_NULL_PTR(mem)) return;
3097
3099 {
3100 // devid and size are known at allocation time -- record them so the release
3101 // path can undo the exact same amount without querying the driver.
3102 if(devid < 0) return;
3104 rec->devid = devid;
3105 rec->size = size;
3107 // g_hash_table_insert frees the previous value (g_free) if the key already
3108 // exists, so re-inserting the same cl_mem pointer never leaks.
3111 }
3112 else
3113 {
3114 // Look up what we recorded on ADD. Never ask the driver about the object here
3115 // either: on some Windows drivers clGetMemObjectInfo faults under vRAM
3116 // pressure (issues #130221119 / #130557353), aborting the process.
3119 if(rec)
3120 {
3121 devid = rec->devid;
3122 size = rec->size;
3124 }
3125 else
3126 {
3127 // Untracked object (allocated before this bookkeeping, or via a path that
3128 // did not register). Nothing reliable to subtract; leave the counter be.
3129 devid = -1;
3130 }
3132 }
3133
3134 if(devid < 0)
3135 return;
3136
3138 _opencl->dev[devid].memory_in_use += size;
3139 else
3140 _opencl->dev[devid].memory_in_use =
3141 (_opencl->dev[devid].memory_in_use > size)
3142 ? (_opencl->dev[devid].memory_in_use - size)
3143 : 0;
3144
3145 _opencl->dev[devid].peak_memory = MAX(_opencl->dev[devid].peak_memory,
3146 _opencl->dev[devid].memory_in_use);
3147
3150 "[opencl memory] device %d: %" G_GSIZE_FORMAT " bytes (%.1f MB) in use\n", devid, _opencl->dev[devid].memory_in_use,
3151 (float)_opencl->dev[devid].memory_in_use/(1024*1024));
3152}
3153
3154void dt_opencl_check_tuning(const int devid)
3155{
3156 dt_opencl_t *cl = _opencl;
3157 if(!cl->inited || devid < 0) return;
3158
3159 // Apply the headroom read from this device configuration. Older configs without
3160 // a per-device key are migrated from the global default during device init.
3161 size_t headroom = cl->dev[devid].forced_headroom;
3162
3163 cl->dev[devid].used_available = MAX(0ul, cl->dev[devid].max_global_mem - headroom * 1024 * 1024);
3164
3166 "[dt_opencl_check_tuning] use %" G_GSIZE_FORMAT " MiB on device `%s' id=%i\n",
3167 cl->dev[devid].used_available / (1024 * 1024),
3168 cl->dev[devid].name, devid);
3169}
3170
3171cl_ulong dt_opencl_get_device_available(const int devid)
3172{
3173 if(!(_opencl && _opencl->inited) || devid < 0) return 0;
3174 const cl_ulong limit = _opencl->dev[devid].used_available;
3175 const size_t in_use = _opencl->dev[devid].memory_in_use;
3176 cl_ulong available = (limit > in_use) ? (limit - in_use) : 0;
3177
3178 /* A host-unified device is bounded by two DIFFERENT things, and they must not be conflated.
3179 *
3180 * 1. Free space. Its "vRAM" is system RAM, shared with every other process and with the host
3181 * side of our own pipeline, so max_global_mem is the size of the machine rather than a
3182 * budget -- a P630 reports 28.75 GiB on a 31 GiB box. dt_get_system_available_mem() already
3183 * measures what is actually left (free plus reclaimable, cgroup limits included), so clamp
3184 * to it. A 0 return means the platform will not say; that is "no information", not "no
3185 * memory", so the device's own accounting stands.
3186 *
3187 * 2. How much the driver can have in flight at once, which is NOT a free-space question and
3188 * does not get better when RAM is free. Measured on the P630 with 22 GiB genuinely
3189 * available: an ~8 GiB working set fails, the pipe loses OpenCL entirely and drops to CPU;
3190 * ~4 GiB fails mid-tile; ~2 GiB completes. The ceiling is the GPU aperture / address space
3191 * per context, which OpenCL publishes no query for. max_mem_alloc is the closest thing it
3192 * does publish -- NEO reports min(global/4, 4 GiB), which tracks that aperture -- so half
3193 * of it is used as a working-set ceiling. It is a proxy chosen to match the measurement,
3194 * not a measurement of anything, and it is written here as its own clamp so it cannot be
3195 * misread as free space.
3196 *
3197 * This lives in the reader rather than in dt_opencl_check_tuning() because the tilers and the
3198 * fit checks call it while deciding: limit 1 is then re-probed at each decision instead of
3199 * frozen once per pipe run, before any of the allocations it governs. The probe caches for
3200 * tens of milliseconds, which is what makes that affordable.
3201 *
3202 * Discrete devices never enter here: their max_global_mem really is dedicated vRAM. */
3203 if(_opencl->dev[devid].host_unified_memory)
3204 {
3205 const size_t reserved = (size_t)_opencl->dev[devid].forced_headroom * 1024 * 1024;
3206
3208 if(system_available > 0)
3209 available = MIN(available, (cl_ulong)((system_available > reserved) ? system_available - reserved : 0));
3210
3211 available = MIN(available, (cl_ulong)(_opencl->dev[devid].max_mem_alloc / 2));
3212 }
3213 return available;
3214}
3215
3216static cl_ulong _opencl_get_device_memalloc(const int devid)
3217{
3218 return _opencl->dev[devid].max_mem_alloc;
3219}
3220
3221cl_ulong dt_opencl_get_device_memalloc(const int devid)
3222{
3223 if(!(_opencl && _opencl->inited) || devid < 0) return 0;
3224 return _opencl_get_device_memalloc(devid);
3225}
3226
3228 const size_t height, const unsigned bpp, const float factor,
3229 const size_t overhead, size_t *needed, size_t *limit)
3230{
3231 size_t n = 0, l = 0;
3233
3234 dt_opencl_t *cl = _opencl;
3235 if(!cl->inited || devid < 0)
3236 {
3237 reason = DT_OPENCL_FIT_UNINITED;
3238 }
3239 else
3240 {
3241 const size_t required = width * height * bpp;
3242 const size_t total = (size_t)ceilf((float)required * factor) + overhead;
3243
3244 if(cl->dev[devid].max_image_width < width || cl->dev[devid].max_image_height < height)
3245 {
3246 // dimension limit: compared quantities are pixel counts, not bytes -> leave n/l at 0
3247 reason = DT_OPENCL_FIT_DIMENSION;
3248 }
3249 else if(_opencl_get_device_memalloc(devid) < required)
3250 {
3251 n = required;
3252 l = _opencl_get_device_memalloc(devid);
3254 "[opencl] trying to allocate %" PRIu64 " MiB of memory while the vRAM has %" PRIu64
3255 " MiB total\n",
3256 (uint64_t)(n / (1024 * 1024)), (uint64_t)(l / (1024 * 1024)));
3258 }
3259 else if(dt_opencl_get_device_available(devid) < total)
3260 {
3261 n = total;
3264 "[opencl] trying to allocate %" PRIu64 " MiB of memory while the vRAM has %" PRIu64
3265 " MiB left\n",
3266 (uint64_t)(n / (1024 * 1024)), (uint64_t)(l / (1024 * 1024)));
3267 reason = DT_OPENCL_FIT_AVAILABLE;
3268 }
3269 }
3270
3271 if(needed) *needed = n;
3272 if(limit) *limit = l;
3273 return reason;
3274}
3275
3276gboolean dt_opencl_image_fits_device(const int devid, const size_t width, const size_t height, const unsigned bpp,
3277 const float factor, const size_t overhead)
3278{
3279 return dt_opencl_image_fits_device_reason(devid, width, height, bpp, factor, overhead, NULL, NULL)
3281}
3282
3284int dt_opencl_dev_roundup_width(int size, const int devid)
3285{
3286 const int roundup = _opencl->dev[devid].clroundup_wd;
3287 return (size % roundup == 0 ? size : (size / roundup + 1) * roundup);
3288}
3289int dt_opencl_dev_roundup_height(int size, const int devid)
3290{
3291 const int roundup = _opencl->dev[devid].clroundup_ht;
3292 return (size % roundup == 0 ? size : (size / roundup + 1) * roundup);
3293}
3294
3297{
3298 return (_opencl && _opencl->inited);
3299}
3300
3301
3304{
3305 if(!(_opencl && _opencl->inited)) return FALSE;
3306 return _opencl->enabled;
3307}
3308
3309
3312{
3313 if(!(_opencl && _opencl->inited)) return;
3315 dt_conf_set_bool("opencl", FALSE);
3316}
3317
3318
3321{
3322 dt_opencl_t *cl = _opencl;
3323 // FIXME: This pulls in prefs every time the pixelpipe runs. Instead have a callback for DT_SIGNAL_PREFERENCES_CHANGE?
3324 if(!cl->inited) return FALSE;
3325 const int prefs = dt_conf_get_bool("opencl");
3326
3327 if(cl->enabled != prefs)
3328 {
3329 cl->enabled = prefs;
3330 cl->stopped = 0;
3331 cl->error_count = 0;
3332 dt_print(DT_DEBUG_OPENCL, "[opencl_update_enabled] enabled flag set to %s\n", prefs ? "ON" : "OFF");
3333 }
3334
3335 return (cl->enabled && !cl->stopped);
3336}
3337
3338
3341{
3343 dt_print_nts(DT_DEBUG_OPENCL, "[opencl_synchronization_timeout] synchronization timeout set to %d\n", value);
3344}
3345
3354
3355
3359cl_event *dt_opencl_events_get_slot(const int devid, const char *tag)
3360{
3361 dt_opencl_t *cl = _opencl;
3362 if(!cl->inited || devid < 0) return NULL;
3363 if(!cl->dev[devid].use_events) return NULL;
3364
3365 static const cl_event zeroevent[1]; // implicitly initialized to zero
3366 cl_event **eventlist = &(cl->dev[devid].eventlist);
3367 dt_opencl_eventtag_t **eventtags = &(cl->dev[devid].eventtags);
3368 int *numevents = &(cl->dev[devid].numevents);
3369 int *maxevents = &(cl->dev[devid].maxevents);
3370 int *eventsconsolidated = &(cl->dev[devid].eventsconsolidated);
3371 int *lostevents = &(cl->dev[devid].lostevents);
3372 int *totalevents = &(cl->dev[devid].totalevents);
3373 int *totallost = &(cl->dev[devid].totallost);
3374 int *maxeventslot = &(cl->dev[devid].maxeventslot);
3375 // if first time called: allocate initial buffers
3376 if(IS_NULL_PTR(*eventlist))
3377 {
3379 *eventlist = calloc(newevents, sizeof(cl_event));
3380 *eventtags = calloc(newevents, sizeof(dt_opencl_eventtag_t));
3381 if(!*eventlist || !*eventtags)
3382 {
3383 dt_free(*eventlist);
3384 dt_free(*eventtags);
3385 *eventlist = NULL;
3386 *eventtags = NULL;
3387 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_events_get_slot] NO eventlist for device %i\n", devid);
3388 return NULL;
3389 }
3390 *maxevents = newevents;
3391 }
3392
3393 // check if currently highest event slot was actually consumed. If not use it again
3394 if(*numevents > 0 && !memcmp((*eventlist) + *numevents - 1, zeroevent, sizeof(cl_event)))
3395 {
3396 (*lostevents)++;
3397 (*totallost)++;
3398 if(!IS_NULL_PTR(tag))
3399 {
3400 g_strlcpy((*eventtags)[*numevents - 1].tag, tag, DT_OPENCL_EVENTNAMELENGTH);
3401 }
3402 else
3403 {
3404 (*eventtags)[*numevents - 1].tag[0] = '\0';
3405 }
3406
3407 (*totalevents)++;
3408 return (*eventlist) + *numevents - 1;
3409 }
3410
3411 // check if we would exceed the number of available event handles. In that case first flush existing handles
3412 if((*numevents - *eventsconsolidated + 1 > cl->dev[devid].event_handles) || (*numevents == *maxevents))
3413 (void)dt_opencl_events_flush(devid, 0);
3414
3415 // if no more space left in eventlist: grow buffer
3416 if(*numevents == *maxevents)
3417 {
3418 int newevents = *maxevents + DT_OPENCL_EVENTLISTSIZE;
3422 {
3423 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_events_get_slot] NO new eventlist with size %i for device %i\n",
3424 newevents, devid);
3427 return NULL;
3428 }
3429 memcpy(neweventlist, *eventlist, sizeof(cl_event) * *maxevents);
3430 memcpy(neweventtags, *eventtags, sizeof(dt_opencl_eventtag_t) * *maxevents);
3431 dt_free(*eventlist);
3432 dt_free(*eventtags);
3433 *eventlist = neweventlist;
3434 *eventtags = neweventtags;
3435 *maxevents = newevents;
3436 }
3437
3438 // init next event slot and return it
3439 (*numevents)++;
3440 memcpy((*eventlist) + *numevents - 1, zeroevent, sizeof(cl_event));
3441 if(!IS_NULL_PTR(tag))
3442 {
3443 g_strlcpy((*eventtags)[*numevents - 1].tag, tag, DT_OPENCL_EVENTNAMELENGTH);
3444 }
3445 else
3446 {
3447 (*eventtags)[*numevents - 1].tag[0] = '\0';
3448 }
3449
3450 (*totalevents)++;
3451 *maxeventslot = MAX(*maxeventslot, *numevents - 1);
3452 return (*eventlist) + *numevents - 1;
3453}
3454
3455
3457void dt_opencl_events_reset(const int devid)
3458{
3459 dt_opencl_t *cl = _opencl;
3460 if(!cl->inited || devid < 0) return;
3461 if(!cl->dev[devid].use_events) return;
3462
3463 cl_event **eventlist = &(cl->dev[devid].eventlist);
3464 dt_opencl_eventtag_t **eventtags = &(cl->dev[devid].eventtags);
3465 int *numevents = &(cl->dev[devid].numevents);
3466 int *maxevents = &(cl->dev[devid].maxevents);
3467 int *eventsconsolidated = &(cl->dev[devid].eventsconsolidated);
3468 int *lostevents = &(cl->dev[devid].lostevents);
3469 cl_int *summary = &(cl->dev[devid].summary);
3470
3471 if(IS_NULL_PTR(*eventlist) || *numevents == 0) return; // nothing to do
3472
3473 static const cl_event zeroevent[1]; // implicitly initialized to zero
3474
3475 // release all remaining events in eventlist, not to waste resources.
3476 // Skip NULL handles left behind by failed enqueues: releasing them is
3477 // pointless and crashes some drivers.
3478 for(int k = *eventsconsolidated; k < *numevents; k++)
3479 {
3480 if(memcmp((*eventlist) + k, zeroevent, sizeof(cl_event)))
3481 (cl->dlocl->symbols->dt_clReleaseEvent)((*eventlist)[k]);
3482 }
3483
3484 memset(*eventtags, 0, sizeof(dt_opencl_eventtag_t) * *maxevents);
3485 *numevents = 0;
3486 *eventsconsolidated = 0;
3487 *lostevents = 0;
3488 *summary = CL_COMPLETE;
3489 return;
3490}
3491
3492
3495void dt_opencl_events_wait_for(const int devid)
3496{
3497 dt_opencl_t *cl = _opencl;
3498 if(!cl->inited || devid < 0) return;
3499 if(!cl->dev[devid].use_events) return;
3500
3501 static const cl_event zeroevent[1]; // implicitly initialized to zero
3502 cl_event **eventlist = &(cl->dev[devid].eventlist);
3503 int *numevents = &(cl->dev[devid].numevents);
3504 int *lostevents = &(cl->dev[devid].lostevents);
3505 int *totallost = &(cl->dev[devid].totallost);
3506 int *eventsconsolidated = &(cl->dev[devid].eventsconsolidated);
3507
3508 if(IS_NULL_PTR(*eventlist) || *numevents == 0) return; // nothing to do
3509
3510 // check if last event slot was actually used and correct numevents if needed
3511 if(!memcmp((*eventlist) + *numevents - 1, zeroevent, sizeof(cl_event)))
3512 {
3513 (*numevents)--;
3514 (*lostevents)++;
3515 (*totallost)++;
3516 }
3517
3518 if(*numevents == *eventsconsolidated) return; // nothing to do
3519
3520 assert(*numevents > *eventsconsolidated);
3521
3522 // Wait for all remaining events to terminate, skipping NULL handles. A reserved
3523 // slot can hold a NULL handle when its enqueue failed (the event is never
3524 // created, but get_slot had already counted the slot). Passing NULL to
3525 // clWaitForEvents crashes some drivers and, on those that merely return an
3526 // error, would abort a batched wait and leave the valid events that follow
3527 // un-waited-for before flush checks/releases them. We wait on each handle
3528 // individually rather than gathering them into a temporary array: a heap
3529 // allocation could fail under the very memory pressure that creates these NULL
3530 // slots, and returning early on that failure would skip the wait entirely.
3531 // Risk: might never return in case of OpenCL blocks or endless loops
3532 // TODO: run clWaitForEvents in separate thread and implement watchdog timer
3533 for(int k = *eventsconsolidated; k < *numevents; k++)
3534 {
3535 if(!memcmp((*eventlist) + k, zeroevent, sizeof(cl_event)))
3536 continue; // NULL handle from a failed enqueue
3537
3538 cl_int err = (cl->dlocl->symbols->dt_clWaitForEvents)(1, &((*eventlist)[k]));
3539 if((err != CL_SUCCESS) && (err != CL_INVALID_VALUE))
3540 dt_vprint(DT_DEBUG_OPENCL, "[dt_opencl_events_wait_for] reported %i for device %i\n",
3541 err, devid);
3542 }
3543}
3544
3545
3552cl_int dt_opencl_events_flush(const int devid, const int reset)
3553{
3554 dt_opencl_t *cl = _opencl;
3555 if(!cl->inited || devid < 0) return FALSE;
3556 if(!cl->dev[devid].use_events) return FALSE;
3557
3558 cl_event **eventlist = &(cl->dev[devid].eventlist);
3559 dt_opencl_eventtag_t **eventtags = &(cl->dev[devid].eventtags);
3560 int *numevents = &(cl->dev[devid].numevents);
3561 int *eventsconsolidated = &(cl->dev[devid].eventsconsolidated);
3562 int *lostevents = &(cl->dev[devid].lostevents);
3563 int *totalsuccess = &(cl->dev[devid].totalsuccess);
3564
3565 cl_int *summary = &(cl->dev[devid].summary);
3566
3567 static const cl_event zeroevent[1]; // implicitly initialized to zero
3568
3569 if(IS_NULL_PTR(*eventlist) || *numevents == 0) return CL_COMPLETE; // nothing to do, no news is good news
3570
3571 // Wait for command queue to terminate (side effect: might adjust *numevents)
3573
3574 // now check return status and profiling data of all newly terminated events
3575 for(int k = *eventsconsolidated; k < *numevents; k++)
3576 {
3577 // A reserved slot can still hold a NULL handle when the matching enqueue
3578 // failed: OpenCL does not create the event in that case, but get_slot had
3579 // already counted the slot. Passing such a NULL handle to the driver
3580 // crashes some implementations (e.g. NVIDIA on Windows), so treat it as a
3581 // lost event and skip it.
3582 if(!memcmp((*eventlist) + k, zeroevent, sizeof(cl_event)))
3583 {
3584 (*lostevents)++;
3585 (*eventsconsolidated)++;
3586 continue;
3587 }
3588
3589 cl_int err;
3590 char *tag = (*eventtags)[k].tag;
3591 cl_int *retval = &((*eventtags)[k].retval);
3592
3593 // get return value of event
3595 sizeof(cl_int), retval, NULL);
3596 if(err != CL_SUCCESS)
3597 {
3598 dt_print(DT_DEBUG_OPENCL, "[opencl_events_flush] could not get event info for '%s': %i\n",
3599 tag[0] == '\0' ? "<?>" : tag, err);
3600 }
3601 else if(*retval != CL_COMPLETE)
3602 {
3603 dt_print(DT_DEBUG_OPENCL, "[opencl_events_flush] execution of '%s' %s: %d\n",
3604 tag[0] == '\0' ? "<?>" : tag, *retval == CL_COMPLETE ? "was successful" : "failed", *retval);
3605 *summary = *retval;
3606 }
3607 else
3608 (*totalsuccess)++;
3609
3611 {
3612 // get profiling info of event (only if darktable was called with '-d perf')
3613 cl_ulong start;
3614 cl_ulong end;
3616 (*eventlist)[k], CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, NULL);
3618 sizeof(cl_ulong), &end, NULL);
3619 if(errs == CL_SUCCESS && erre == CL_SUCCESS)
3620 {
3621 (*eventtags)[k].timelapsed = end - start;
3622 }
3623 else
3624 {
3625 (*eventtags)[k].timelapsed = 0;
3626 (*lostevents)++;
3627 }
3628 }
3629 else
3630 (*eventtags)[k].timelapsed = 0;
3631
3632 // finally release event to be re-used by driver
3633 (cl->dlocl->symbols->dt_clReleaseEvent)((*eventlist)[k]);
3634 (*eventsconsolidated)++;
3635 }
3636
3637 cl_int result = *summary;
3638
3639 // do we want to get rid of all stored info?
3640 if(reset)
3641 {
3642 // output profiling info if wanted
3644
3645 // reset eventlist structures to empty state
3647 }
3648
3649 return result == CL_COMPLETE ? 0 : result;
3650}
3651
3652
3655void dt_opencl_events_profiling(const int devid, const int aggregated)
3656{
3657 dt_opencl_t *cl = _opencl;
3658 if(!cl->inited || devid < 0) return;
3659 if(!cl->dev[devid].use_events) return;
3660
3661 cl_event **eventlist = &(cl->dev[devid].eventlist);
3662 dt_opencl_eventtag_t **eventtags = &(cl->dev[devid].eventtags);
3663 int *numevents = &(cl->dev[devid].numevents);
3664 int *eventsconsolidated = &(cl->dev[devid].eventsconsolidated);
3665 int *lostevents = &(cl->dev[devid].lostevents);
3666
3667 if(IS_NULL_PTR(*eventlist) || *numevents == 0 || IS_NULL_PTR(*eventtags) || *eventsconsolidated == 0)
3668 return; // nothing to do
3669
3670 char **tags = malloc(sizeof(char *) * (*eventsconsolidated + 1));
3671 float *timings = malloc(sizeof(float) * (*eventsconsolidated + 1));
3672 int items = 1;
3673 tags[0] = "";
3674 timings[0] = 0.0f;
3675
3676 // get profiling info and arrange it
3677 for(int k = 0; k < *eventsconsolidated; k++)
3678 {
3679 // if aggregated is TRUE, try to sum up timings for multiple runs of each kernel
3680 if(aggregated)
3681 {
3682 // linear search: this is not efficient at all but acceptable given the limited
3683 // number of events (ca. 10 - 20)
3684 int tagfound = -1;
3685 for(int i = 0; i < items; i++)
3686 {
3687 if(!strncmp(tags[i], (*eventtags)[k].tag, DT_OPENCL_EVENTNAMELENGTH))
3688 {
3689 tagfound = i;
3690 break;
3691 }
3692 }
3693
3694 if(tagfound >= 0) // tag was already detected before
3695 {
3696 // sum up timings
3697 timings[tagfound] += (*eventtags)[k].timelapsed * 1e-9;
3698 }
3699 else // tag is new
3700 {
3701 // make new entry
3702 items++;
3703 tags[items - 1] = (*eventtags)[k].tag;
3704 timings[items - 1] = (*eventtags)[k].timelapsed * 1e-9;
3705 }
3706 }
3707
3708 else // no aggregated info wanted -> arrange event by event
3709 {
3710 items++;
3711 tags[items - 1] = (*eventtags)[k].tag;
3712 timings[items - 1] = (*eventtags)[k].timelapsed * 1e-9;
3713 }
3714 }
3715
3716 // now display profiling info
3718 "[opencl_profiling] profiling device %d ('%s'):\n", devid, cl->dev[devid].name);
3719
3720 float total = 0.0f;
3721 for(int i = 1; i < items; i++)
3722 {
3723 dt_print(DT_DEBUG_OPENCL, "[opencl_profiling] spent %7.4f seconds in %s\n", (double)timings[i],
3724 tags[i][0] == '\0' ? "<?>" : tags[i]);
3725 total += timings[i];
3726 }
3727 // aggregated timing info for items without tag (if any)
3728 if(timings[0] != 0.0f)
3729 {
3730 dt_print(DT_DEBUG_OPENCL, "[opencl_profiling] spent %7.4f seconds (unallocated)\n", (double)timings[0]);
3731 total += timings[0];
3732 }
3733
3735 "[opencl_profiling] spent %7.4f seconds totally in command queue (with %d event%s missing)\n",
3736 (double)total, *lostevents, *lostevents == 1 ? "" : "s");
3737
3739 dt_free(tags);
3740
3741 return;
3742}
3743
3744static int nextpow2(int n)
3745{
3746 int k = 1;
3747 while (k < n)
3748 k <<= 1;
3749 return k;
3750}
3751
3752// utility function to calculate optimal work group dimensions for a given kernel
3753// taking device specific restrictions and local memory limitations into account
3755{
3756 dt_opencl_t *cl = _opencl;
3757 if(!cl->inited || devid < 0) return FALSE;
3758
3759 size_t maxsizes[3] = { 0 }; // the maximum dimensions for a work group
3760 size_t workgroupsize = 0; // the maximum number of items in a work group
3761 unsigned long localmemsize = 0; // the maximum amount of local memory we can use
3762 size_t kernelworkgroupsize = 0; // the maximum amount of items in work group for this kernel
3763
3764 int *blocksizex = &factors->sizex;
3765 int *blocksizey = &factors->sizey;
3766
3767 // initial values must be supplied in sizex and sizey.
3768 // we make sure that these are a power of 2 and lie within reasonable limits.
3769 *blocksizex = CLAMP(nextpow2(*blocksizex), 1, 1 << 16);
3770 *blocksizey = CLAMP(nextpow2(*blocksizey), 1, 1 << 16);
3771
3774 {
3775 while(maxsizes[0] < *blocksizex || maxsizes[1] < *blocksizey
3776 || localmemsize < ((factors->xfactor * (*blocksizex) + factors->xoffset) *
3777 (factors->yfactor * (*blocksizey) + factors->yoffset)) * factors->cellsize + factors->overhead
3778 || workgroupsize < (size_t)(*blocksizex) * (*blocksizey) || kernelworkgroupsize < (size_t)(*blocksizex) * (*blocksizey))
3779 {
3780 if(*blocksizex == 1 && *blocksizey == 1) return FALSE;
3781
3782 if(*blocksizex > *blocksizey)
3783 *blocksizex >>= 1;
3784 else
3785 *blocksizey >>= 1;
3786 }
3787 }
3788 else
3789 {
3790 dt_print(DT_DEBUG_OPENCL, "[dt_opencl_local_buffer_opt] can not identify resource limits for device %d\n", devid);
3791 return FALSE;
3792 }
3793
3794 return TRUE;
3795}
3796
3797
3798#endif
3799
3800// clang-format off
3801// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
3802// vim: shiftwidth=2 expandtab tabstop=2 cindent
3803// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
3804// 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:1684
void dt_develop_blend_init_cl_global(void)
Definition blend.c:1653
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_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.
void dt_conf_save(dt_conf_t *cf)
Write cf back to its file. Overridden keys keep their stored value.
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:2339
darktable_t darktable
Definition darktable.c:213
void dt_capabilities_remove(char *capability)
Definition darktable.c:2569
void dt_capabilities_add(char *capability)
Definition darktable.c:2558
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:2085
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:3171
int dt_opencl_get_kernel_work_group_size(const int dev, const int kernel, size_t *kernelworkgroupsize)
Definition opencl.c:2574
cl_event * dt_opencl_events_get_slot(const int devid, const char *tag)
Definition opencl.c:3359
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:2904
int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
Definition opencl.c:3754
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2595
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:3011
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:3227
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:2634
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:2958
size_t dt_opencl_get_mem_object_size(cl_mem mem)
Definition opencl.c:3017
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:2743
void dt_opencl_events_reset(const int devid)
Definition opencl.c:3457
cl_int dt_opencl_events_flush(const int devid, const int reset)
Definition opencl.c:3552
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:2622
gboolean dt_opencl_read_device_config(const int devid)
Definition opencl.c:294
void dt_opencl_check_tuning(const int devid)
Definition opencl.c:3154
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2935
int dt_opencl_is_inited(void)
Definition opencl.c:3296
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2489
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2791
int dt_opencl_dev_roundup_height(int size, const int devid)
Definition opencl.c:3289
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:2812
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:2681
int dt_opencl_dev_roundup_width(int size, const int devid)
Definition opencl.c:3284
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:3340
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:3027
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:2691
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:2163
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:2859
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:3347
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:2076
int dt_opencl_get_image_height(cl_mem mem)
Definition opencl.c:3065
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
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:2651
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:2779
int dt_opencl_micro_nap(const int devid)
Definition opencl.c:225
static cl_ulong _opencl_get_device_memalloc(const int devid)
Definition opencl.c:3216
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:2720
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:2768
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:2345
int dt_opencl_get_max_work_item_sizes(const int dev, size_t *sizes)
Definition opencl.c:2546
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:2090
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:3276
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:2893
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:2663
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:3303
void dt_opencl_memory_statistics(int devid, cl_mem mem, size_t size, dt_opencl_memory_t action)
Definition opencl.c:3094
void dt_opencl_md5sum(const char **files, char **md5sums)
Definition opencl.c:2109
static int nextpow2(int n)
Definition opencl.c:3744
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2532
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:3054
cl_ulong dt_opencl_get_device_memalloc(const int devid)
Definition opencl.c:3221
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:2644
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:2873
void * dt_opencl_alloc_device_buffer_with_flags(const int devid, const size_t size, const int flags, void *host_ptr)
Definition opencl.c:2981
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:2697
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:2586
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:2731
static void _opencl_splash_update_compile(const char *programname)
Definition opencl.c:136
int dt_opencl_update_settings(void)
Definition opencl.c:3320
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:3495
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:2628
void dt_opencl_events_profiling(const int devid, const int aggregated)
Definition opencl.c:3655
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:2554
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:2601
cl_mem_flags dt_opencl_get_mem_flags(cl_mem mem)
Definition opencl.c:3045
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:2755
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:2806
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:2708
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:2846
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:3076
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
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:2675
void dt_opencl_disable(void)
Definition opencl.c:3311
#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:2674
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
struct dt_conf_t * conf
Definition darktable.h:184
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
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