Skip to content

Commit

Permalink
Introduce OpenCL exceptions
Browse files Browse the repository at this point in the history
While installing an OpenCL device we do a number of checks for special situations, that could be detecting
problematic drivers/devices or some implementations with advantage.

These checks leave a bitflag in device exceptions, they can later be tested while running OpenCL code
via `gboolean dt_opencl_exception(const int devid, const uint32_t mask);`

An example is provided in demosaicer module, we know that the default AMD windows driver is bad for PPG
so we do a fallback there.
  • Loading branch information
jenshannoschwalm authored and TurboGit committed Mar 2, 2025
1 parent ca55f74 commit fb8a96d
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 5 deletions.
14 changes: 12 additions & 2 deletions src/common/opencl.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
This file is part of darktable,
Copyright (C) 2010-2024 darktable developers.
Copyright (C) 2010-2025 darktable developers.
darktable is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -212,6 +212,8 @@ const char *cl_errstr(cl_int error)
return "DT_OPENCL_PROCESS_CL";
case DT_OPENCL_NODEVICE:
return "DT_OPENCL_NODEVICE";
case DT_OPENCL_DT_EXCEPTION:
return "DT_OPENCL_DT_EXCEPTION";
default:
return "Unknown OpenCL error";
}
Expand Down Expand Up @@ -789,7 +791,7 @@ static gboolean _opencl_device_init(dt_opencl_t *cl,
goto end;
}

const gboolean is_blacklisted = dt_opencl_check_driver_blacklist(deviceversion);
const gboolean is_blacklisted = _opencl_check_driver_blacklist(deviceversion);

// disable device for now if this is the first time detected and blacklisted too.
if(newdevice && is_blacklisted)
Expand Down Expand Up @@ -965,6 +967,8 @@ static gboolean _opencl_device_init(dt_opencl_t *cl,
dt_print_nts(DT_DEBUG_OPENCL, " CL COMPILER OPTION: %s\n", my_option);
dt_print_nts(DT_DEBUG_OPENCL, " CL COMPILER COMMAND: %s\n", cl->dev[dev].options);

_write_test_exceptions(&cl->dev[dev]);

g_free(compile_option_name_cname);
g_free(my_option);
g_free(escapedkerneldir);
Expand Down Expand Up @@ -3664,6 +3668,12 @@ gboolean dt_opencl_running(void)
return _cl_running();
}

gboolean dt_opencl_exception(const int devid, const uint32_t mask)
{
if(!_cldev_running(devid)) return FALSE;
return (darktable.opencl->dev[devid].exceptions & mask) != 0;
}

/** update enabled flag and profile with value from preferences */
void dt_opencl_update_settings(void)
{
Expand Down
15 changes: 14 additions & 1 deletion src/common/opencl.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
This file is part of darktable,
Copyright (C) 2010-2024 darktable developers.
Copyright (C) 2010-2025 darktable developers.
darktable is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -37,6 +37,13 @@
#define DT_OPENCL_SYSMEM_ALLOCATION -998
#define DT_OPENCL_PROCESS_CL -997
#define DT_OPENCL_NODEVICE -996
#define DT_OPENCL_DT_EXCEPTION -995

/* exceptions */
#define DT_OPENCL_AMD_APP 1
#define DT_OPENCL_ONLY_CUDA 2


#include "common/darktable.h"

#ifdef HAVE_OPENCL
Expand Down Expand Up @@ -201,6 +208,9 @@ typedef struct dt_opencl_device_t
// lets keep the vendor for runtime checks
int vendor_id;

// exceptions bit mask
uint32_t exceptions;

float advantage;
} dt_opencl_device_t;

Expand Down Expand Up @@ -610,6 +620,9 @@ void dt_opencl_check_tuning(const int devid);
/** get size of allocatable single buffer */
cl_ulong dt_opencl_get_device_memalloc(const int devid);

/** checks for a detected OpenCL runtime exception */
gboolean dt_opencl_exception(const int devid, const uint32_t mask);

/** round size to a multiple of the value given in the device specifig
* config parameter for opencl_size_roundup */
int dt_opencl_dev_roundup_width(int size,
Expand Down
32 changes: 30 additions & 2 deletions src/common/opencl_drivers_blacklist.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
This file is part of darktable,
Copyright (C) 2016-2020 darktable developers.
Copyright (C) 2016-2025 darktable developers.
darktable is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -44,7 +44,7 @@ static const gchar *bad_opencl_drivers[] =
};

// returns TRUE if blacklisted
gboolean dt_opencl_check_driver_blacklist(const char *device_version)
static gboolean _opencl_check_driver_blacklist(const char *device_version)
{
gchar *device = g_ascii_strdown(device_version, -1);

Expand All @@ -62,6 +62,34 @@ gboolean dt_opencl_check_driver_blacklist(const char *device_version)
return FALSE;
}

/*
darktable OpenCL runtime exceptions
1. We test for a number of problematic or advantage situations and leave a flag about that
in the dt_opencl_device_t struct
2. gboolean dt_opencl_exception(const int devid, const uint32_t mask)
allows to check for such conditions while processing the pixelpipe and
possibly using different code or fallbacks
3. An example can be found in demosaic testing for DT_OPENCL_AMD_APP while using the
DT_IOP_DEMOSAIC_PPG demosaicer, as that OpenCL code fails for unknown reasons we do
a fallback to DT_IOP_DEMOSAIC_RCD (which is better anyway).
4. We could also fallback to CPU code path in such exceptions, in that case we should return
with DT_OPENCL_DT_EXCEPTION as the error code, that would be reported in the -d opencl log
*/

static void _write_test_exceptions(dt_opencl_device_t *device)
{
if(!strncasecmp(device->device_version, "OpenCL 2.0 AMD-APP", 18))
{
device->exceptions |= DT_OPENCL_AMD_APP;
dt_print_nts(DT_DEBUG_OPENCL, " CL EXCEPTION: DT_OPENCL_AMD_APP\n");
}
if(!strncasecmp(device->platform, "NVIDIA CUDA", 11))
{
device->exceptions |= DT_OPENCL_ONLY_CUDA;
dt_print_nts(DT_DEBUG_OPENCL, " CL EXCEPTION: DT_OPENCL_ONLY_CUDA\n");
}
}

// clang-format off
// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
// vim: shiftwidth=2 expandtab tabstop=2 cindent
Expand Down
7 changes: 7 additions & 0 deletions src/iop/demosaic.c
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,13 @@ int process_cl(dt_iop_module_t *self,
const dt_iop_demosaic_global_data_t *gd = self->global_data;

int demosaicing_method = d->demosaicing_method;

// We do a PPG to RCD demosaicer fallback here as the used driver is known to fail.
// Also could "return DT_OPENCL_DT_EXCEPTION" for a cpu fallback
if(demosaicing_method == DT_IOP_DEMOSAIC_PPG
&& dt_opencl_exception(piece->pipe->devid, DT_OPENCL_AMD_APP))
demosaicing_method = DT_IOP_DEMOSAIC_RCD;

const int width = roi_in->width;
const int height = roi_in->height;

Expand Down

0 comments on commit fb8a96d

Please sign in to comment.