63#define RESAMPLING_BORDER_MODE BORDER_REPLICATE
67#define INTERPOLATION_BORDER_MODE BORDER_MIRROR
71#define MAX_HALF_FILTER_WIDTH 3
74#define DEBUG_PRINT_VERBOSE 0
132 if(i < min || i >
max)
145static inline __attribute__((always_inline))
void _prepare_tap_boundaries(
int *tap_first,
148 const int filterwidth,
161 *tap_last = filterwidth;
177 const size_t num_taps,
179 const float first_tap,
180 const float interval)
182 static const dt_aligned_pixel_simd_t bootstrap = { 0.0f, 1.0f, 2.0f, 3.0f };
183 const dt_aligned_pixel_simd_t interval_v =
dt_simd_set1(interval);
184 const dt_aligned_pixel_simd_t iter =
dt_simd_set1(4.0f * interval);
185 dt_aligned_pixel_simd_t vt =
dt_simd_set1(first_tap) + bootstrap * interval_v;
187 const int runs = (num_taps + 3) / 4;
189 for(
size_t i = 0;
i < runs;
i++)
202 const size_t num_taps,
204 const float first_tap,
205 const float interval)
207 static const dt_aligned_pixel_simd_t bootstrap = { 0.0f, 1.0f, 2.0f, 3.0f };
208 const dt_aligned_pixel_simd_t half =
dt_simd_set1(0.5f);
210 const dt_aligned_pixel_simd_t three =
dt_simd_set1(3.0f);
211 const dt_aligned_pixel_simd_t four =
dt_simd_set1(4.0f);
212 const dt_aligned_pixel_simd_t five =
dt_simd_set1(5.0f);
213 const dt_aligned_pixel_simd_t eight =
dt_simd_set1(8.0f);
214 const dt_aligned_pixel_simd_t interval_v =
dt_simd_set1(interval);
215 const dt_aligned_pixel_simd_t iter =
dt_simd_set1(4.0f * interval);
216 dt_aligned_pixel_simd_t vt =
dt_simd_set1(first_tap) + bootstrap * interval_v;
218 const int runs = (num_taps + 3) / 4;
220 for(
size_t i = 0;
i < runs;
i++)
222 const dt_aligned_pixel_simd_t vt_abs = dt_simd_abs(vt);
223 const dt_aligned_pixel_simd_t t2 = vt * vt;
224 const dt_aligned_pixel_simd_t t5 = five * vt_abs;
225 const dt_aligned_pixel_simd_t r12 = (vt_abs * (t5 - eight - t2) + four) * half;
226 const dt_aligned_pixel_simd_t r01 = ((three * t2 - t5) * vt_abs + two) * half;
227 dt_aligned_pixel_simd_t taps4 = r12;
229 taps4[c] = (vt_abs[c] <= 1.0f) ? r01[c] : r12[c];
255 const size_t num_taps,
257 const float first_tap,
258 const float interval)
260 static const dt_aligned_pixel_simd_t bootstrap = { 0.0f, 1.0f, 2.0f, 3.0f };
261 const dt_aligned_pixel_simd_t c7_6 =
dt_simd_set1(7.0f / 6.0f);
263 const dt_aligned_pixel_simd_t c8_9 =
dt_simd_set1(8.0f / 9.0f);
264 const dt_aligned_pixel_simd_t c7_18 =
dt_simd_set1(7.0f / 18.0f);
265 const dt_aligned_pixel_simd_t c10_3 =
dt_simd_set1(10.0f / 3.0f);
266 const dt_aligned_pixel_simd_t c16_9 =
dt_simd_set1(16.0f / 9.0f);
267 const dt_aligned_pixel_simd_t interval_v =
dt_simd_set1(interval);
268 const dt_aligned_pixel_simd_t iter =
dt_simd_set1(4.0f * interval);
269 dt_aligned_pixel_simd_t vt =
dt_simd_set1(first_tap) + bootstrap * interval_v;
271 const int runs = (num_taps + 3) / 4;
273 for(
size_t i = 0;
i < runs;
i++)
275 const dt_aligned_pixel_simd_t a = dt_simd_abs(vt);
276 const dt_aligned_pixel_simd_t a2 = a * a;
277 const dt_aligned_pixel_simd_t a3 = a2 * a;
279 const dt_aligned_pixel_simd_t r01 = c7_6 * a3 -
c2 * a2 + c8_9;
280 const dt_aligned_pixel_simd_t r12 =
c2 * a2 - c7_18 * a3 - c10_3 * a + c16_9;
281 dt_aligned_pixel_simd_t taps4 = r12;
283 taps4[c] = (a[c] <= 1.0f) ? r01[c] : r12[c];
331 int f = (int)floorf(
t) - itor->
width + 1;
360 const float outoinratio,
364 const float w = (float)itor->
width;
368 const float xin =
ceil_fast(((
float)xout - w) / outoinratio);
375 float t = xin * outoinratio - (float)xout;
378 int num_taps = *taps = (int)((w -
t) / outoinratio);
384 for(
size_t i = 0;
i < num_taps;
i++)
394#define MAX_KERNEL_REQ ((2 * (MAX_HALF_FILTER_WIDTH) + 3) & (~3))
403 const int samplestride,
404 const int linestride)
412 float normh = _compute_upsampling_kernel(itor, kernelh, NULL,
x);
413 float normv = _compute_upsampling_kernel(itor, kernelv, NULL, y);
429 in = (
float *)in + linestride * iy + ix * samplestride;
430 in = in - (itor->
width - 1) * (samplestride + linestride);
434 for(
int i = 0;
i < 2 * itor->
width;
i++)
437 for(
int j = 0; j < 2 * itor->
width; j++)
439 h += kernelh[j] * in[j * samplestride];
444 r = fmaxf(0.0f, s / (normh * normv));
446 else if(ix >= 0 && iy >= 0 && ix <
width && iy <
height)
451 iy -= itor->
width - 1;
452 ix -= itor->
width - 1;
459 _prepare_tap_boundaries(&xtap_first, &xtap_last,
464 _prepare_tap_boundaries(&ytap_first, &ytap_last,
469 for(ssize_t
i = ytap_first;
i < ytap_last;
i++)
471 const ssize_t clip_y = _clip(iy +
i, 0,
height - 1, bordermode);
473 for(ssize_t j = xtap_first; j < xtap_last; j++)
475 const ssize_t clip_x = _clip(ix + j, 0,
width - 1, bordermode);
476 const float *ipixel = in + clip_y * linestride + clip_x * samplestride;
477 h += kernelh[j] * ipixel[0];
482 r = fmaxf(0.0f, s / (normh * normv));
504 const int linestride)
513 float normh = _compute_upsampling_kernel(itor, kernelh, NULL,
x);
514 float normv = _compute_upsampling_kernel(itor, kernelv, NULL, y);
517 const float oonorm = (1.f / (normh * normv));
526 if(ix >= (itor->
width - 1)
527 && iy >= (itor->
width - 1)
534 in = (
float *)in + linestride * iy + ix * 4;
535 in = in - (itor->
width - 1) * (4 + linestride);
537 const size_t itor_width = 2 * itor->
width;
541 for(
size_t i = 0;
i < itor_width;
i++)
544 for(
size_t j = 0; j < itor_width; j++)
545 h += dt_load_simd_aligned(in + 4 * j) *
dt_simd_set1(kernelh[j]);
552 else if(ix >= 0 && iy >= 0 && ix <
width && iy <
height)
557 iy -= itor->
width - 1;
558 ix -= itor->
width - 1;
565 _prepare_tap_boundaries(&xtap_first, &xtap_last,
570 _prepare_tap_boundaries(&ytap_first, &ytap_last,
575 for(ssize_t
i = ytap_first;
i < ytap_last;
i++)
577 const ssize_t clip_y = _clip(iy +
i, 0,
height - 1, bordermode);
579 const float *ipixel = in + clip_y * linestride;
580 for(ssize_t j = xtap_first; j < xtap_last; j++)
582 const ssize_t clip_x = _clip(ix + j, 0,
width - 1, bordermode);
583 h += dt_load_simd_aligned(ipixel + 4 * clip_x) *
dt_simd_set1(kernelh[j]);
637 dt_atomic_uint64 *generation,
665 itor =
_userpref_cached(
"plugins/lighttable/export/pixel_interpolator_warp",
767 maxtapsapixel = 2 * itor->
width;
776 const int nindex = maxtapsapixel *
out;
777 const int nkernel = maxtapsapixel *
out;
785 const size_t totalreq = kernelreq + lengthreq + indexreq + scratchreq + metareq;
789 int *lengths = (
int *)blob;
790 blob = (
char *)blob + lengthreq;
791 int *index = (
int *)blob;
792 blob = (
char *)blob + indexreq;
793 float *
kernel = (
float *)blob;
794 blob = (
char *)blob + kernelreq;
800 float *scratchpad = (
float *)blob;
801 blob = (
char *)blob + scratchreq;
802 int *
meta = metareq ? (
int *)blob : NULL;
818 for(
int x = 0;
x <
out;
x++)
828 float fx = (float)(out_x0 +
x) / scale - in_x0;
832 (
void)_compute_upsampling_kernel(itor, scratchpad, &first,
fx);
838 _prepare_tap_boundaries(&tap_first, &tap_last, bordermode, 2 * itor->
width, first, in);
841 lengths[lidx++] = tap_last - tap_first;
845 for(
int tap = tap_first; tap < tap_last; tap++)
847 norm += scratchpad[tap];
856 for(
int tap = tap_first; tap < tap_last; tap++)
858 kernel[kidx++] = scratchpad[tap] * norm;
859 index[iidx++] = _clip(first++, 0, in - 1, bordermode);
869 for(
int x = 0;
x <
out;
x++)
887 _prepare_tap_boundaries(&tap_first, &tap_last, bordermode, taps, first, in);
890 lengths[lidx++] = tap_last - tap_first;
894 for(
int tap = tap_first; tap < tap_last; tap++)
896 norm += scratchpad[tap];
905 for(
int tap = tap_first; tap < tap_last; tap++)
907 kernel[kidx++] = scratchpad[tap] * norm;
908 index[iidx++] = _clip(first++, 0, in - 1, bordermode);
929 float *
const restrict
out,
931 const float *
const restrict in,
936 float *hkernel = NULL;
939 float *vkernel = NULL;
942 const int32_t in_stride_floats = roi_in->
width * 4;
943 const int32_t out_stride_floats = roi_out->
width * 4;
948 const size_t x0 = (roi_out->
x - roi_in->
x) * 4 *
sizeof(
float);
949 const size_t y0 = (roi_out->
y - roi_in->
y);
954 for(
int y = yt; y < y_end; y++)
955 memcpy((
char *)__builtin_assume_aligned(
out, 64) + (
size_t)out_stride_floats *
sizeof(
float) * y,
956 (
char *)__builtin_assume_aligned(in, 64) + (
size_t)in_stride_floats *
sizeof(
float) * (y + y0) + x0,
957 out_stride_floats *
sizeof(
float));
969 const float resample_scale = roi_out->
scale / roi_in->
scale;
972 roi_out->
width, roi_out->
x, resample_scale,
973 &hlength, &hkernel, &hindex, NULL))
977 roi_out->
height, roi_out->
y, resample_scale,
978 &vlength, &vkernel, &vindex, &vmeta))
986 for(
size_t oy = 0; oy <
height; oy++)
989 int vlidx = vmeta[3 * oy + 0];
990 int vkidx = vmeta[3 * oy + 1];
991 int viidx = vmeta[3 * oy + 2];
998 int vl = vlength[vlidx++];
1001 for(
size_t ox = 0; ox <
width; ox++)
1007 const int hl = hlength[hlidx++];
1008 const int *
const column_hindex = hindex + hkidx;
1009 const float *
const column_hkernel = hkernel + hkidx;
1010 const int *
const column_vindex = vindex + viidx;
1011 const float *
const column_vkernel = vkernel + vkidx;
1013 for(
size_t iy = 0; iy < vl; iy++)
1016 const size_t baseidx_vindex = (size_t)column_vindex[iy] * in_stride_floats;
1020 for(
size_t ix = 0; ix < hl; ix++)
1023 const size_t baseidx = baseidx_vindex + (size_t)column_hindex[ix] * 4;
1024 const float htap = column_hkernel[ix];
1025 vhs += dt_load_simd_aligned(in + baseidx) *
dt_simd_set1(htap);
1029 const float vtap = column_vkernel[iy];
1034 const size_t baseidx = (size_t)oy * out_stride_floats + (
size_t)ox * 4;
1065 const float *
const in,
1079 const float *
const in,
1104 const int program = 2;
1143 int *hlength = NULL;
1144 float *hkernel = NULL;
1147 int *vlength = NULL;
1148 float *vkernel = NULL;
1153 cl_mem dev_hindex = NULL;
1154 cl_mem dev_hlength = NULL;
1155 cl_mem dev_hkernel = NULL;
1156 cl_mem dev_hmeta = NULL;
1157 cl_mem dev_vindex = NULL;
1158 cl_mem dev_vlength = NULL;
1159 cl_mem dev_vkernel = NULL;
1160 cl_mem dev_vmeta = NULL;
1165 size_t iorigin[] = { roi_out->
x - roi_in->
x, roi_out->
y - roi_in->
y, 0 };
1166 size_t oorigin[] = { 0, 0, 0 };
1167 size_t region[] = { roi_out->
width, roi_out->
height, 1 };
1171 if(err != CL_SUCCESS)
goto error;
1181 const float resample_scale = roi_out->
scale / roi_in->
scale;
1184 roi_out->
width, roi_out->
x, resample_scale,
1185 &hlength, &hkernel, &hindex, &hmeta))
1189 roi_out->
height, roi_out->
y, resample_scale,
1190 &vlength, &vkernel, &vindex, &vmeta))
1193 int hmaxtaps = -1, vmaxtaps = -1;
1194 for(
int k = 0;
k < roi_out->
width;
k++) hmaxtaps =
MAX(hmaxtaps, hlength[
k]);
1195 for(
int k = 0;
k < roi_out->
height;
k++) vmaxtaps =
MAX(vmaxtaps, vlength[
k]);
1218 .cellsize = 4 *
sizeof(float),
1219 .overhead = hmaxtaps *
sizeof(
float) + hmaxtaps *
sizeof(int),
1221 .sizey = (1 << 16) * taps };
1224 vblocksize = locopt.
sizey;
1228 if(vblocksize < taps)
1234 err = CL_INVALID_WORK_GROUP_SIZE;
1239 size_t local[3] = { 1, vblocksize, 1 };
1329 const float *
const in,
1333 int *hlength = NULL;
1334 float *hkernel = NULL;
1336 int *vlength = NULL;
1337 float *vkernel = NULL;
1341 const size_t out_stride = roi_out->
width *
sizeof(float);
1342 const size_t in_stride = roi_in->
width *
sizeof(float);
1347 const size_t x0 = (roi_out->
x - roi_in->
x) *
sizeof(
float);
1348 const size_t y0 = (roi_out->
y - roi_in->
y);
1350 for(
int y = 0; y < roi_out->
height; y++)
1352 float *
i = (
float *)((
char *)in + in_stride * (y + y0) + x0);
1353 float *
o = (
float *)((
char *)
out + out_stride * y);
1354 memcpy(
o,
i, out_stride);
1365 &hlength, &hkernel, &hindex, NULL))
1370 &vlength, &vkernel, &vindex, &vmeta))
1375 for(
int oy = 0; oy < roi_out->
height; oy++)
1378 int vlidx = vmeta[3 * oy + 0];
1379 int vkidx = vmeta[3 * oy + 1];
1380 int viidx = vmeta[3 * oy + 2];
1388 int vl = vlength[vlidx++];
1391 for(
int ox = 0; ox < roi_out->
width; ox++)
1397 const int hl = hlength[hlidx++];
1398 for(
int iy = 0; iy < vl; iy++)
1401 const float *
i = (
float *)((
char *)in + in_stride * vindex[viidx++]);
1405 for(
int ix = 0; ix < hl; ix++)
1408 const size_t baseidx = (size_t)hindex[hiidx++];
1409 const float htap = hkernel[hkidx++];
1410 vhs +=
i[baseidx] * htap;
1414 const float vtap = vkernel[vkidx++];
1423 float *
o = (
float *)((
char *)
out + (size_t)oy * out_stride
1424 + (
size_t)ox *
sizeof(float));
1451 const float *
const in,
1464 const float *
const in,
static void error(char *msg)
uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
static void * dt_atomic_get_ptr(const dt_atomic_ptr *var)
static void dt_atomic_set_ptr(dt_atomic_ptr *var, void *value)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
static const float const float const float min
const dt_colormatrix_t dt_aligned_pixel_t out
dt_store_simd_aligned(out, dt_mat3x4_mul_vec4(vin, dt_colormatrix_row_to_simd(matrix, 0), dt_colormatrix_row_to_simd(matrix, 1), dt_colormatrix_row_to_simd(matrix, 2)))
uint64_t dt_conf_generation(void)
A counter that advances whenever a conf value actually changes.
const char * dt_conf_get_string_const(const char *name)
Borrow the stored string for name without copying it.
static CameraMetaData * meta
const struct dt_interpolation * dt_interpolation_new(enum dt_interpolation_type type)
static dt_atomic_ptr _userpref_itor
#define MAX_HALF_FILTER_WIDTH
__DT_CLONE_TARGETS__ void dt_interpolation_compute_pixel4c(const struct dt_interpolation *itor, const float *in, float *out, const float x, const float y, const int width, const int height, const int linestride)
static void _interpolation_resample_1c_plain(const struct dt_interpolation *itor, float *out, const dt_iop_roi_t *const roi_out, const float *const in, const dt_iop_roi_t *const roi_in)
static float _maketaps_mitchell(float *taps, const size_t num_taps, const float width, const float first_tap, const float interval)
static const struct dt_interpolation * _resolve_by_name(const char *conf_key)
static uint32_t roundToNextPowerOfTwo(uint32_t x)
#define RESAMPLING_BORDER_MODE
void dt_interpolation_resample_roi(const struct dt_interpolation *itor, float *out, const dt_iop_roi_t *const roi_out, const float *const in, const dt_iop_roi_t *const roi_in)
static __DT_CLONE_TARGETS__ gboolean _prepare_resampling_plan(const struct dt_interpolation *itor, const int in, const int in_x0, const int out, const int out_x0, const float scale, int **plength, float **pkernel, int **pindex, int **pmeta)
void dt_interpolation_resample_roi_1c(const struct dt_interpolation *itor, float *out, const dt_iop_roi_t *const roi_out, const float *const in, const dt_iop_roi_t *const roi_in)
void dt_interpolation_resample(const struct dt_interpolation *itor, float *out, const dt_iop_roi_t *const roi_out, const float *const in, const dt_iop_roi_t *const roi_in)
int dt_interpolation_resample_cl(const struct dt_interpolation *itor, const int devid, cl_mem dev_out, const dt_iop_roi_t *const roi_out, cl_mem dev_in, const dt_iop_roi_t *const roi_in)
void dt_interpolation_resample_1c(const struct dt_interpolation *itor, float *out, const dt_iop_roi_t *const roi_out, const float *const in, const dt_iop_roi_t *const roi_in)
static dt_interpolation_cl_global_t * _interpolation_cl_global
void dt_interpolation_free_cl_global(void)
static const struct dt_interpolation * _userpref_cached(const char *conf_key, dt_atomic_uint64 *generation, dt_atomic_ptr *slot)
static float _maketaps_bilinear(float *taps, const size_t num_taps, const float width, const float first_tap, const float interval)
int dt_interpolation_resample_roi_cl(const struct dt_interpolation *itor, const int devid, cl_mem dev_out, const dt_iop_roi_t *const roi_out, cl_mem dev_in, const dt_iop_roi_t *const roi_in)
void dt_interpolation_init_cl_global(void)
static const struct dt_interpolation dt_interpolator[]
__DT_CLONE_TARGETS__ float dt_interpolation_compute_sample(const struct dt_interpolation *itor, const float *in, const float x, const float y, const int width, const int height, const int samplestride, const int linestride)
#define INTERPOLATION_BORDER_MODE
static __DT_CLONE_TARGETS__ void _interpolation_resample_plain(const struct dt_interpolation *itor, float *const restrict out, const dt_iop_roi_t *const roi_out, const float *const restrict in, const dt_iop_roi_t *const roi_in)
static dt_atomic_uint64 _userpref_generation
static void _compute_downsampling_kernel(const struct dt_interpolation *itor, int *taps, int *first, float *kernel, float *norm, const float outoinratio, const int xout)
static dt_atomic_ptr _userpref_warp_itor
static dt_atomic_uint64 _userpref_warp_generation
static float _maketaps_bicubic(float *taps, const size_t num_taps, const float width, const float first_tap, const float interval)
@ DT_INTERPOLATION_BICUBIC
@ DT_INTERPOLATION_BILINEAR
@ DT_INTERPOLATION_DEFAULT
@ DT_INTERPOLATION_MITCHELL
@ DT_INTERPOLATION_USERPREF
@ DT_INTERPOLATION_DEFAULT_WARP
@ DT_INTERPOLATION_USERPREF_WARP
static float kernel(const float *x, const float *y)
_lib_location_type_t type
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
static float ceil_fast(float x)
#define DT_ALIGNED_ARRAY
Align an object on a cacheline boundary, so AVX2 can load it whole.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
static size_t dt_round_size(const size_t size, const size_t alignment)
Round size UP to the next multiple of alignment.
#define DT_CACHELINE_BYTES
int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
int dt_opencl_create_kernel(const int prog, const char *name)
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
void dt_opencl_free_kernel(const int kernel)
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 dt_omploop_sfence()
#define __OMP_PARALLEL_FOR__(...)
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
#define dt_pixelpipe_cache_free_align(mem)
dt_store_simd(out, value)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
static void copy_pixel_nontemporal(float *const __restrict__ out, const float *const __restrict__ in)
#define for_four_channels(_var,...)
unsigned __int64 uint64_t
int kernel_interpolation_resample
dt_interpolation_func maketaps
enum dt_interpolation_type id
Region of interest passed through the pixelpipe.
#define __DT_CLONE_TARGETS__