29static inline void _lap5(
const float *
const restrict field,
float *
const restrict laplacian,
const int region_w,
33 for(
int y = 0; y < region_h; y++)
35 for(
int x = 0;
x < region_w;
x++)
38 const int y_north = (y > 0) ? (y - 1) : y;
39 const int y_south = (y < region_h - 1) ? (y + 1) : y;
40 const int x_west = (
x > 0) ? (
x - 1) :
x;
41 const int x_east = (
x < region_w - 1) ? (
x + 1) :
x;
44 const float c = field[(size_t)y * region_w +
x];
45 const float north = field[(size_t)y_north * region_w +
x];
46 const float south = field[(size_t)y_south * region_w +
x];
47 const float west = field[(size_t)y * region_w + x_west];
48 const float east = field[(size_t)y * region_w + x_east];
49 const float north_west = field[(size_t)y_north * region_w + x_west];
50 const float north_east = field[(size_t)y_north * region_w + x_east];
51 const float south_west = field[(size_t)y_south * region_w + x_west];
52 const float south_east = field[(size_t)y_south * region_w + x_east];
55 laplacian[(size_t)y * region_w +
x]
56 = (4.f * (north + south + west + east) + (north_west + north_east + south_west + south_east) - 20.f * c)
67static inline void _apply_op(
const float *
const restrict field,
float *
const restrict output_field,
68 float *
const restrict scratch,
const int order,
const int region_w,
71 const size_t region_pixels = (size_t)region_w * region_h;
74 _lap5(field, output_field, region_w, region_h);
75 for(
size_t i = 0;
i < region_pixels;
i++) output_field[
i] = -output_field[
i];
79 _lap5(field, scratch, region_w, region_h);
80 _lap5(scratch, output_field, region_w, region_h);
89static int _sp_row_l9(
const int y,
const int x,
const int region_w,
const int region_h,
90 int *
const restrict targets,
double *
const restrict target_weights)
92 static const int offset_y[9] = { 0, -1, 1, 0, 0, -1, -1, 1, 1 };
93 static const int offset_x[9] = { 0, 0, 0, -1, 1, -1, 1, -1, 1 };
94 static const double stencil_weight[9]
95 = { -20. / 6., 4. / 6., 4. / 6., 4. / 6., 4. / 6., 1. / 6., 1. / 6., 1. / 6., 1. / 6. };
97 for(
int k = 0;
k < 9;
k++)
99 const int neighbour_y = CLAMP(y + offset_y[
k], 0, region_h - 1);
100 const int neighbour_x = CLAMP(
x + offset_x[
k], 0, region_w - 1);
101 const int target = neighbour_y * region_w + neighbour_x;
103 for(; slot < count; slot++)
104 if(targets[slot] == target)
106 target_weights[slot] += stencil_weight[
k];
111 targets[count] = target;
112 target_weights[count] = stencil_weight[
k];
124static int _sp_row_op(
const int grid_index,
const int order,
const int region_w,
const int region_h,
125 int *
const restrict targets,
double *
const restrict target_weights)
127 const int y = grid_index / region_w;
128 const int x = grid_index - y * region_w;
130 double lap_weights[9];
131 const int lap_count =
_sp_row_l9(y,
x, region_w, region_h, lap_targets, lap_weights);
134 for(
int i = 0;
i < lap_count;
i++)
136 targets[
i] = lap_targets[
i];
137 target_weights[
i] = -lap_weights[
i];
143 double lap2_weights[9];
144 for(
int i = 0;
i < lap_count;
i++)
146 const int mid_y = lap_targets[
i] / region_w;
147 const int mid_x = lap_targets[
i] - mid_y * region_w;
148 const int lap2_count =
_sp_row_l9(mid_y, mid_x, region_w, region_h, lap2_targets, lap2_weights);
149 for(
int j = 0; j < lap2_count; j++)
151 const int target = lap2_targets[j];
152 const double value = lap_weights[
i] * lap2_weights[j];
154 for(; slot < count; slot++)
155 if(targets[slot] == target)
157 target_weights[slot] +=
value;
162 targets[count] = target;
163 target_weights[count] =
value;
171int _sp_pde_assemble(
const uint8_t *
const restrict hole,
const float *
const restrict diffusion,
172 const float diffusion_const,
const int order,
const float lambda,
const int region_w,
173 const int region_h,
int **matrix_col_ptr_out,
int **matrix_row_index_out,
174 double **matrix_values_out,
int **perm_grid_out,
int *n_unknowns_out,
177 const size_t region_pixels = (size_t)region_w * region_h;
179 for(
size_t i = 0;
i < region_pixels;
i++)
180 if(hole[
i]) n_unknowns++;
189 int *matrix_col_ptr = NULL, *matrix_row_index = NULL, *inverse_perm = NULL, *perm_grid = NULL;
190 double *matrix_values = NULL;
191 if(!grid_to_unknown || !unknown_to_grid || !unknown_x || !unknown_y || !
permutation)
goto done;
193 int unknown_index = 0;
194 for(
size_t i = 0;
i < region_pixels;
i++)
196 grid_to_unknown[
i] = hole[
i] ? unknown_index : -1;
199 unknown_to_grid[unknown_index] = (int)
i;
200 unknown_y[unknown_index] = (int)(
i / region_w);
201 unknown_x[unknown_index] = (int)(
i - (
size_t)unknown_y[unknown_index] * region_w);
207 const int reach = (order == 1) ? 1 : 2;
211 if(!inverse_perm)
goto done;
212 for(
int perm_index = 0; perm_index < n_unknowns; perm_index++)
213 inverse_perm[
permutation[perm_index]] = perm_index;
217 if(!matrix_col_ptr)
goto done;
220 double target_weights[25];
222 for(
int pass = 0; pass < 2; pass++)
227 for(
int perm_index = 0; perm_index < n_unknowns; perm_index++)
229 const int col_count = matrix_col_ptr[perm_index];
230 matrix_col_ptr[perm_index] = total;
233 matrix_col_ptr[n_unknowns] = total;
236 if(!matrix_row_index || !matrix_values)
goto done;
239 for(
int perm_index = 0; perm_index < n_unknowns; perm_index++)
241 const int origin_grid = unknown_to_grid[
permutation[perm_index]];
242 const int count =
_sp_row_op(origin_grid, order, region_w, region_h, targets, target_weights);
243 int n_col_entries = 0;
245 for(
int slot = 0; slot < count; slot++)
247 const int target_grid = targets[slot];
248 const int target_unknown = grid_to_unknown[target_grid];
249 if(target_unknown < 0)
continue;
250 const int target_row = inverse_perm[target_unknown];
251 if(target_row > perm_index)
continue;
257 double value = target_weights[slot];
259 if(target_row == perm_index)
265 matrix_row_index[matrix_col_ptr[perm_index] + n_col_entries] = target_row;
266 matrix_values[matrix_col_ptr[perm_index] + n_col_entries] =
value;
270 if(pass == 0) matrix_col_ptr[perm_index] = n_col_entries;
276 if(!perm_grid)
goto done;
277 for(
int perm_index = 0; perm_index < n_unknowns; perm_index++)
278 perm_grid[perm_index] = unknown_to_grid[
permutation[perm_index]];
290 *matrix_col_ptr_out = matrix_col_ptr;
291 *matrix_row_index_out = matrix_row_index;
292 *matrix_values_out = matrix_values;
293 *perm_grid_out = perm_grid;
294 *n_unknowns_out = n_unknowns;
307 const int order,
const float lambda,
const int region_w,
const int region_h,
310 int *matrix_col_ptr = NULL, *matrix_row_index = NULL, *perm_grid = NULL;
311 double *matrix_values = NULL;
313 if(!
_sp_pde_assemble(hole, diffusion, 0.f, order, lambda, region_w, region_h, &matrix_col_ptr, &matrix_row_index,
314 &matrix_values, &perm_grid, &n_unknowns, pipe))
326 *perm_out = perm_grid;
327 *n_unknowns_out = n_unknowns;
333 float *
const restrict field,
const uint8_t *
const restrict hole,
334 const float *
const restrict diffusion,
const float *
const restrict target,
335 const float *
const restrict source,
const int order,
const float lambda,
const int region_w,
336 const int region_h,
double *
const restrict rhs,
float *
const restrict embedded,
337 float *
const restrict operator_out,
float *
const restrict scratch)
339 const size_t region_pixels = (size_t)region_w * region_h;
343 for(
size_t i = 0;
i < region_pixels;
i++) embedded[
i] = hole[
i] ? 0.f : field[
i];
345 _apply_op(embedded, operator_out, scratch, order, region_w, region_h);
347 const int n_unknowns =
factor->dimension;
349 for(
int unknown_index = 0; unknown_index < n_unknowns; unknown_index++)
351 const size_t i = (size_t)perm_grid[unknown_index];
354 rhs[unknown_index] = (diffusion ? (
double)diffusion[
i] * target[
i] : 0.0) + (source ? (
double)source[
i] : 0.0)
355 - (
double)lambda * operator_out[
i];
361 for(
int unknown_index = 0; unknown_index < n_unknowns; unknown_index++)
362 field[perm_grid[unknown_index]] = (
float)rhs[unknown_index];
367 const float *
const restrict diffusion,
const float *
const restrict target,
368 const float *
const restrict source,
const int order,
const float lambda,
const int region_w,
369 const int region_h,
float *
const restrict residual,
float *
const restrict search_dir,
370 float *
const restrict operator_dir,
float *
const restrict embedded,
371 float *
const restrict scratch,
const int maxiter)
373 const size_t region_pixels = (size_t)region_w * region_h;
376 for(
size_t i = 0;
i < region_pixels;
i++) embedded[
i] = hole[
i] ? 0.f : field[
i];
378 _apply_op(embedded, scratch, operator_dir, order, region_w, region_h);
381 for(
size_t i = 0;
i < region_pixels;
i++)
384 ? ((diffusion ? diffusion[
i] * target[
i] : 0.f) + (source ? source[
i] : 0.f) - lambda * scratch[
i])
389 for(
size_t i = 0;
i < region_pixels;
i++) embedded[
i] = hole[
i] ? field[
i] : 0.f;
391 _apply_op(embedded, scratch, operator_dir, order, region_w, region_h);
393 double residual_sq = 0.0;
395 for(
size_t i = 0;
i < region_pixels;
i++)
403 residual[
i] -= (diffusion ? diffusion[
i] * field[
i] : 0.f) + lambda * scratch[
i];
404 search_dir[
i] = residual[
i];
405 residual_sq += (
double)residual[
i] * residual[
i];
408 const double residual_sq0 = residual_sq;
409 if(residual_sq0 < 1e-20)
return;
410 for(
int iter = 0; iter < maxiter; iter++)
413 for(
size_t i = 0;
i < region_pixels;
i++) embedded[
i] = hole[
i] ? search_dir[
i] : 0.f;
415 _apply_op(embedded, scratch, operator_dir, order, region_w, region_h);
417 double dir_operator_dot = 0.0;
419 for(
size_t i = 0;
i < region_pixels;
i++)
423 operator_dir[
i] = 0.f;
427 operator_dir[
i] = (diffusion ? diffusion[
i] * search_dir[
i] : 0.f) + lambda * scratch[
i];
428 dir_operator_dot += (
double)search_dir[
i] * operator_dir[
i];
431 if(dir_operator_dot <= 1e-30)
break;
432 const float alpha = (float)(residual_sq / dir_operator_dot);
433 double new_residual_sq = 0.0;
436 for(
size_t i = 0;
i < region_pixels;
i++)
439 field[
i] += alpha * search_dir[
i];
440 residual[
i] -= alpha * operator_dir[
i];
441 new_residual_sq += (
double)residual[
i] * residual[
i];
444 if(new_residual_sq < 1e-4 * residual_sq0)
break;
445 const float beta = (float)(new_residual_sq / residual_sq);
448 for(
size_t i = 0;
i < region_pixels;
i++)
449 if(hole[
i]) search_dir[
i] = residual[
i] + beta * search_dir[
i];
451 residual_sq = new_residual_sq;
460#if defined(HAVE_OPENCL) && DT_HL_SPARSE_SOLVE
461cl_int _region_blur1_cl(
const int devid, cl_mem in, cl_mem
out,
const int region_w,
const int region_h,
464 const float vmax[1] = { 1e9f };
465 const float vmin[1] = { -1e9f };
473cl_int _region_pde_cg_cl(
const int devid,
void *gd_void, cl_mem solution, cl_mem hole,
const int region_w,
474 const int region_h,
const float dscalar,
const float tscalar,
const int maxiter)
477 const size_t region_pixels = (size_t)region_w * region_h;
478 const int unknown_count = (int)region_pixels;
481 const int local_size = 64, n_groups = 256;
482 size_t work_size_1d[3] = { (size_t)n_groups * local_size, 1, 1 };
483 size_t local_size_1d[3] = { local_size, 1, 1 };
496 if(!temp1 || !temp2 || !residual || !search_dir || !matvec || !partials)
goto out;
498#define CG_EMBED(src_, keep_) \
501 const int kernel = global_data->kernel_hl_cg_embed; \
502 const int keep_flag = (keep_); \
503 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &(src_)); \
504 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &hole); \
505 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(cl_mem), &temp1); \
506 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), ®ion_w); \
507 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(int), ®ion_h); \
508 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(int), &keep_flag); \
509 cl_err = dt_opencl_enqueue_kernel_2d(devid, kernel, work_size); \
510 if(cl_err != CL_SUCCESS) goto out; \
511 const int kernel_op = global_data->kernel_hl_cg_op; \
512 dt_opencl_set_kernel_arg(devid, kernel_op, 0, sizeof(cl_mem), &temp1); \
513 dt_opencl_set_kernel_arg(devid, kernel_op, 1, sizeof(cl_mem), &temp2); \
514 dt_opencl_set_kernel_arg(devid, kernel_op, 2, sizeof(int), ®ion_w); \
515 dt_opencl_set_kernel_arg(devid, kernel_op, 3, sizeof(int), ®ion_h); \
516 cl_err = dt_opencl_enqueue_kernel_2d(devid, kernel_op, work_size); \
517 if(cl_err != CL_SUCCESS) goto out; \
521 CG_EMBED(solution, 0);
532 if(cl_err != CL_SUCCESS)
goto out;
536 CG_EMBED(solution, 1);
549 if(cl_err != CL_SUCCESS)
goto out;
551 const int slot_rr = 0, do_init = 1;
552 size_t cg_one[3] = { 1, 1, 1 };
559 if(cl_err != CL_SUCCESS)
goto out;
562 for(
int iteration = 0; iteration < maxiter; iteration++)
564 CG_EMBED(search_dir, 1);
576 if(cl_err != CL_SUCCESS)
goto out;
578 size_t cg_one[3] = { 1, 1, 1 };
583 if(cl_err != CL_SUCCESS)
goto out;
598 if(cl_err != CL_SUCCESS)
goto out;
600 const int slot_new = 1, no_init = 0;
601 size_t cg_one[3] = { 1, 1, 1 };
608 if(cl_err != CL_SUCCESS)
goto out;
616 if(cl_err != CL_SUCCESS)
goto out;
627 if(cl_err != CL_SUCCESS)
goto out;
const dt_colormatrix_t dt_aligned_pixel_t out
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_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
#define __OMP_PARALLEL_FOR__(...)
__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)
#define dt_pixelpipe_cache_alloc_align(size, pipe)
#define dt_pixelpipe_cache_free_align(mem)
static const dt_aligned_pixel_simd_t value
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 void _sp_chol_solve(const _sp_chol_t *const factor, double *const restrict rhs)
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 int cache_id)
dt_dev_pixelpipe_type_t type
int kernel_hl_cg_beta_step
int kernel_hl_cg_alpha_step
#define __DT_CLONE_TARGETS__
typedef double((*spd)(unsigned long int wavelength, double TempK))