31static inline void _lap5(
const float *
const restrict field,
float *
const restrict laplacian,
const int region_w,
35 for(
int y = 0; y < region_h; y++)
37 for(
int x = 0;
x < region_w;
x++)
40 const int y_north = (y > 0) ? (y - 1) : y;
41 const int y_south = (y < region_h - 1) ? (y + 1) : y;
42 const int x_west = (
x > 0) ? (
x - 1) :
x;
43 const int x_east = (
x < region_w - 1) ? (
x + 1) :
x;
46 const float c = field[(size_t)y * region_w +
x];
47 const float north = field[(size_t)y_north * region_w +
x];
48 const float south = field[(size_t)y_south * region_w +
x];
49 const float west = field[(size_t)y * region_w + x_west];
50 const float east = field[(size_t)y * region_w + x_east];
51 const float north_west = field[(size_t)y_north * region_w + x_west];
52 const float north_east = field[(size_t)y_north * region_w + x_east];
53 const float south_west = field[(size_t)y_south * region_w + x_west];
54 const float south_east = field[(size_t)y_south * region_w + x_east];
57 laplacian[(size_t)y * region_w +
x]
58 = (4.f * (north + south + west + east) + (north_west + north_east + south_west + south_east) - 20.f * c)
69static inline void _apply_op(
const float *
const restrict field,
float *
const restrict output_field,
70 float *
const restrict scratch,
const int order,
const int region_w,
73 const size_t region_pixels = (size_t)region_w * region_h;
76 _lap5(field, output_field, region_w, region_h);
77 for(
size_t i = 0;
i < region_pixels;
i++) output_field[
i] = -output_field[
i];
81 _lap5(field, scratch, region_w, region_h);
82 _lap5(scratch, output_field, region_w, region_h);
91static int _sp_row_l9(
const int y,
const int x,
const int region_w,
const int region_h,
92 int *
const restrict targets,
double *
const restrict target_weights)
94 static const int offset_y[9] = { 0, -1, 1, 0, 0, -1, -1, 1, 1 };
95 static const int offset_x[9] = { 0, 0, 0, -1, 1, -1, 1, -1, 1 };
96 static const double stencil_weight[9]
97 = { -20. / 6., 4. / 6., 4. / 6., 4. / 6., 4. / 6., 1. / 6., 1. / 6., 1. / 6., 1. / 6. };
99 for(
int k = 0;
k < 9;
k++)
101 const int neighbour_y = CLAMP(y + offset_y[
k], 0, region_h - 1);
102 const int neighbour_x = CLAMP(
x + offset_x[
k], 0, region_w - 1);
103 const int target = neighbour_y * region_w + neighbour_x;
105 for(; slot < count; slot++)
106 if(targets[slot] == target)
108 target_weights[slot] += stencil_weight[
k];
113 targets[count] = target;
114 target_weights[count] = stencil_weight[
k];
126static int _sp_row_op(
const int grid_index,
const int order,
const int region_w,
const int region_h,
127 int *
const restrict targets,
double *
const restrict target_weights)
129 const int y = grid_index / region_w;
130 const int x = grid_index - y * region_w;
132 double lap_weights[9];
133 const int lap_count =
_sp_row_l9(y,
x, region_w, region_h, lap_targets, lap_weights);
136 for(
int i = 0;
i < lap_count;
i++)
138 targets[
i] = lap_targets[
i];
139 target_weights[
i] = -lap_weights[
i];
145 double lap2_weights[9];
146 for(
int i = 0;
i < lap_count;
i++)
148 const int mid_y = lap_targets[
i] / region_w;
149 const int mid_x = lap_targets[
i] - mid_y * region_w;
150 const int lap2_count =
_sp_row_l9(mid_y, mid_x, region_w, region_h, lap2_targets, lap2_weights);
151 for(
int j = 0; j < lap2_count; j++)
153 const int target = lap2_targets[j];
154 const double value = lap_weights[
i] * lap2_weights[j];
156 for(; slot < count; slot++)
157 if(targets[slot] == target)
159 target_weights[slot] +=
value;
164 targets[count] = target;
165 target_weights[count] =
value;
173int _sp_pde_assemble(
const uint8_t *
const restrict hole,
const float *
const restrict diffusion,
174 const float diffusion_const,
const int order,
const float lambda,
const int region_w,
175 const int region_h,
int **matrix_col_ptr_out,
int **matrix_row_index_out,
176 double **matrix_values_out,
int **perm_grid_out,
int *n_unknowns_out,
179 const size_t region_pixels = (size_t)region_w * region_h;
181 for(
size_t i = 0;
i < region_pixels;
i++)
182 if(hole[
i]) n_unknowns++;
191 int *matrix_col_ptr = NULL, *matrix_row_index = NULL, *inverse_perm = NULL, *perm_grid = NULL;
192 double *matrix_values = NULL;
193 if(!grid_to_unknown || !unknown_to_grid || !unknown_x || !unknown_y || !
permutation)
goto done;
195 int unknown_index = 0;
196 for(
size_t i = 0;
i < region_pixels;
i++)
198 grid_to_unknown[
i] = hole[
i] ? unknown_index : -1;
201 unknown_to_grid[unknown_index] = (int)
i;
202 unknown_y[unknown_index] = (int)(
i / region_w);
203 unknown_x[unknown_index] = (int)(
i - (
size_t)unknown_y[unknown_index] * region_w);
209 const int reach = (order == 1) ? 1 : 2;
213 if(!inverse_perm)
goto done;
214 for(
int perm_index = 0; perm_index < n_unknowns; perm_index++)
215 inverse_perm[
permutation[perm_index]] = perm_index;
219 if(!matrix_col_ptr)
goto done;
222 double target_weights[25];
224 for(
int pass = 0; pass < 2; pass++)
229 for(
int perm_index = 0; perm_index < n_unknowns; perm_index++)
231 const int col_count = matrix_col_ptr[perm_index];
232 matrix_col_ptr[perm_index] = total;
235 matrix_col_ptr[n_unknowns] = total;
238 if(!matrix_row_index || !matrix_values)
goto done;
241 for(
int perm_index = 0; perm_index < n_unknowns; perm_index++)
243 const int origin_grid = unknown_to_grid[
permutation[perm_index]];
244 const int count =
_sp_row_op(origin_grid, order, region_w, region_h, targets, target_weights);
245 int n_col_entries = 0;
247 for(
int slot = 0; slot < count; slot++)
249 const int target_grid = targets[slot];
250 const int target_unknown = grid_to_unknown[target_grid];
251 if(target_unknown < 0)
continue;
252 const int target_row = inverse_perm[target_unknown];
253 if(target_row > perm_index)
continue;
259 double value = target_weights[slot];
261 if(target_row == perm_index)
267 matrix_row_index[matrix_col_ptr[perm_index] + n_col_entries] = target_row;
268 matrix_values[matrix_col_ptr[perm_index] + n_col_entries] =
value;
272 if(pass == 0) matrix_col_ptr[perm_index] = n_col_entries;
278 if(!perm_grid)
goto done;
279 for(
int perm_index = 0; perm_index < n_unknowns; perm_index++)
280 perm_grid[perm_index] = unknown_to_grid[
permutation[perm_index]];
292 *matrix_col_ptr_out = matrix_col_ptr;
293 *matrix_row_index_out = matrix_row_index;
294 *matrix_values_out = matrix_values;
295 *perm_grid_out = perm_grid;
296 *n_unknowns_out = n_unknowns;
309 const int order,
const float lambda,
const int region_w,
const int region_h,
312 int *matrix_col_ptr = NULL, *matrix_row_index = NULL, *perm_grid = NULL;
313 double *matrix_values = NULL;
315 if(!
_sp_pde_assemble(hole, diffusion, 0.f, order, lambda, region_w, region_h, &matrix_col_ptr, &matrix_row_index,
316 &matrix_values, &perm_grid, &n_unknowns, pipe))
328 *perm_out = perm_grid;
329 *n_unknowns_out = n_unknowns;
335 float *
const restrict field,
const uint8_t *
const restrict hole,
336 const float *
const restrict diffusion,
const float *
const restrict target,
337 const float *
const restrict source,
const int order,
const float lambda,
const int region_w,
338 const int region_h,
double *
const restrict rhs,
float *
const restrict embedded,
339 float *
const restrict operator_out,
float *
const restrict scratch)
341 const size_t region_pixels = (size_t)region_w * region_h;
345 for(
size_t i = 0;
i < region_pixels;
i++) embedded[
i] = hole[
i] ? 0.f : field[
i];
347 _apply_op(embedded, operator_out, scratch, order, region_w, region_h);
349 const int n_unknowns =
factor->dimension;
351 for(
int unknown_index = 0; unknown_index < n_unknowns; unknown_index++)
353 const size_t i = (size_t)perm_grid[unknown_index];
356 rhs[unknown_index] = (diffusion ? (
double)diffusion[
i] * target[
i] : 0.0) + (source ? (
double)source[
i] : 0.0)
357 - (
double)lambda * operator_out[
i];
363 for(
int unknown_index = 0; unknown_index < n_unknowns; unknown_index++)
364 field[perm_grid[unknown_index]] = (
float)rhs[unknown_index];
369 const float *
const restrict diffusion,
const float *
const restrict target,
370 const float *
const restrict source,
const int order,
const float lambda,
const int region_w,
371 const int region_h,
float *
const restrict residual,
float *
const restrict search_dir,
372 float *
const restrict operator_dir,
float *
const restrict embedded,
373 float *
const restrict scratch,
const int maxiter)
375 const size_t region_pixels = (size_t)region_w * region_h;
378 for(
size_t i = 0;
i < region_pixels;
i++) embedded[
i] = hole[
i] ? 0.f : field[
i];
380 _apply_op(embedded, scratch, operator_dir, order, region_w, region_h);
383 for(
size_t i = 0;
i < region_pixels;
i++)
386 ? ((diffusion ? diffusion[
i] * target[
i] : 0.f) + (source ? source[
i] : 0.f) - lambda * scratch[
i])
391 for(
size_t i = 0;
i < region_pixels;
i++) embedded[
i] = hole[
i] ? field[
i] : 0.f;
393 _apply_op(embedded, scratch, operator_dir, order, region_w, region_h);
395 double residual_sq = 0.0;
397 for(
size_t i = 0;
i < region_pixels;
i++)
405 residual[
i] -= (diffusion ? diffusion[
i] * field[
i] : 0.f) + lambda * scratch[
i];
406 search_dir[
i] = residual[
i];
407 residual_sq += (
double)residual[
i] * residual[
i];
410 const double residual_sq0 = residual_sq;
411 if(residual_sq0 < 1e-20)
return;
412 for(
int iter = 0; iter < maxiter; iter++)
415 for(
size_t i = 0;
i < region_pixels;
i++) embedded[
i] = hole[
i] ? search_dir[
i] : 0.f;
417 _apply_op(embedded, scratch, operator_dir, order, region_w, region_h);
419 double dir_operator_dot = 0.0;
421 for(
size_t i = 0;
i < region_pixels;
i++)
425 operator_dir[
i] = 0.f;
429 operator_dir[
i] = (diffusion ? diffusion[
i] * search_dir[
i] : 0.f) + lambda * scratch[
i];
430 dir_operator_dot += (
double)search_dir[
i] * operator_dir[
i];
433 if(dir_operator_dot <= 1e-30)
break;
434 const float alpha = (float)(residual_sq / dir_operator_dot);
435 double new_residual_sq = 0.0;
438 for(
size_t i = 0;
i < region_pixels;
i++)
441 field[
i] += alpha * search_dir[
i];
442 residual[
i] -= alpha * operator_dir[
i];
443 new_residual_sq += (
double)residual[
i] * residual[
i];
446 if(new_residual_sq < 1e-4 * residual_sq0)
break;
447 const float beta = (float)(new_residual_sq / residual_sq);
450 for(
size_t i = 0;
i < region_pixels;
i++)
451 if(hole[
i]) search_dir[
i] = residual[
i] + beta * search_dir[
i];
453 residual_sq = new_residual_sq;
463#if defined(HAVE_OPENCL) && DT_HL_SPARSE_SOLVE
464cl_int _region_blur1_cl(
const int devid, cl_mem in, cl_mem
out,
const int region_w,
const int region_h,
467 const float vmax[1] = { 1e9f };
468 const float vmin[1] = { -1e9f };
476cl_int _region_pde_cg_cl(
const int devid,
void *gd_void, cl_mem solution, cl_mem hole,
const int region_w,
477 const int region_h,
const float dscalar,
const float tscalar,
const int maxiter)
480 const size_t region_pixels = (size_t)region_w * region_h;
481 const int unknown_count = (int)region_pixels;
484 const int local_size = 64, n_groups = 256;
485 size_t work_size_1d[3] = { (size_t)n_groups * local_size, 1, 1 };
486 size_t local_size_1d[3] = { local_size, 1, 1 };
496 double partial_sums[256];
497 if(!temp1 || !temp2 || !residual || !search_dir || !matvec || !partials)
goto out;
499#define CG_EMBED(src_, keep_) \
502 const int kernel = global_data->kernel_hl_cg_embed; \
503 const int keep_flag = (keep_); \
504 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &(src_)); \
505 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &hole); \
506 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(cl_mem), &temp1); \
507 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), ®ion_w); \
508 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(int), ®ion_h); \
509 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(int), &keep_flag); \
510 cl_err = dt_opencl_enqueue_kernel_2d(devid, kernel, work_size); \
511 if(cl_err != CL_SUCCESS) goto out; \
512 const int kernel_op = global_data->kernel_hl_cg_op; \
513 dt_opencl_set_kernel_arg(devid, kernel_op, 0, sizeof(cl_mem), &temp1); \
514 dt_opencl_set_kernel_arg(devid, kernel_op, 1, sizeof(cl_mem), &temp2); \
515 dt_opencl_set_kernel_arg(devid, kernel_op, 2, sizeof(int), ®ion_w); \
516 dt_opencl_set_kernel_arg(devid, kernel_op, 3, sizeof(int), ®ion_h); \
517 cl_err = dt_opencl_enqueue_kernel_2d(devid, kernel_op, work_size); \
518 if(cl_err != CL_SUCCESS) goto out; \
522 CG_EMBED(solution, 0);
533 if(cl_err != CL_SUCCESS)
goto out;
537 CG_EMBED(solution, 1);
538 double residual_norm;
551 if(cl_err != CL_SUCCESS)
goto out;
554 if(cl_err != CL_SUCCESS)
goto out;
556 for(
int group_index = 0; group_index < n_groups; group_index++) residual_norm += partial_sums[group_index];
559 const double residual_norm_init = residual_norm;
560 if(residual_norm_init < 1e-20)
566 for(
int iteration = 0; iteration < maxiter; iteration++)
568 CG_EMBED(search_dir, 1);
581 if(cl_err != CL_SUCCESS)
goto out;
584 if(cl_err != CL_SUCCESS)
goto out;
586 for(
int group_index = 0; group_index < n_groups; group_index++) p_dot_matvec += partial_sums[group_index];
589 if(p_dot_matvec <= 1e-30)
break;
590 const float alpha = (float)(residual_norm / p_dot_matvec);
591 double residual_norm_new;
604 if(cl_err != CL_SUCCESS)
goto out;
607 if(cl_err != CL_SUCCESS)
goto out;
608 residual_norm_new = 0.0;
609 for(
int group_index = 0; group_index < n_groups; group_index++)
610 residual_norm_new += partial_sums[group_index];
613 if(residual_norm_new < 1e-4 * residual_norm_init)
break;
614 const float beta = (float)(residual_norm_new / residual_norm);
624 if(cl_err != CL_SUCCESS)
goto out;
626 residual_norm = residual_norm_new;
const dt_colormatrix_t dt_aligned_pixel_t out
#define dt_pixelpipe_cache_alloc_align(size, pipe)
#define dt_pixelpipe_cache_free_align(mem)
#define __DT_CLONE_TARGETS__
#define __OMP_PARALLEL_FOR__(...)
static const dt_aligned_pixel_simd_t value
static float gaussian(float x, float std)
void dt_gaussian_free_cl(dt_gaussian_cl_t *g)
cl_int dt_gaussian_blur_cl(dt_gaussian_cl_t *g, cl_mem dev_in, cl_mem dev_out)
dt_gaussian_cl_t * dt_gaussian_init_cl(const int devid, const int width, const int height, const int channels, const float *max, const float *min, const float sigma, const int order)
static float kernel(const float *x, const float *y)
float *const restrict const size_t k
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_read_buffer_from_device(const int devid, void *host, void *device, const size_t offset, const size_t size, const int blocking)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
int dt_opencl_enqueue_kernel_2d_with_local(const int dev, const int kernel, const size_t *sizes, const size_t *local)
void dt_opencl_release_mem_object(cl_mem mem)
#define DT_OPENCL_DEFAULT_ERROR
__DT_CLONE_TARGETS__ void _region_pde_solve(float *const restrict field, const uint8_t *const restrict hole, const float *const restrict diffusion, const float *const restrict target, const float *const restrict source, const int order, const float lambda, const int region_w, const int region_h, float *const restrict residual, float *const restrict search_dir, float *const restrict operator_dir, float *const restrict embedded, float *const restrict scratch, const int maxiter)
static void _apply_op(const float *const restrict field, float *const restrict output_field, float *const restrict scratch, const int order, const int region_w, const int region_h)
_sp_chol_t * _sp_pde_factor(const uint8_t *const restrict hole, const float *const restrict diffusion, const int order, const float lambda, const int region_w, const int region_h, int **perm_out, int *n_unknowns_out, const dt_dev_pixelpipe_t *pipe)
static int _sp_row_l9(const int y, const int x, const int region_w, const int region_h, int *const restrict targets, double *const restrict target_weights)
__DT_CLONE_TARGETS__ void _sp_pde_solve(const _sp_chol_t *const factor, const int *const restrict perm_grid, float *const restrict field, const uint8_t *const restrict hole, const float *const restrict diffusion, const float *const restrict target, const float *const restrict source, const int order, const float lambda, const int region_w, const int region_h, double *const restrict rhs, float *const restrict embedded, float *const restrict operator_out, float *const restrict scratch)
static void _lap5(const float *const restrict field, float *const restrict laplacian, const int region_w, const int region_h)
int _sp_pde_assemble(const uint8_t *const restrict hole, const float *const restrict diffusion, const float diffusion_const, const int order, const float lambda, const int region_w, const int region_h, int **matrix_col_ptr_out, int **matrix_row_index_out, double **matrix_values_out, int **perm_grid_out, int *n_unknowns_out, const dt_dev_pixelpipe_t *const pipe)
static int _sp_row_op(const int grid_index, const int order, const int region_w, const int region_h, int *const restrict targets, double *const restrict target_weights)
static void _sp_nd_order(int *const restrict unknown_ids, const int count, const int *const restrict unknown_x, const int *const restrict unknown_y, const int reach)
static _sp_chol_t * _sp_chol_factor(const int dimension, const int *const restrict matrix_col_ptr, const int *const restrict matrix_row_index, const double *const restrict matrix_values, const dt_dev_pixelpipe_t *pipe)
static void _sp_chol_solve(const _sp_chol_t *const factor, double *const restrict rhs)
typedef double((*spd)(unsigned long int wavelength, double TempK))