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