71 for(
size_t i = 0;
i < npix;
i++)
75 maskb[
i] = (clipping_mask[
i * 4 + 3] >= 1e-3f);
95 for(
int region_index = 0; region_index < nreg; region_index++)
127 const uint8_t(*
const xtrans)[6]
134 float *
const restrict interpolated
136 float *
const restrict clipping_mask
145 const float *
const restrict input = (
const float *
const restrict)ivoid;
146 float *
const restrict output = (
float *
const restrict)
ovoid;
161 for(
int c = 0; c < 3; c++)
163 clipvaln[c] = clips[c] / (
DT_HL_KNEE_DET * fmaxf(normalization[c], 1e-9f));
183 for(
int c = 0; c < 3; c++)
201 int32_t
lookup[6][6][32] = { { { 0 } } };
236 const float *remosaic_input = input;
237 float *input_corr = NULL;
246 remosaic_input = input_corr;
259 _remosaic_and_replace(remosaic_input, input, interpolated, clipping_mask, output, normalization, clips,
305 float *
const restrict interpolated,
float *
const restrict clipping_mask,
313 const uint8_t(*
const xtrans)[6] = (filters == 9u) ? (
const uint8_t(*
const)[6])
piece->dsc_in.xtrans : NULL;
318 *remosaic_input_out = input;
319 *input_corr_out = NULL;
324 memcpy(knee, knee_pre,
sizeof(knee));
327 for(
int c = 0; c < 3; c++)
329 clipvaln[c] = clips[c] / (
DT_HL_KNEE_DET * fmaxf(normalization[c], 1e-9f));
345 *remosaic_input_out = input_corr;
346 *input_corr_out = input_corr;
354#define HL_CL_RELEASE(mem_obj) \
357 dt_opencl_release_mem_object(mem_obj); \
385 const size_t n_in = (size_t)roi_in->
width * roi_in->
height;
386 const size_t n_out = (size_t)roi_out->
width * roi_out->
height;
396 if(cl_err != CL_SUCCESS)
goto error;
438 cl_mem mask_buf, cl_mem *corr_out,
const dt_iop_roi_t *
const roi_in,
445 const uint32_t filters =
piece->dsc_in.filters;
449 const int is_xtrans = (filters == 9u);
457 cl_mem member = NULL;
458 cl_mem depth_dev = NULL;
460 uint8_t *h_seed = NULL;
461 uint8_t *h_member = NULL;
470 memcpy(knee, knee_pre,
sizeof(knee));
473 for(
int c = 0; c < 3; c++)
475 clipvaln[c] = clips[c] / (
DT_HL_KNEE_DET * fmaxf(norm[c], 1e-9f));
484 for(
int c = 0; c < 3; c++) memcpy(lift + c *
DT_HL_KNEE_BINS, knee[c].lift,
sizeof(knee[c].lift));
492 const cl_float4 clip4 = { { clipvaln[0], clipvaln[1], clipvaln[2], 1.f } };
493 const cl_float4 wb4 = { { norm[0], norm[1], norm[2], 1.f } };
510 if(cl_err != CL_SUCCESS)
goto out;
520 is_xtrans, knee_clipraw, knee);
521 if(cl_err != CL_SUCCESS)
goto out;
531 if(!seed || !member || !h_seed || !h_member || !depth)
544 if(cl_err != CL_SUCCESS)
goto out;
548 if(cl_err != CL_SUCCESS)
goto out;
563 if(cl_err != CL_SUCCESS)
goto out;
570 const char *override_env = getenv(
"HL_CL_CPU_PX");
571 if(override_env) cpu_px = (size_t)strtoull(override_env, NULL, 10);
572 for(
int region_index = 0; region_index < nreg && cl_err == CL_SUCCESS; region_index++)
584 const int region_w = regions[region_index].
rx1 - regions[region_index].
rx0 + 1;
585 const int region_h = regions[region_index].
ry1 - regions[region_index].
ry0 + 1;
586 const size_t region_px = (size_t)region_w * region_h;
590 const gboolean fits = region_px <= cpu_px
595 "[opencl_highlights] harmonic region window %dx%d does not fit the device, reconstructed on the CPU\n",
597 if(region_px <= cpu_px || !fits)
601 cl_err = _region_cpu_offload_cl(devid, global_data, interp_buf, mask_buf, depth_dev,
width,
608 cl_err = _region_guided_filter_cl(devid, global_data, interp_buf, mask_buf, depth_dev,
width,
614 if(cl_err == CL_SUCCESS)
628 if(cl_err == CL_SUCCESS)
660 const uint32_t filters =
piece->dsc_in.filters;
665 const int is_xtrans = (filters == 9u);
669 const int is_passthrough = (filters == 0u);
670 const size_t in_channels = is_passthrough ? 4 : 1;
674 cl_mem interpolated = NULL;
675 cl_mem clipping_mask = NULL;
677 cl_mem clips_cl = NULL;
678 cl_mem normalization_final = NULL;
679 cl_mem dev_xtrans = NULL;
680 cl_mem lookup_cl = NULL;
681 cl_mem corr_cl = NULL;
682 cl_mem det_clips_cl = NULL;
683 float *h_interp = NULL;
684 float *h_mask = NULL;
686 float *input_corr = NULL;
687 const float *remosaic_input = NULL;
700 (
void *)
piece->dsc_in.xtrans);
701 int32_t
lookup[6][6][32] = { { { 0 } } };
715 if(cl_err != CL_SUCCESS)
goto fallback;
721 is_xtrans ? (
const uint8_t(*
const)[6])
piece->dsc_in.xtrans : NULL, norm_host);
723 if(
IS_NULL_PTR(normalization_final))
goto fallback;
733 for(
int c = 0; c < 3; c++) knee_clipraw[c] = clips[c] /
DT_HL_KNEE_DET;
738 size_t korigin[3] = { 0, 0, 0 };
739 size_t kregion[3] = { (size_t)
width, (
size_t)
height, 1 };
741 if(cl_err != CL_SUCCESS)
748 is_xtrans, knee_clipraw, knee,
pipe);
750 if(cl_err != CL_SUCCESS)
goto fallback;
755 for(
int c = 0; c < 3; c++)
772 &normalization_final);
787 else if(is_passthrough)
792 sizeof(cl_mem), &dev_in);
794 sizeof(cl_mem), &interpolated);
796 sizeof(cl_mem), &clipping_mask);
798 sizeof(cl_mem), &det_clips_cl);
800 sizeof(cl_mem), &normalization_final);
818 &normalization_final);
827 if(cl_err != CL_SUCCESS)
goto fallback;
835 cl_mem corr_buf = NULL;
836 size_t origin[3] = { 0, 0, 0 };
837 size_t region1[3] = { (size_t)
width, (
size_t)
height, 1 };
841 if(gpu_err == CL_SUCCESS && !is_passthrough)
843 if(gpu_err == CL_SUCCESS)
845 if(gpu_err == CL_SUCCESS)
848 if(gpu_err == CL_SUCCESS)
855 if(!getenv(
"HL_MIDDLE_AB"))
864 clips, norm_host, dev_xtrans, knee);
871 if(gpu_err == CL_SUCCESS && corr_buf)
882 if(gpu_err == CL_SUCCESS && getenv(
"HL_MIDDLE_AB"))
888 if(gpu_interp && host_interp && host_mask && host_raw
897 const float *remosaic_ptr = NULL;
898 float *input_corr_ab = NULL;
900 norm_host, &remosaic_ptr, &input_corr_ab, knee))
902 float max_diff = 0.f;
903 double sum_diff = 0.0;
904 size_t arg_index = 0;
905 for(
size_t i = 0;
i < npix * 4;
i++)
907 const float diff = fabsf(gpu_interp[
i] - host_interp[
i]);
915 fprintf(stderr,
"[hl middle AB] max=%.3e mean=%.3e at px=(%llu,%llu) c=%llu gpu=%f cpu=%f\n", max_diff,
916 sum_diff / (
double)(npix * 4), (
unsigned long long)((arg_index / 4) %
width),
917 (
unsigned long long)((arg_index / 4) /
width), (
unsigned long long)(arg_index % 4),
918 gpu_interp[arg_index], host_interp[arg_index]);
939 if(restore_err == CL_SUCCESS && gpu_err == CL_SUCCESS)
942 if(restore_err == CL_SUCCESS)
945 else if(restore_err == CL_SUCCESS)
949 if(restore_err == CL_SUCCESS)
981 if(restore_err == CL_SUCCESS)
991 if(restore_err != CL_SUCCESS)
997 cl_err = restore_err;
1001 else if(gpu_err == CL_SUCCESS)
1006 if(restore_err == CL_SUCCESS)
1008 if(restore_err != CL_SUCCESS)
1014 cl_err = restore_err;
1022 if(gpu_err == CL_SUCCESS)
goto remosaic;
1043 if(cl_err != CL_SUCCESS)
goto fallback;
1045 if(cl_err != CL_SUCCESS)
goto fallback;
1049 &remosaic_input, &input_corr, knee))
1054 if(cl_err != CL_SUCCESS)
goto fallback;
1060 cl_mem remosaic_in_cl = dev_in;
1062 remosaic_in_cl = corr_cl;
1063 else if(remosaic_input != h_raw && remosaic_input != NULL)
1068 if(cl_err != CL_SUCCESS)
goto fallback;
1069 remosaic_in_cl = corr_cl;
1074 const int clip_floor_on =
TRUE;
1086 &normalization_final);
1103 else if(is_passthrough)
1107 const int clip_floor_on =
TRUE;
1109 sizeof(cl_mem), &remosaic_in_cl);
1111 sizeof(cl_mem), &dev_in);
1113 sizeof(cl_mem), &interpolated);
1115 sizeof(cl_mem), &clipping_mask);
1117 sizeof(cl_mem), &dev_out);
1119 sizeof(cl_mem), &normalization_final);
1121 sizeof(cl_mem), &clips_cl);
1123 sizeof(
int), &clip_floor_on);
1125 sizeof(
int), &
width);
1133 const int clip_floor_on =
TRUE;
1145 &normalization_final);
1156 if(cl_err != CL_SUCCESS)
goto fallback;
1176 "[opencl_highlights] harmonic GPU gather failed (%i), falling back to the host roundtrip\n", cl_err);
static void error(char *msg)
void _hl_gauss_cache_flush(void)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static float lookup(read_only image2d_t lut, const float x)
const dt_colormatrix_t dt_aligned_pixel_t out
__DT_CLONE_TARGETS__ void _interpolate_and_mask_passthrough(const float *const restrict input, float *const restrict interpolated, float *const restrict clipping_mask, const dt_aligned_pixel_t clips, const dt_aligned_pixel_t white_balance, const size_t width, const size_t height)
__DT_CLONE_TARGETS__ void _compute_laplacian_normalization(const float *const restrict input, const dt_iop_roi_t *const roi_in, const uint32_t filters, const uint8_t(*const xtrans)[6], dt_aligned_pixel_t normalization)
__DT_CLONE_TARGETS__ void _remosaic_and_replace_xtrans(const float *const restrict input, const float *const restrict input_raw, const float *const restrict interpolated, const float *const restrict clipping_mask, float *const restrict output, const dt_aligned_pixel_t white_balance, const dt_aligned_pixel_t clips, const int clip_is_floor, const dt_iop_roi_t *const roi_in, const uint8_t(*const xtrans)[6], const size_t width, const size_t height)
__DT_CLONE_TARGETS__ void _interpolate_and_mask(const float *const restrict input, float *const restrict interpolated, float *const restrict clipping_mask, const dt_aligned_pixel_t clips_in, const dt_aligned_pixel_t det_scale, const dt_aligned_pixel_t white_balance, const uint32_t filters, const size_t width, const size_t height)
__DT_CLONE_TARGETS__ void _remosaic_and_replace(const float *const restrict input, const float *const restrict input_raw, const float *const restrict interpolated, const float *const restrict clipping_mask, float *const restrict output, const dt_aligned_pixel_t white_balance, const dt_aligned_pixel_t clips, const int clip_is_floor, const uint32_t filters, const size_t width, const size_t height)
__DT_CLONE_TARGETS__ void _interpolate_and_mask_xtrans(const float *const restrict input, float *const restrict interpolated, float *const restrict clipping_mask, const dt_aligned_pixel_t clips, const dt_aligned_pixel_t white_balance, const dt_iop_roi_t *const roi_in, const int32_t lookup[6][6][32], const uint8_t(*const xtrans)[6], const size_t width, const size_t height)
__DT_CLONE_TARGETS__ void _build_xtrans_bilinear_lookup(int32_t lookup[6][6][32], const dt_iop_roi_t *const roi_in, const uint8_t(*const xtrans)[6])
__DT_CLONE_TARGETS__ void _remosaic_and_replace_passthrough(const float *const restrict input, const float *const restrict input_raw, const float *const restrict interpolated, const float *const restrict clipping_mask, float *const restrict output, const dt_aligned_pixel_t white_balance, const dt_aligned_pixel_t clips, const int clip_is_floor, const size_t width, const size_t height)
static dt_hl_cfa_t _hl_cfa_strategy(const uint32_t filters)
uint32_t dt_dev_get_roi_filters(const dt_dev_pixelpipe_iop_t *const piece, const dt_iop_roi_t *const roi_in)
float dt_dev_get_module_scale(const dt_dev_pixelpipe_t *const pipe, const dt_iop_roi_t *const roi_in)
static float kernel(const float *x, const float *y)
__DT_CLONE_TARGETS__ void _hl_knee_apply_interpolated(float *const restrict interpolated, const size_t npix, const dt_aligned_pixel_t clipvaln, const dt_aligned_pixel_t wb4, const _hl_knee_curve_t curves[3])
__DT_CLONE_TARGETS__ void _hl_knee_apply_cfa(const float *const restrict input, float *const restrict input_corr, const size_t width, const size_t height, const uint32_t filters, const dt_iop_roi_t *const roi_in, const uint8_t(*const xtrans)[6], const dt_aligned_pixel_t clipval_raw, const _hl_knee_curve_t curves[3])
__DT_CLONE_TARGETS__ int _hl_knee_estimate(const float *const restrict input, const size_t width, const size_t height, const uint32_t filters, const dt_iop_roi_t *const roi_in, const uint8_t(*const xtrans)[6], const dt_aligned_pixel_t clipval_raw, _hl_knee_curve_t curves[3], const dt_dev_pixelpipe_t *pipe)
cl_int _hl_knee_estimate_cl(const int devid, void *gd_void, cl_mem dev_in, const size_t width, const size_t height, const uint32_t filters, const dt_iop_roi_t *const roi_in, cl_mem dev_xtrans, const int is_xtrans, const dt_aligned_pixel_t clipval_raw, _hl_knee_curve_t curves[3], const dt_dev_pixelpipe_t *pipe)
cl_int _hl_knee_apply_cfa_cl(const int devid, void *gd_void, cl_mem dev_in, cl_mem dev_out, const size_t width, const size_t height, const uint32_t filters, const dt_iop_roi_t *const roi_in, cl_mem dev_xtrans, const int is_xtrans, const dt_aligned_pixel_t clipval_raw, const _hl_knee_curve_t curves[3])
static const dt_dev_pixelpipe_t * pipe
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t * piece
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.
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
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)
int dt_opencl_copy_device_to_host(const int devid, void *host, void *device, const int width, const int height, const int bpp)
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
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)
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)
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)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
gboolean dt_opencl_finish(const int devid)
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)
void dt_opencl_release_mem_object(cl_mem mem)
int dt_opencl_write_host_to_device(const int devid, void *host, void *device, const int width, const int height, const int bpp)
#define DT_OPENCL_DEFAULT_ERROR
#define __OMP_PARALLEL_FOR__(...)
#define dt_pixelpipe_cache_alloc_align(size, pipe)
#define dt_pixelpipe_cache_free_align(mem)
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
static gboolean dt_dev_pixelpipe_has_shutdown(const dt_dev_pixelpipe_t *pipe)
cl_int process_harmonic_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const dt_aligned_pixel_t clips)
__DT_CLONE_TARGETS__ int process_harmonic(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const restrict ivoid, void *const restrict ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const dt_aligned_pixel_t clips)
#define HL_CL_RELEASE(mem_obj)
static __DT_CLONE_TARGETS__ int _harmonic_reconstruct_regions(float *const interpolated, const float *const clipping_mask, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *const roi_in, const dt_aligned_pixel_t clips)
static __DT_CLONE_TARGETS__ int _harmonic_reconstruct_host(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const float *const restrict input, float *const restrict interpolated, float *const restrict clipping_mask, const dt_iop_roi_t *const roi_in, const dt_aligned_pixel_t clips, const dt_aligned_pixel_t normalization, const float **remosaic_input_out, float **input_corr_out, const _hl_knee_curve_t knee_pre[3])
static cl_int _harmonic_cl_roundtrip(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const dt_aligned_pixel_t clips)
static cl_int _harmonic_reconstruct_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem raw_buf, cl_mem interp_buf, cl_mem mask_buf, cl_mem *corr_out, const dt_iop_roi_t *const roi_in, const dt_aligned_pixel_t clips, const dt_aligned_pixel_t norm, cl_mem dev_xtrans, const _hl_knee_curve_t knee_pre[3])
void _region_guided_filter(float *const restrict interp, const float *const restrict mask, const float *const restrict depth, const int width, const _hl_region_t *const region, const dt_dev_pixelpipe_t *pipe, const float solid_color, const int max_iter, const float noise_level, const float floor_gate, const float module_scale)
int _segment_clipped_regions(const uint8_t *const restrict maskb, const float *const restrict depth, const int width, const int height, const float pad_factor, const int pad_min, const int pad_max, _hl_region_t **regions_out)
void _hf_stage_cl_selftest(const int devid, void *gd_void, const dt_dev_pixelpipe_t *pipe)
void _region_guided_filter_cl_selftest(const int devid, void *gd_void, const dt_dev_pixelpipe_t *pipe)
void _knee_cl_selftest(const int devid, void *gd_void, const dt_dev_pixelpipe_t *pipe)
void _joint_core_stage_cl_selftest(const int devid, void *gd_void, const dt_dev_pixelpipe_t *pipe)
void _selfdome_stage_cl_selftest(const int devid, void *gd_void, const dt_dev_pixelpipe_t *pipe)
void _aniso_stage_cl_selftest(const int devid, void *gd_void, const dt_dev_pixelpipe_t *pipe)
void _cf_harmonic_fill_cl_selftest(const int devid, void *gd_void, const dt_dev_pixelpipe_t *pipe)
void _cf_stage_cl_selftest(const int devid, void *gd_void, const dt_dev_pixelpipe_t *pipe)
void _region_blur_cl_selftest(const int devid, const dt_dev_pixelpipe_t *pipe)
void _chromaticity_gradient_stage_cl_selftest(const int devid, void *gd_void, const dt_dev_pixelpipe_t *pipe)
void _cf_joint_stage_cl_selftest(const int devid, void *gd_void, const dt_dev_pixelpipe_t *pipe)
void _sp_chol_cl_selftest(const int devid, void *gd_void, const dt_dev_pixelpipe_t *pipe)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
#define for_four_channels(_var,...)
static cl_mem _sp_cl_upload(const int devid, const void *data, const size_t bytes)
static float _hl_floor_gate(const float clips[4])
#define DT_HL_CL_CPU_REGION_PX
#define DT_HL_CL_REGION_FLOATS_PER_PX
int kernel_highlights_bilinear_and_mask_passthrough
int kernel_hl_knee_apply_interp
int kernel_highlights_remosaic_and_replace
int kernel_highlights_remosaic_and_replace_passthrough
int kernel_highlights_bilinear_and_mask_xtrans
int kernel_highlights_box_blur
int kernel_highlights_remosaic_and_replace_xtrans
int kernel_highlights_bilinear_and_mask
dt_iop_global_data_t * global_data
Region of interest passed through the pixelpipe.
#define __DT_CLONE_TARGETS__
typedef double((*spd)(unsigned long int wavelength, double TempK))