33void _biharmonic_dome(
float *
const restrict field,
const uint8_t *
const restrict hole,
const int region_w,
36 const size_t region_pixels = (size_t)region_w * region_h;
37 size_t n_hole_fine = 0;
38 for(
size_t i = 0;
i < region_pixels;
i++)
39 if(hole[
i]) n_hole_fine++;
40 if(n_hole_fine == 0)
return;
50 int downsample = (forced_downsample > 0) ? forced_downsample
51 :
MAX(1, (
int)ceilf(sqrtf((
float)n_hole_fine / (
float)max_unknowns)));
52 int coarse_w = (region_w + downsample - 1) / downsample;
53 int coarse_h = (region_h + downsample - 1) / downsample;
54 const size_t coarse_pixels = (size_t)coarse_w * coarse_h;
57 uint8_t *
const restrict coarse_hole
60 if(!coarse_field || !coarse_hole || !coarse_index)
71 for(
int coarse_y = 0; coarse_y < coarse_h; coarse_y++)
72 for(
int coarse_x = 0; coarse_x < coarse_w; coarse_x++)
75 int n_valid = 0, n_hole_block = 0, n_total = 0;
76 for(
int fine_y = coarse_y * downsample; fine_y <
MIN((coarse_y + 1) * downsample, region_h); fine_y++)
77 for(
int fine_x = coarse_x * downsample; fine_x <
MIN((coarse_x + 1) * downsample, region_w); fine_x++)
79 const size_t fine_index = (size_t)fine_y * region_w + fine_x;
87 accum += field[fine_index];
91 const size_t coarse_i = (size_t)coarse_y * coarse_w + coarse_x;
92 coarse_hole[coarse_i] = (2 * n_hole_block > n_total) ? 1 : 0;
93 coarse_field[coarse_i] = (n_valid > 0) ? (
float)(accum / n_valid) : 0.f;
98 for(
size_t coarse_i = 0; coarse_i < coarse_pixels; coarse_i++)
99 coarse_index[coarse_i] = coarse_hole[coarse_i] ? n_unknowns++ : -1;
107 const int stencil_dy[13] = { 0, -1, 1, 0, 0, -1, -1, 1, 1, -2, 2, 0, 0 };
108 const int stencil_dx[13] = { 0, 0, 0, -1, 1, -1, 1, -1, 1, 0, 0, -2, 2 };
109 const float stencil_weight[13] = { 20.f, -8.f, -8.f, -8.f, -8.f, 2.f, 2.f, 2.f, 2.f, 1.f, 1.f, 1.f, 1.f };
120 int *matrix_row_index = NULL;
121 double *matrix_values = NULL;
123 if(unknown_x && unknown_y &&
permutation && inverse_perm && matrix_col_ptr && right_hand_side)
125 for(
size_t coarse_i = 0; coarse_i < coarse_pixels; coarse_i++)
126 if(coarse_hole[coarse_i])
128 unknown_x[coarse_index[coarse_i]] = (int)(coarse_i % coarse_w);
129 unknown_y[coarse_index[coarse_i]] = (int)(coarse_i / coarse_w);
134 for(
int perm_index = 0; perm_index < n_unknowns; perm_index++)
135 inverse_perm[
permutation[perm_index]] = perm_index;
142 double target_weights[13];
144 for(
int pass = 0; pass < 2 && success; pass++)
149 for(
int perm_index = 0; perm_index < n_unknowns; perm_index++)
151 const int col_count = matrix_col_ptr[perm_index];
152 matrix_col_ptr[perm_index] = total;
155 matrix_col_ptr[n_unknowns] = total;
158 if(!matrix_row_index || !matrix_values) success = 0;
161 for(
int perm_index = 0; perm_index < n_unknowns && success; perm_index++)
163 const int coarse_y = unknown_y[
permutation[perm_index]];
164 const int coarse_x = unknown_x[
permutation[perm_index]];
169 double boundary_sum = 0.0;
170 for(
int k = 0;
k < 13;
k++)
172 const int neighbour_y = CLAMP(coarse_y + stencil_dy[
k], 0, coarse_h - 1);
173 const int neighbour_x = CLAMP(coarse_x + stencil_dx[
k], 0, coarse_w - 1);
174 const size_t neighbour_i = (size_t)neighbour_y * coarse_w + neighbour_x;
175 if(!coarse_hole[neighbour_i])
179 boundary_sum -= (
double)stencil_weight[
k] * coarse_field[neighbour_i];
182 const int target = neighbour_y * coarse_w + neighbour_x;
184 for(; slot < count; slot++)
185 if(targets[slot] == target)
187 target_weights[slot] += stencil_weight[
k];
192 targets[count] = target;
193 target_weights[count] = stencil_weight[
k];
197 if(pass == 1) right_hand_side[perm_index] = boundary_sum;
199 int n_col_entries = 0;
200 for(
int slot = 0; slot < count; slot++)
202 const int target_row = inverse_perm[coarse_index[targets[slot]]];
203 if(target_row > perm_index)
continue;
205 const double value = target_weights[slot];
208 matrix_row_index[matrix_col_ptr[perm_index] + n_col_entries] = target_row;
209 matrix_values[matrix_col_ptr[perm_index] + n_col_entries] =
value;
213 if(pass == 0) matrix_col_ptr[perm_index] = n_col_entries;
227 for(
size_t coarse_i = 0; coarse_i < coarse_pixels; coarse_i++)
228 if(coarse_hole[coarse_i])
229 coarse_field[coarse_i] = (float)right_hand_side[(
size_t)inverse_perm[coarse_index[coarse_i]]];
251 if(
matrix && right_hand_side)
253 memset(
matrix, 0, (
size_t)n_unknowns * n_unknowns *
sizeof(
float));
255 for(
int coarse_y = 0; coarse_y < coarse_h; coarse_y++)
256 for(
int coarse_x = 0; coarse_x < coarse_w; coarse_x++)
258 const size_t coarse_i = (size_t)coarse_y * coarse_w + coarse_x;
259 if(!coarse_hole[coarse_i])
continue;
260 const int unknown_index = coarse_index[coarse_i];
261 float boundary_sum = 0.f;
262 for(
int k = 0;
k < 13;
k++)
264 const int neighbour_y = CLAMP(coarse_y + stencil_dy[
k], 0, coarse_h - 1);
265 const int neighbour_x = CLAMP(coarse_x + stencil_dx[
k], 0, coarse_w - 1);
266 const size_t neighbour_i = (size_t)neighbour_y * coarse_w + neighbour_x;
267 if(coarse_hole[neighbour_i])
268 matrix[(size_t)unknown_index * n_unknowns + coarse_index[neighbour_i]] += stencil_weight[
k];
270 boundary_sum -= stencil_weight[
k] * coarse_field[neighbour_i];
272 right_hand_side[unknown_index] = boundary_sum;
279 for(
size_t coarse_i = 0; coarse_i < coarse_pixels; coarse_i++)
280 if(coarse_hole[coarse_i]) coarse_field[coarse_i] = right_hand_side[coarse_index[coarse_i]];
292 double anchor_sum = 0.0;
293 size_t anchor_count = 0;
294 for(
size_t coarse_i = 0; coarse_i < coarse_pixels; coarse_i++)
295 if(!coarse_hole[coarse_i])
297 anchor_sum += coarse_field[coarse_i];
300 const float anchor_mean = anchor_count ? (float)(anchor_sum / (
double)anchor_count) : 0.f;
301 for(
size_t coarse_i = 0; coarse_i < coarse_pixels; coarse_i++)
302 if(coarse_hole[coarse_i]) coarse_field[coarse_i] = anchor_mean;
308 for(
int y = 0; y < region_h; y++)
309 for(
int x = 0;
x < region_w;
x++)
311 const size_t fine_index = (size_t)y * region_w +
x;
312 if(!hole[fine_index])
continue;
313 const float grid_x = ((float)
x + 0.5f) / downsample - 0.5f;
314 const float grid_y = ((float)y + 0.5f) / downsample - 0.5f;
315 const int x_lo = CLAMP((
int)floorf(grid_x), 0, coarse_w - 1);
316 const int y_lo = CLAMP((
int)floorf(grid_y), 0, coarse_h - 1);
317 const int x_hi =
MIN(x_lo + 1, coarse_w - 1);
318 const int y_hi =
MIN(y_lo + 1, coarse_h - 1);
319 const float frac_x = CLAMP(grid_x - x_lo, 0.f, 1.f);
320 const float frac_y = CLAMP(grid_y - y_lo, 0.f, 1.f);
321 const float interp_top = coarse_field[(size_t)y_lo * coarse_w + x_lo] * (1.f - frac_x)
322 + coarse_field[(size_t)y_lo * coarse_w + x_hi] * frac_x;
323 const float interp_bottom = coarse_field[(size_t)y_hi * coarse_w + x_lo] * (1.f - frac_x)
324 + coarse_field[(size_t)y_hi * coarse_w + x_hi] * frac_x;
325 field[fine_index] = interp_top * (1.f - frac_y) + interp_bottom * frac_y;
354#if defined(HAVE_OPENCL) && DT_HL_SPARSE_SOLVE
355cl_int _biharmonic_dome_cl(
const int devid,
void *gd_void, cl_mem field, cl_mem hole,
const int region_w,
359 const int coarse_w = (region_w + downsample - 1) / downsample;
360 const int coarse_h = (region_h + downsample - 1) / downsample;
361 const size_t coarse_pixels = (size_t)coarse_w * coarse_h;
371 int *matrix_col_ptr = NULL, *matrix_row_index = NULL;
372 double *matrix_values = NULL;
373 cl_mem solution_device = NULL;
374 if(!dval || !dhole || !cf || !coarse_hole || !idx)
goto out;
390 if(cl_err != CL_SUCCESS)
goto out;
395 if(cl_err != CL_SUCCESS)
goto out;
397 if(cl_err != CL_SUCCESS)
goto out;
400 int unknown_count = 0;
401 for(
size_t coarse_index = 0; coarse_index < coarse_pixels; coarse_index++)
402 idx[coarse_index] = coarse_hole[coarse_index] ? unknown_count++ : -1;
407 if(unknown_count > 0)
414 static const int stencil_off_y[13] = { 0, -1, 1, 0, 0, -1, -1, 1, 1, -2, 2, 0, 0 };
415 static const int stencil_off_x[13] = { 0, 0, 0, -1, 1, -1, 1, -1, 1, 0, 0, -2, 2 };
416 static const double stencil_coef[13] = { 20., -8., -8., -8., -8., 2., 2., 2., 2., 1., 1., 1., 1. };
426 int alloc_ok = (unknown_x && unknown_y &&
perm && inv_perm && matrix_col_ptr && matrix_row_index
427 && matrix_values && rhs);
430 for(
size_t coarse_index = 0; coarse_index < coarse_pixels; coarse_index++)
431 if(coarse_hole[coarse_index])
433 unknown_x[idx[coarse_index]] = (int)(coarse_index % coarse_w);
434 unknown_y[idx[coarse_index]] = (int)(coarse_index / coarse_w);
436 for(
int i = 0;
i < unknown_count;
i++)
perm[
i] =
i;
438 for(
int perm_index = 0; perm_index < unknown_count; perm_index++) inv_perm[
perm[perm_index]] = perm_index;
441 for(
int perm_index = 0; perm_index < unknown_count; perm_index++)
443 const int cell_y = unknown_y[
perm[perm_index]], cell_x = unknown_x[
perm[perm_index]];
444 matrix_col_ptr[perm_index] = n_nonzero;
445 double rhs_accum = 0.0;
446 for(
int stencil = 0; stencil < 13; stencil++)
448 const int neighbor_y = CLAMP(cell_y + stencil_off_y[stencil], 0, coarse_h - 1);
449 const int neighbor_x = CLAMP(cell_x + stencil_off_x[stencil], 0, coarse_w - 1);
450 const size_t neighbor_index = (size_t)neighbor_y * coarse_w + neighbor_x;
451 if(!coarse_hole[neighbor_index])
455 rhs_accum -= stencil_coef[stencil] * cf[neighbor_index];
458 const int row_index = inv_perm[idx[neighbor_index]];
459 if(row_index > perm_index)
continue;
460 int fill_index = matrix_col_ptr[perm_index];
461 for(; fill_index < n_nonzero; fill_index++)
462 if(matrix_row_index[fill_index] == row_index)
464 matrix_values[fill_index] += stencil_coef[stencil];
467 if(fill_index == n_nonzero)
469 matrix_row_index[n_nonzero] = row_index;
470 matrix_values[n_nonzero] = stencil_coef[stencil];
474 rhs[perm_index] = rhs_accum;
476 matrix_col_ptr[unknown_count] = n_nonzero;
481 matrix_row_index, matrix_values);
485 cl_mem rhs_device =
_sp_cl_upload(devid, rhs,
sizeof(
double) * unknown_count);
496 for(
int k = 0;
k < unknown_count && solved;
k++)
497 if(!isfinite(rhs[
k])) solved = 0;
499 for(
size_t coarse_index = 0; coarse_index < coarse_pixels; coarse_index++)
500 if(coarse_hole[coarse_index]) cf[coarse_index] = (float)rhs[(
size_t)inv_perm[idx[coarse_index]]];
508 float *
const restrict dense_matrix
511 if(dense_matrix && dense_rhs)
513 memset(dense_matrix, 0, (
size_t)unknown_count * unknown_count *
sizeof(
float));
514 for(
int cell_y = 0; cell_y < coarse_h; cell_y++)
515 for(
int cell_x = 0; cell_x < coarse_w; cell_x++)
517 const size_t coarse_index = (size_t)cell_y * coarse_w + cell_x;
518 if(!coarse_hole[coarse_index])
continue;
519 const int k = idx[coarse_index];
520 float rhs_accum = 0.f;
521 for(
int stencil = 0; stencil < 13; stencil++)
523 const int neighbor_y = CLAMP(cell_y + stencil_off_y[stencil], 0, coarse_h - 1);
524 const int neighbor_x = CLAMP(cell_x + stencil_off_x[stencil], 0, coarse_w - 1);
525 const size_t neighbor_index = (size_t)neighbor_y * coarse_w + neighbor_x;
526 if(coarse_hole[neighbor_index])
527 dense_matrix[(size_t)
k * unknown_count + idx[neighbor_index]] += stencil_coef[stencil];
529 rhs_accum -= stencil_coef[stencil] * cf[neighbor_index];
531 dense_rhs[
k] = rhs_accum;
535 for(
size_t coarse_index = 0; coarse_index < coarse_pixels; coarse_index++)
536 if(coarse_hole[coarse_index]) cf[coarse_index] = dense_rhs[idx[coarse_index]];
549 for(
size_t coarse_index = 0; coarse_index < coarse_pixels; coarse_index++)
550 if(!coarse_hole[coarse_index])
552 asum += cf[coarse_index];
555 const float amean = acnt ? (float)(asum / (
double)acnt) : 0.f;
556 for(
size_t coarse_index = 0; coarse_index < coarse_pixels; coarse_index++)
557 if(coarse_hole[coarse_index]) cf[coarse_index] = amean;
567 if(cl_err != CL_SUCCESS)
goto out;
594 solution_device =
_sp_cl_upload(devid, cf,
sizeof(
float) * coarse_pixels);
604 const int mask_is_hole = 1;
static int solve_hermitian(const float *const restrict A, float *const restrict y, const size_t n, const int checks)
const dt_colormatrix_t dt_aligned_pixel_t out
const dt_colormatrix_t matrix
#define dt_pixelpipe_cache_alloc_align(size, pipe)
#define dt_pixelpipe_cache_free_align(mem)
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
#define __DT_CLONE_TARGETS__
#define __OMP_PARALLEL_FOR__(...)
static const dt_aligned_pixel_simd_t value
__DT_CLONE_TARGETS__ void _biharmonic_dome(float *const restrict field, const uint8_t *const restrict hole, const int region_w, const int region_h, const int forced_downsample, const dt_dev_pixelpipe_t *pipe)
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)
void dt_opencl_release_mem_object(cl_mem mem)
#define DT_OPENCL_DEFAULT_ERROR
static _sp_chol_cl_kernels_t _hl_sp_chol_kernels(void *gd_void)
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_free(_sp_chol_t *factor)
static void _sp_chol_solve(const _sp_chol_t *const factor, double *const restrict rhs)
static void _sp_chol_cl_free(_sp_chol_cl_t *factor)
static _sp_chol_cl_t * _sp_chol_factor_cl(const int devid, const _sp_chol_cl_kernels_t kernels, const int dimension, const int *const restrict matrix_col_ptr, const int *const restrict matrix_row_index, const double *const restrict matrix_values)
static int _sp_chol_solve_cl(const _sp_chol_cl_t *const factor, const _sp_chol_cl_kernels_t kernels, cl_mem rhs)
static cl_mem _sp_cl_upload(const int devid, const void *data, const size_t bytes)
#define DT_HL_DOME_NMAX_SPARSE
typedef double((*spd)(unsigned long int wavelength, double TempK))