53 float *
const restrict coarse_field,
const int coarse_w,
56 const size_t coarse_pixels = (size_t)coarse_w * coarse_h;
61 for(
size_t i = 0;
i < coarse_pixels;
i++) hull[
i] = 1;
62 for(
int y = 0; y < coarse_h; y++)
64 int seen_left = 0, seen_right = 0;
65 for(
int x = 0;
x < coarse_w;
x++)
67 if(
x >= 2 && !coarse_hole[(
size_t)y * coarse_w +
x - 2]) seen_left = 1;
68 hull[(size_t)y * coarse_w +
x] &= seen_left;
69 const int xr = coarse_w - 1 -
x;
70 if(xr + 2 < coarse_w && !coarse_hole[(
size_t)y * coarse_w + xr + 2]) seen_right = 1;
71 hull[(size_t)y * coarse_w + xr] &= seen_right;
74 for(
int x = 0;
x < coarse_w;
x++)
76 int seen_up = 0, seen_down = 0;
77 for(
int y = 0; y < coarse_h; y++)
79 if(y >= 2 && !coarse_hole[(
size_t)(y - 2) * coarse_w +
x]) seen_up = 1;
80 hull[(size_t)y * coarse_w +
x] &= seen_up;
81 const int yd = coarse_h - 1 - y;
82 if(yd + 2 < coarse_h && !coarse_hole[(
size_t)(yd + 2) * coarse_w +
x]) seen_down = 1;
83 hull[(size_t)yd * coarse_w +
x] &= seen_down;
87 double anchor_sum = 0.0;
88 size_t anchor_count = 0;
89 for(
size_t i = 0;
i < coarse_pixels;
i++)
92 anchor_sum += coarse_field[
i];
95 const float anchor_mean = anchor_count ? (float)(anchor_sum / (
double)anchor_count) : 0.f;
98 for(
size_t i = 0;
i < coarse_pixels;
i++)
99 if(coarse_hole[
i] && !hull[
i])
104 if(coarse_field[
i] == 0.f) coarse_field[
i] = anchor_mean;
113void _biharmonic_dome(
float *
const restrict field,
const uint8_t *
const restrict hole,
const int region_w,
116 const size_t region_pixels = (size_t)region_w * region_h;
117 size_t n_hole_fine = 0;
118 for(
size_t i = 0;
i < region_pixels;
i++)
119 if(hole[
i]) n_hole_fine++;
120 if(n_hole_fine == 0)
return;
130 int downsample = (forced_downsample > 0) ? forced_downsample
131 :
MAX(1, (
int)ceilf(sqrtf((
float)n_hole_fine / (
float)max_unknowns)));
132 int coarse_w = (region_w + downsample - 1) / downsample;
133 int coarse_h = (region_h + downsample - 1) / downsample;
134 const size_t coarse_pixels = (size_t)coarse_w * coarse_h;
137 uint8_t *
const restrict coarse_hole
140 if(!coarse_field || !coarse_hole || !coarse_index)
151 for(
int coarse_y = 0; coarse_y < coarse_h; coarse_y++)
152 for(
int coarse_x = 0; coarse_x < coarse_w; coarse_x++)
155 int n_valid = 0, n_hole_block = 0, n_total = 0;
156 for(
int fine_y = coarse_y * downsample; fine_y <
MIN((coarse_y + 1) * downsample, region_h); fine_y++)
157 for(
int fine_x = coarse_x * downsample; fine_x <
MIN((coarse_x + 1) * downsample, region_w); fine_x++)
159 const size_t fine_index = (size_t)fine_y * region_w + fine_x;
167 accum += field[fine_index];
171 const size_t coarse_i = (size_t)coarse_y * coarse_w + coarse_x;
172 coarse_hole[coarse_i] = (2 * n_hole_block > n_total) ? 1 : 0;
173 coarse_field[coarse_i] = (n_valid > 0) ? (
float)(accum / n_valid) : 0.f;
182 for(
size_t coarse_i = 0; coarse_i < coarse_pixels; coarse_i++)
183 coarse_index[coarse_i] = coarse_hole[coarse_i] ? n_unknowns++ : -1;
191 const int stencil_dy[13] = { 0, -1, 1, 0, 0, -1, -1, 1, 1, -2, 2, 0, 0 };
192 const int stencil_dx[13] = { 0, 0, 0, -1, 1, -1, 1, -1, 1, 0, 0, -2, 2 };
193 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 };
204 int *matrix_row_index = NULL;
205 double *matrix_values = NULL;
207 if(unknown_x && unknown_y &&
permutation && inverse_perm && matrix_col_ptr && right_hand_side)
209 for(
size_t coarse_i = 0; coarse_i < coarse_pixels; coarse_i++)
210 if(coarse_hole[coarse_i])
212 unknown_x[coarse_index[coarse_i]] = (int)(coarse_i % coarse_w);
213 unknown_y[coarse_index[coarse_i]] = (int)(coarse_i / coarse_w);
218 for(
int perm_index = 0; perm_index < n_unknowns; perm_index++)
219 inverse_perm[
permutation[perm_index]] = perm_index;
226 double target_weights[13];
228 for(
int pass = 0; pass < 2 && success; pass++)
233 for(
int perm_index = 0; perm_index < n_unknowns; perm_index++)
235 const int col_count = matrix_col_ptr[perm_index];
236 matrix_col_ptr[perm_index] = total;
239 matrix_col_ptr[n_unknowns] = total;
242 if(!matrix_row_index || !matrix_values) success = 0;
245 for(
int perm_index = 0; perm_index < n_unknowns && success; perm_index++)
247 const int coarse_y = unknown_y[
permutation[perm_index]];
248 const int coarse_x = unknown_x[
permutation[perm_index]];
253 double boundary_sum = 0.0;
254 for(
int k = 0;
k < 13;
k++)
256 const int neighbour_y = CLAMP(coarse_y + stencil_dy[
k], 0, coarse_h - 1);
257 const int neighbour_x = CLAMP(coarse_x + stencil_dx[
k], 0, coarse_w - 1);
258 const size_t neighbour_i = (size_t)neighbour_y * coarse_w + neighbour_x;
259 if(!coarse_hole[neighbour_i])
263 boundary_sum -= (
double)stencil_weight[
k] * coarse_field[neighbour_i];
266 const int target = neighbour_y * coarse_w + neighbour_x;
268 for(; slot < count; slot++)
269 if(targets[slot] == target)
271 target_weights[slot] += stencil_weight[
k];
276 targets[count] = target;
277 target_weights[count] = stencil_weight[
k];
281 if(pass == 1) right_hand_side[perm_index] = boundary_sum;
283 int n_col_entries = 0;
284 for(
int slot = 0; slot < count; slot++)
286 const int target_row = inverse_perm[coarse_index[targets[slot]]];
287 if(target_row > perm_index)
continue;
289 const double value = target_weights[slot];
292 matrix_row_index[matrix_col_ptr[perm_index] + n_col_entries] = target_row;
293 matrix_values[matrix_col_ptr[perm_index] + n_col_entries] =
value;
297 if(pass == 0) matrix_col_ptr[perm_index] = n_col_entries;
311 for(
size_t coarse_i = 0; coarse_i < coarse_pixels; coarse_i++)
312 if(coarse_hole[coarse_i])
313 coarse_field[coarse_i] = (float)right_hand_side[(
size_t)inverse_perm[coarse_index[coarse_i]]];
335 if(
matrix && right_hand_side)
337 memset(
matrix, 0, (
size_t)n_unknowns * n_unknowns *
sizeof(
float));
339 for(
int coarse_y = 0; coarse_y < coarse_h; coarse_y++)
340 for(
int coarse_x = 0; coarse_x < coarse_w; coarse_x++)
342 const size_t coarse_i = (size_t)coarse_y * coarse_w + coarse_x;
343 if(!coarse_hole[coarse_i])
continue;
344 const int unknown_index = coarse_index[coarse_i];
345 float boundary_sum = 0.f;
346 for(
int k = 0;
k < 13;
k++)
348 const int neighbour_y = CLAMP(coarse_y + stencil_dy[
k], 0, coarse_h - 1);
349 const int neighbour_x = CLAMP(coarse_x + stencil_dx[
k], 0, coarse_w - 1);
350 const size_t neighbour_i = (size_t)neighbour_y * coarse_w + neighbour_x;
351 if(coarse_hole[neighbour_i])
352 matrix[(size_t)unknown_index * n_unknowns + coarse_index[neighbour_i]] += stencil_weight[
k];
354 boundary_sum -= stencil_weight[
k] * coarse_field[neighbour_i];
356 right_hand_side[unknown_index] = boundary_sum;
363 for(
size_t coarse_i = 0; coarse_i < coarse_pixels; coarse_i++)
364 if(coarse_hole[coarse_i]) coarse_field[coarse_i] = right_hand_side[coarse_index[coarse_i]];
380 "[highlights] dome: the %d-unknown biharmonic solve failed, filling the hole flat\n",
382 double anchor_sum = 0.0;
383 size_t anchor_count = 0;
384 for(
size_t coarse_i = 0; coarse_i < coarse_pixels; coarse_i++)
385 if(!coarse_hole[coarse_i])
387 anchor_sum += coarse_field[coarse_i];
390 const float anchor_mean = anchor_count ? (float)(anchor_sum / (
double)anchor_count) : 0.f;
391 for(
size_t coarse_i = 0; coarse_i < coarse_pixels; coarse_i++)
392 if(coarse_hole[coarse_i]) coarse_field[coarse_i] = anchor_mean;
398 for(
int y = 0; y < region_h; y++)
399 for(
int x = 0;
x < region_w;
x++)
401 const size_t fine_index = (size_t)y * region_w +
x;
402 if(!hole[fine_index])
continue;
403 const float grid_x = ((float)
x + 0.5f) / downsample - 0.5f;
404 const float grid_y = ((float)y + 0.5f) / downsample - 0.5f;
405 const int x_lo = CLAMP((
int)floorf(grid_x), 0, coarse_w - 1);
406 const int y_lo = CLAMP((
int)floorf(grid_y), 0, coarse_h - 1);
407 const int x_hi =
MIN(x_lo + 1, coarse_w - 1);
408 const int y_hi =
MIN(y_lo + 1, coarse_h - 1);
409 const float frac_x = CLAMP(grid_x - x_lo, 0.f, 1.f);
410 const float frac_y = CLAMP(grid_y - y_lo, 0.f, 1.f);
411 const float interp_top = coarse_field[(size_t)y_lo * coarse_w + x_lo] * (1.f - frac_x)
412 + coarse_field[(size_t)y_lo * coarse_w + x_hi] * frac_x;
413 const float interp_bottom = coarse_field[(size_t)y_hi * coarse_w + x_lo] * (1.f - frac_x)
414 + coarse_field[(size_t)y_hi * coarse_w + x_hi] * frac_x;
415 field[fine_index] = interp_top * (1.f - frac_y) + interp_bottom * frac_y;
444#if defined(HAVE_OPENCL) && DT_HL_SPARSE_SOLVE
445cl_int _biharmonic_dome_cl(
const int devid,
void *gd_void, cl_mem field, cl_mem hole,
const int region_w,
449 const int coarse_w = (region_w + downsample - 1) / downsample;
450 const int coarse_h = (region_h + downsample - 1) / downsample;
451 const size_t coarse_pixels = (size_t)coarse_w * coarse_h;
461 int *matrix_col_ptr = NULL, *matrix_row_index = NULL;
462 double *matrix_values = NULL;
463 cl_mem solution_device = NULL;
464 if(!dval || !dhole || !cf || !coarse_hole || !idx)
goto out;
480 if(cl_err != CL_SUCCESS)
goto out;
485 if(cl_err != CL_SUCCESS)
goto out;
487 if(cl_err != CL_SUCCESS)
goto out;
494 int unknown_count = 0;
495 for(
size_t coarse_index = 0; coarse_index < coarse_pixels; coarse_index++)
496 idx[coarse_index] = coarse_hole[coarse_index] ? unknown_count++ : -1;
501 if(unknown_count > 0)
508 static const int stencil_off_y[13] = { 0, -1, 1, 0, 0, -1, -1, 1, 1, -2, 2, 0, 0 };
509 static const int stencil_off_x[13] = { 0, 0, 0, -1, 1, -1, 1, -1, 1, 0, 0, -2, 2 };
510 static const double stencil_coef[13] = { 20., -8., -8., -8., -8., 2., 2., 2., 2., 1., 1., 1., 1. };
520 int alloc_ok = (unknown_x && unknown_y &&
perm && inv_perm && matrix_col_ptr && matrix_row_index
521 && matrix_values && rhs);
524 for(
size_t coarse_index = 0; coarse_index < coarse_pixels; coarse_index++)
525 if(coarse_hole[coarse_index])
527 unknown_x[idx[coarse_index]] = (int)(coarse_index % coarse_w);
528 unknown_y[idx[coarse_index]] = (int)(coarse_index / coarse_w);
530 for(
int i = 0;
i < unknown_count;
i++)
perm[
i] =
i;
532 for(
int perm_index = 0; perm_index < unknown_count; perm_index++) inv_perm[
perm[perm_index]] = perm_index;
535 for(
int perm_index = 0; perm_index < unknown_count; perm_index++)
537 const int cell_y = unknown_y[
perm[perm_index]], cell_x = unknown_x[
perm[perm_index]];
538 matrix_col_ptr[perm_index] = n_nonzero;
539 double rhs_accum = 0.0;
540 for(
int stencil = 0; stencil < 13; stencil++)
542 const int neighbor_y = CLAMP(cell_y + stencil_off_y[stencil], 0, coarse_h - 1);
543 const int neighbor_x = CLAMP(cell_x + stencil_off_x[stencil], 0, coarse_w - 1);
544 const size_t neighbor_index = (size_t)neighbor_y * coarse_w + neighbor_x;
545 if(!coarse_hole[neighbor_index])
549 rhs_accum -= stencil_coef[stencil] * cf[neighbor_index];
552 const int row_index = inv_perm[idx[neighbor_index]];
553 if(row_index > perm_index)
continue;
554 int fill_index = matrix_col_ptr[perm_index];
555 for(; fill_index < n_nonzero; fill_index++)
556 if(matrix_row_index[fill_index] == row_index)
558 matrix_values[fill_index] += stencil_coef[stencil];
561 if(fill_index == n_nonzero)
563 matrix_row_index[n_nonzero] = row_index;
564 matrix_values[n_nonzero] = stencil_coef[stencil];
568 rhs[perm_index] = rhs_accum;
570 matrix_col_ptr[unknown_count] = n_nonzero;
575 matrix_row_index, matrix_values);
579 cl_mem rhs_device =
_sp_cl_upload(devid, rhs,
sizeof(
double) * unknown_count);
590 for(
int k = 0;
k < unknown_count && solved;
k++)
591 if(!isfinite(rhs[
k])) solved = 0;
593 for(
size_t coarse_index = 0; coarse_index < coarse_pixels; coarse_index++)
594 if(coarse_hole[coarse_index]) cf[coarse_index] = (float)rhs[(
size_t)inv_perm[idx[coarse_index]]];
602 float *
const restrict dense_matrix
605 if(dense_matrix && dense_rhs)
607 memset(dense_matrix, 0, (
size_t)unknown_count * unknown_count *
sizeof(
float));
608 for(
int cell_y = 0; cell_y < coarse_h; cell_y++)
609 for(
int cell_x = 0; cell_x < coarse_w; cell_x++)
611 const size_t coarse_index = (size_t)cell_y * coarse_w + cell_x;
612 if(!coarse_hole[coarse_index])
continue;
613 const int k = idx[coarse_index];
614 float rhs_accum = 0.f;
615 for(
int stencil = 0; stencil < 13; stencil++)
617 const int neighbor_y = CLAMP(cell_y + stencil_off_y[stencil], 0, coarse_h - 1);
618 const int neighbor_x = CLAMP(cell_x + stencil_off_x[stencil], 0, coarse_w - 1);
619 const size_t neighbor_index = (size_t)neighbor_y * coarse_w + neighbor_x;
620 if(coarse_hole[neighbor_index])
621 dense_matrix[(size_t)
k * unknown_count + idx[neighbor_index]] += stencil_coef[stencil];
623 rhs_accum -= stencil_coef[stencil] * cf[neighbor_index];
625 dense_rhs[
k] = rhs_accum;
629 for(
size_t coarse_index = 0; coarse_index < coarse_pixels; coarse_index++)
630 if(coarse_hole[coarse_index]) cf[coarse_index] = dense_rhs[idx[coarse_index]];
642 "[highlights] dome: the %d-unknown biharmonic solve failed, filling the hole flat\n",
646 for(
size_t coarse_index = 0; coarse_index < coarse_pixels; coarse_index++)
647 if(!coarse_hole[coarse_index])
649 asum += cf[coarse_index];
652 const float amean = acnt ? (float)(asum / (
double)acnt) : 0.f;
653 for(
size_t coarse_index = 0; coarse_index < coarse_pixels; coarse_index++)
654 if(coarse_hole[coarse_index]) cf[coarse_index] = amean;
664 if(cl_err != CL_SUCCESS)
goto out;
691 solution_device =
_sp_cl_upload(devid, cf,
sizeof(
float) * coarse_pixels);
701 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
__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 size_t _dome_restrict_to_anchor_hull(uint8_t *const restrict coarse_hole, float *const restrict coarse_field, const int coarse_w, const int coarse_h, const dt_dev_pixelpipe_t *pipe)
static float kernel(const float *x, const float *y)
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.
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
#define __OMP_PARALLEL_FOR__(...)
static _sp_chol_cl_kernels_t _hl_sp_chol_kernels(void *gd_void)
#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 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_free(_sp_chol_t *factor)
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)
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
dt_dev_pixelpipe_type_t type
#define __DT_CLONE_TARGETS__
typedef double((*spd)(unsigned long int wavelength, double TempK))