Fix some typos (found by codespell)
[openjpeg.git] / src / lib / openjp2 / dwt.c
index 8790626e5401333ebb245a37255f9f9795446ec7..2b9b9e9245c5f30dc283d382e8b5a3e63f255a66 100644 (file)
@@ -115,29 +115,17 @@ static const OPJ_FLOAT32 opj_invK   = (OPJ_FLOAT32)(1.0 / 1.230174105);
 
 /*@}*/
 
-/**
-Virtual function type for wavelet transform in 1-D
-*/
-typedef void (*DWT1DFN)(const opj_dwt_t* v);
-
 /** @name Local static functions */
 /*@{*/
 
 /**
 Forward lazy transform (horizontal)
 */
-static void opj_dwt_deinterleave_h(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn,
+static void opj_dwt_deinterleave_h(const OPJ_INT32 * OPJ_RESTRICT a,
+                                   OPJ_INT32 * OPJ_RESTRICT b,
+                                   OPJ_INT32 dn,
                                    OPJ_INT32 sn, OPJ_INT32 cas);
-/**
-Forward lazy transform (vertical)
-*/
-static void opj_dwt_deinterleave_v(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn,
-                                   OPJ_INT32 sn, OPJ_UINT32 x, OPJ_INT32 cas);
-/**
-Forward 5-3 wavelet transform in 1-D
-*/
-static void opj_dwt_encode_1(void *a, OPJ_INT32 dn, OPJ_INT32 sn,
-                             OPJ_INT32 cas);
+
 /**
 Forward 9-7 wavelet transform in 1-D
 */
@@ -158,13 +146,29 @@ static OPJ_BOOL opj_dwt_decode_partial_tile(
     opj_tcd_tilecomp_t* tilec,
     OPJ_UINT32 numres);
 
+/* Forward transform, for the vertical pass, processing cols columns */
+/* where cols <= NB_ELTS_V8 */
 /* Where void* is a OPJ_INT32* for 5x3 and OPJ_FLOAT32* for 9x7 */
-typedef void (*opj_encode_one_row_fnptr_type)(void *, OPJ_INT32, OPJ_INT32,
-        OPJ_INT32);
+typedef void (*opj_encode_and_deinterleave_v_fnptr_type)(
+    void *array,
+    void *tmp,
+    OPJ_UINT32 height,
+    OPJ_BOOL even,
+    OPJ_UINT32 stride_width,
+    OPJ_UINT32 cols);
+
+/* Where void* is a OPJ_INT32* for 5x3 and OPJ_FLOAT32* for 9x7 */
+typedef void (*opj_encode_and_deinterleave_h_one_row_fnptr_type)(
+    void *row,
+    void *tmp,
+    OPJ_UINT32 width,
+    OPJ_BOOL even);
 
 static OPJ_BOOL opj_dwt_encode_procedure(opj_thread_pool_t* tp,
         opj_tcd_tilecomp_t * tilec,
-        opj_encode_one_row_fnptr_type p_function);
+        opj_encode_and_deinterleave_v_fnptr_type p_encode_and_deinterleave_v,
+        opj_encode_and_deinterleave_h_one_row_fnptr_type
+        p_encode_and_deinterleave_h_one_row);
 
 static OPJ_UINT32 opj_dwt_max_resolution(opj_tcd_resolution_t* OPJ_RESTRICT r,
         OPJ_UINT32 i);
@@ -218,12 +222,14 @@ static const OPJ_FLOAT64 opj_dwt_norms_real[4][10] = {
 /* <summary>                             */
 /* Forward lazy transform (horizontal).  */
 /* </summary>                            */
-static void opj_dwt_deinterleave_h(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn,
+static void opj_dwt_deinterleave_h(const OPJ_INT32 * OPJ_RESTRICT a,
+                                   OPJ_INT32 * OPJ_RESTRICT b,
+                                   OPJ_INT32 dn,
                                    OPJ_INT32 sn, OPJ_INT32 cas)
 {
     OPJ_INT32 i;
-    OPJ_INT32 * l_dest = b;
-    OPJ_INT32 * l_src = a + cas;
+    OPJ_INT32 * OPJ_RESTRICT l_dest = b;
+    const OPJ_INT32 * OPJ_RESTRICT l_src = a + cas;
 
     for (i = 0; i < sn; ++i) {
         *l_dest++ = *l_src;
@@ -239,40 +245,13 @@ static void opj_dwt_deinterleave_h(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn,
     }
 }
 
-/* <summary>                             */
-/* Forward lazy transform (vertical).    */
-/* </summary>                            */
-static void opj_dwt_deinterleave_v(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn,
-                                   OPJ_INT32 sn, OPJ_UINT32 x, OPJ_INT32 cas)
-{
-    OPJ_INT32 i = sn;
-    OPJ_INT32 * l_dest = b;
-    OPJ_INT32 * l_src = a + cas;
-
-    while (i--) {
-        *l_dest = *l_src;
-        l_dest += x;
-        l_src += 2;
-    } /* b[i*x]=a[2*i+cas]; */
-
-    l_dest = b + (OPJ_SIZE_T)sn * (OPJ_SIZE_T)x;
-    l_src = a + 1 - cas;
-
-    i = dn;
-    while (i--) {
-        *l_dest = *l_src;
-        l_dest += x;
-        l_src += 2;
-    } /*b[(sn+i)*x]=a[(2*i+1-cas)];*/
-}
-
 #ifdef STANDARD_SLOW_VERSION
 /* <summary>                             */
 /* Inverse lazy transform (horizontal).  */
 /* </summary>                            */
 static void opj_dwt_interleave_h(const opj_dwt_t* h, OPJ_INT32 *a)
 {
-    OPJ_INT32 *ai = a;
+    const OPJ_INT32 *ai = a;
     OPJ_INT32 *bi = h->mem + h->cas;
     OPJ_INT32  i    = h->sn;
     while (i--) {
@@ -293,7 +272,7 @@ static void opj_dwt_interleave_h(const opj_dwt_t* h, OPJ_INT32 *a)
 /* </summary>                            */
 static void opj_dwt_interleave_v(const opj_dwt_t* v, OPJ_INT32 *a, OPJ_INT32 x)
 {
-    OPJ_INT32 *ai = a;
+    const OPJ_INT32 *ai = a;
     OPJ_INT32 *bi = v->mem + v->cas;
     OPJ_INT32  i = v->sn;
     while (i--) {
@@ -313,38 +292,6 @@ static void opj_dwt_interleave_v(const opj_dwt_t* v, OPJ_INT32 *a, OPJ_INT32 x)
 
 #endif /* STANDARD_SLOW_VERSION */
 
-/* <summary>                            */
-/* Forward 5-3 wavelet transform in 1-D. */
-/* </summary>                           */
-static void opj_dwt_encode_1(void *aIn, OPJ_INT32 dn, OPJ_INT32 sn,
-                             OPJ_INT32 cas)
-{
-    OPJ_INT32 i;
-    OPJ_INT32* a = (OPJ_INT32*)aIn;
-
-    if (!cas) {
-        if ((dn > 0) || (sn > 1)) { /* NEW :  CASE ONE ELEMENT */
-            for (i = 0; i < dn; i++) {
-                OPJ_D(i) -= (OPJ_S_(i) + OPJ_S_(i + 1)) >> 1;
-            }
-            for (i = 0; i < sn; i++) {
-                OPJ_S(i) += (OPJ_D_(i - 1) + OPJ_D_(i) + 2) >> 2;
-            }
-        }
-    } else {
-        if (!sn && dn == 1) {       /* NEW :  CASE ONE ELEMENT */
-            OPJ_S(0) *= 2;
-        } else {
-            for (i = 0; i < dn; i++) {
-                OPJ_S(i) -= (OPJ_DD_(i) + OPJ_DD_(i - 1)) >> 1;
-            }
-            for (i = 0; i < sn; i++) {
-                OPJ_D(i) += (OPJ_SS_(i) + OPJ_SS_(i + 1) + 2) >> 2;
-            }
-        }
-    }
-}
-
 #ifdef STANDARD_SLOW_VERSION
 /* <summary>                            */
 /* Inverse 5-3 wavelet transform in 1-D. */
@@ -438,7 +385,8 @@ static void  opj_idwt53_h_cas0(OPJ_INT32* tmp,
         s0n = s1n - ((d1c + d1n + 2) >> 2);
 
         tmp[i  ] = s0c;
-        tmp[i + 1] = d1c + ((s0c + s0n) >> 1);
+        tmp[i + 1] = opj_int_add_no_overflow(d1c, opj_int_add_no_overflow(s0c,
+                                             s0n) >> 1);
     }
 
     tmp[i] = s0n;
@@ -503,7 +451,7 @@ static void  opj_idwt53_h_cas1(OPJ_INT32* tmp,
 
         dn = in_odd[j] - ((s1 + s2 + 2) >> 2);
         tmp[i  ] = dc;
-        tmp[i + 1] = s1 + ((dn + dc) >> 1);
+        tmp[i + 1] = opj_int_add_no_overflow(s1, opj_int_add_no_overflow(dn, dc) >> 1);
 
         dc = dn;
         s1 = s2;
@@ -565,7 +513,7 @@ static void opj_idwt53_h(const opj_dwt_t *dwt,
 
 #if (defined(__SSE2__) || defined(__AVX2__)) && !defined(STANDARD_SLOW_VERSION)
 
-/* Conveniency macros to improve the readabilty of the formulas */
+/* Conveniency macros to improve the readability of the formulas */
 #if __AVX2__
 #define VREG        __m256i
 #define LOAD_CST(x) _mm256_set1_epi32(x)
@@ -849,7 +797,8 @@ static void opj_idwt3_v_cas0(OPJ_INT32* tmp,
         s1n = tiledp_col[(OPJ_SIZE_T)(j + 1) * stride];
         d1n = tiledp_col[(OPJ_SIZE_T)(sn + j + 1) * stride];
 
-        s0n = s1n - ((d1c + d1n + 2) >> 2);
+        s0n = opj_int_sub_no_overflow(s1n,
+                                      opj_int_add_no_overflow(opj_int_add_no_overflow(d1c, d1n), 2) >> 2);
 
         tmp[i  ] = s0c;
         tmp[i + 1] = d1c + ((s0c + s0n) >> 1);
@@ -1006,36 +955,85 @@ static void opj_idwt53_v(const opj_dwt_t *dwt,
 #endif
 }
 
+#if 0
 static void opj_dwt_encode_step1(OPJ_FLOAT32* fw,
-                                 OPJ_UINT32 start,
                                  OPJ_UINT32 end,
                                  const OPJ_FLOAT32 c)
 {
-    OPJ_UINT32 i;
-    for (i = start; i < end; ++i) {
-        fw[i * 2] *= c;
+    OPJ_UINT32 i = 0;
+    for (; i < end; ++i) {
+        fw[0] *= c;
+        fw += 2;
+    }
+}
+#else
+static void opj_dwt_encode_step1_combined(OPJ_FLOAT32* fw,
+        OPJ_UINT32 iters_c1,
+        OPJ_UINT32 iters_c2,
+        const OPJ_FLOAT32 c1,
+        const OPJ_FLOAT32 c2)
+{
+    OPJ_UINT32 i = 0;
+    const OPJ_UINT32 iters_common =  opj_uint_min(iters_c1, iters_c2);
+    assert((((OPJ_SIZE_T)fw) & 0xf) == 0);
+    assert(opj_int_abs((OPJ_INT32)iters_c1 - (OPJ_INT32)iters_c2) <= 1);
+    for (; i + 3 < iters_common; i += 4) {
+#ifdef __SSE__
+        const __m128 vcst = _mm_set_ps(c2, c1, c2, c1);
+        *(__m128*)fw = _mm_mul_ps(*(__m128*)fw, vcst);
+        *(__m128*)(fw + 4) = _mm_mul_ps(*(__m128*)(fw + 4), vcst);
+#else
+        fw[0] *= c1;
+        fw[1] *= c2;
+        fw[2] *= c1;
+        fw[3] *= c2;
+        fw[4] *= c1;
+        fw[5] *= c2;
+        fw[6] *= c1;
+        fw[7] *= c2;
+#endif
+        fw += 8;
+    }
+    for (; i < iters_common; i++) {
+        fw[0] *= c1;
+        fw[1] *= c2;
+        fw += 2;
+    }
+    if (i < iters_c1) {
+        fw[0] *= c1;
+    } else if (i < iters_c2) {
+        fw[1] *= c2;
     }
 }
+
+#endif
+
 static void opj_dwt_encode_step2(OPJ_FLOAT32* fl, OPJ_FLOAT32* fw,
-                                 OPJ_UINT32 start,
                                  OPJ_UINT32 end,
                                  OPJ_UINT32 m,
                                  OPJ_FLOAT32 c)
 {
     OPJ_UINT32 i;
     OPJ_UINT32 imax = opj_uint_min(end, m);
-    if (start > 0) {
-        fw += 2 * start;
-        fl = fw - 2;
-    }
-    for (i = start; i < imax; ++i) {
+    if (imax > 0) {
         fw[-1] += (fl[0] + fw[0]) * c;
-        fl = fw;
         fw += 2;
+        i = 1;
+        for (; i + 3 < imax; i += 4) {
+            fw[-1] += (fw[-2] + fw[0]) * c;
+            fw[1] += (fw[0] + fw[2]) * c;
+            fw[3] += (fw[2] + fw[4]) * c;
+            fw[5] += (fw[4] + fw[6]) * c;
+            fw += 8;
+        }
+        for (; i < imax; ++i) {
+            fw[-1] += (fw[-2] + fw[0]) * c;
+            fw += 2;
+        }
     }
     if (m < end) {
         assert(m + 1 == end);
-        fw[-1] += (2 * fl[0]) * c;
+        fw[-1] += (2 * fw[-2]) * c;
     }
 }
 
@@ -1044,39 +1042,50 @@ static void opj_dwt_encode_1_real(void *aIn, OPJ_INT32 dn, OPJ_INT32 sn,
 {
     OPJ_FLOAT32* w = (OPJ_FLOAT32*)aIn;
     OPJ_INT32 a, b;
+    assert(dn + sn > 1);
     if (cas == 0) {
-        if (!((dn > 0) || (sn > 1))) {
-            return;
-        }
         a = 0;
         b = 1;
     } else {
-        if (!((sn > 0) || (dn > 1))) {
-            return;
-        }
         a = 1;
         b = 0;
     }
     opj_dwt_encode_step2(w + a, w + b + 1,
-                         0, (OPJ_UINT32)dn,
+                         (OPJ_UINT32)dn,
                          (OPJ_UINT32)opj_int_min(dn, sn - b),
                          opj_dwt_alpha);
     opj_dwt_encode_step2(w + b, w + a + 1,
-                         0, (OPJ_UINT32)sn,
+                         (OPJ_UINT32)sn,
                          (OPJ_UINT32)opj_int_min(sn, dn - a),
                          opj_dwt_beta);
     opj_dwt_encode_step2(w + a, w + b + 1,
-                         0, (OPJ_UINT32)dn,
+                         (OPJ_UINT32)dn,
                          (OPJ_UINT32)opj_int_min(dn, sn - b),
                          opj_dwt_gamma);
     opj_dwt_encode_step2(w + b, w + a + 1,
-                         0, (OPJ_UINT32)sn,
+                         (OPJ_UINT32)sn,
                          (OPJ_UINT32)opj_int_min(sn, dn - a),
                          opj_dwt_delta);
-    opj_dwt_encode_step1(w + b, 0, (OPJ_UINT32)dn,
+#if 0
+    opj_dwt_encode_step1(w + b, (OPJ_UINT32)dn,
                          opj_K);
-    opj_dwt_encode_step1(w + a, 0, (OPJ_UINT32)sn,
+    opj_dwt_encode_step1(w + a, (OPJ_UINT32)sn,
                          opj_invK);
+#else
+    if (a == 0) {
+        opj_dwt_encode_step1_combined(w,
+                                      (OPJ_UINT32)sn,
+                                      (OPJ_UINT32)dn,
+                                      opj_invK,
+                                      opj_K);
+    } else {
+        opj_dwt_encode_step1_combined(w,
+                                      (OPJ_UINT32)dn,
+                                      (OPJ_UINT32)sn,
+                                      opj_K,
+                                      opj_invK);
+    }
+#endif
 }
 
 static void opj_dwt_encode_stepsize(OPJ_INT32 stepsize, OPJ_INT32 numbps,
@@ -1095,15 +1104,89 @@ static void opj_dwt_encode_stepsize(OPJ_INT32 stepsize, OPJ_INT32 numbps,
 ==========================================================
 */
 
+/** Process one line for the horizontal pass of the 5x3 forward transform */
+static
+void opj_dwt_encode_and_deinterleave_h_one_row(void* rowIn,
+        void* tmpIn,
+        OPJ_UINT32 width,
+        OPJ_BOOL even)
+{
+    OPJ_INT32* OPJ_RESTRICT row = (OPJ_INT32*)rowIn;
+    OPJ_INT32* OPJ_RESTRICT tmp = (OPJ_INT32*)tmpIn;
+    const OPJ_INT32 sn = (OPJ_INT32)((width + (even ? 1 : 0)) >> 1);
+    const OPJ_INT32 dn = (OPJ_INT32)(width - (OPJ_UINT32)sn);
+
+    if (even) {
+        if (width > 1) {
+            OPJ_INT32 i;
+            for (i = 0; i < sn - 1; i++) {
+                tmp[sn + i] = row[2 * i + 1] - ((row[(i) * 2] + row[(i + 1) * 2]) >> 1);
+            }
+            if ((width % 2) == 0) {
+                tmp[sn + i] = row[2 * i + 1] - row[(i) * 2];
+            }
+            row[0] += (tmp[sn] + tmp[sn] + 2) >> 2;
+            for (i = 1; i < dn; i++) {
+                row[i] = row[2 * i] + ((tmp[sn + (i - 1)] + tmp[sn + i] + 2) >> 2);
+            }
+            if ((width % 2) == 1) {
+                row[i] = row[2 * i] + ((tmp[sn + (i - 1)] + tmp[sn + (i - 1)] + 2) >> 2);
+            }
+            memcpy(row + sn, tmp + sn, (OPJ_SIZE_T)dn * sizeof(OPJ_INT32));
+        }
+    } else {
+        if (width == 1) {
+            row[0] *= 2;
+        } else {
+            OPJ_INT32 i;
+            tmp[sn + 0] = row[0] - row[1];
+            for (i = 1; i < sn; i++) {
+                tmp[sn + i] = row[2 * i] - ((row[2 * i + 1] + row[2 * (i - 1) + 1]) >> 1);
+            }
+            if ((width % 2) == 1) {
+                tmp[sn + i] = row[2 * i] - row[2 * (i - 1) + 1];
+            }
+
+            for (i = 0; i < dn - 1; i++) {
+                row[i] = row[2 * i + 1] + ((tmp[sn + i] + tmp[sn + i + 1] + 2) >> 2);
+            }
+            if ((width % 2) == 0) {
+                row[i] = row[2 * i + 1] + ((tmp[sn + i] + tmp[sn + i] + 2) >> 2);
+            }
+            memcpy(row + sn, tmp + sn, (OPJ_SIZE_T)dn * sizeof(OPJ_INT32));
+        }
+    }
+}
+
+/** Process one line for the horizontal pass of the 9x7 forward transform */
+static
+void opj_dwt_encode_and_deinterleave_h_one_row_real(void* rowIn,
+        void* tmpIn,
+        OPJ_UINT32 width,
+        OPJ_BOOL even)
+{
+    OPJ_FLOAT32* OPJ_RESTRICT row = (OPJ_FLOAT32*)rowIn;
+    OPJ_FLOAT32* OPJ_RESTRICT tmp = (OPJ_FLOAT32*)tmpIn;
+    const OPJ_INT32 sn = (OPJ_INT32)((width + (even ? 1 : 0)) >> 1);
+    const OPJ_INT32 dn = (OPJ_INT32)(width - (OPJ_UINT32)sn);
+    if (width == 1) {
+        return;
+    }
+    memcpy(tmp, row, width * sizeof(OPJ_FLOAT32));
+    opj_dwt_encode_1_real(tmp, dn, sn, even ? 0 : 1);
+    opj_dwt_deinterleave_h((OPJ_INT32 * OPJ_RESTRICT)tmp,
+                           (OPJ_INT32 * OPJ_RESTRICT)row,
+                           dn, sn, even ? 0 : 1);
+}
 
 typedef struct {
     opj_dwt_t h;
-    OPJ_UINT32 rw;
-    OPJ_UINT32 w;
+    OPJ_UINT32 rw; /* Width of the resolution to process */
+    OPJ_UINT32 w; /* Width of tiledp */
     OPJ_INT32 * OPJ_RESTRICT tiledp;
     OPJ_UINT32 min_j;
     OPJ_UINT32 max_j;
-    opj_encode_one_row_fnptr_type p_function;
+    opj_encode_and_deinterleave_h_one_row_fnptr_type p_function;
 } opj_dwt_encode_h_job_t;
 
 static void opj_dwt_encode_h_func(void* user_data, opj_tls_t* tls)
@@ -1115,12 +1198,8 @@ static void opj_dwt_encode_h_func(void* user_data, opj_tls_t* tls)
     job = (opj_dwt_encode_h_job_t*)user_data;
     for (j = job->min_j; j < job->max_j; j++) {
         OPJ_INT32* OPJ_RESTRICT aj = job->tiledp + j * job->w;
-        OPJ_UINT32 k;
-        for (k = 0; k < job->rw; k++) {
-            job->h.mem[k] = aj[k];
-        }
-        (*job->p_function)(job->h.mem, job->h.dn, job->h.sn, job->h.cas);
-        opj_dwt_deinterleave_h(job->h.mem, aj, job->h.dn, job->h.sn, job->h.cas);
+        (*job->p_function)(aj, job->h.mem, job->rw,
+                           job->h.cas == 0 ? OPJ_TRUE : OPJ_FALSE);
     }
 
     opj_aligned_free(job->h.mem);
@@ -1134,7 +1213,7 @@ typedef struct {
     OPJ_INT32 * OPJ_RESTRICT tiledp;
     OPJ_UINT32 min_j;
     OPJ_UINT32 max_j;
-    opj_encode_one_row_fnptr_type p_function;
+    opj_encode_and_deinterleave_v_fnptr_type p_encode_and_deinterleave_v;
 } opj_dwt_encode_v_job_t;
 
 static void opj_dwt_encode_v_func(void* user_data, opj_tls_t* tls)
@@ -1144,29 +1223,504 @@ static void opj_dwt_encode_v_func(void* user_data, opj_tls_t* tls)
     (void)tls;
 
     job = (opj_dwt_encode_v_job_t*)user_data;
-    for (j = job->min_j; j < job->max_j; j++) {
-        OPJ_INT32* OPJ_RESTRICT aj = job->tiledp + j;
+    for (j = job->min_j; j + NB_ELTS_V8 - 1 < job->max_j; j += NB_ELTS_V8) {
+        (*job->p_encode_and_deinterleave_v)(job->tiledp + j,
+                                            job->v.mem,
+                                            job->rh,
+                                            job->v.cas == 0,
+                                            job->w,
+                                            NB_ELTS_V8);
+    }
+    if (j < job->max_j) {
+        (*job->p_encode_and_deinterleave_v)(job->tiledp + j,
+                                            job->v.mem,
+                                            job->rh,
+                                            job->v.cas == 0,
+                                            job->w,
+                                            job->max_j - j);
+    }
+
+    opj_aligned_free(job->v.mem);
+    opj_free(job);
+}
+
+/** Fetch up to cols <= NB_ELTS_V8 for each line, and put them in tmpOut */
+/* that has a NB_ELTS_V8 interleave factor. */
+static void opj_dwt_fetch_cols_vertical_pass(const void *arrayIn,
+        void *tmpOut,
+        OPJ_UINT32 height,
+        OPJ_UINT32 stride_width,
+        OPJ_UINT32 cols)
+{
+    const OPJ_INT32* OPJ_RESTRICT array = (const OPJ_INT32 * OPJ_RESTRICT)arrayIn;
+    OPJ_INT32* OPJ_RESTRICT tmp = (OPJ_INT32 * OPJ_RESTRICT)tmpOut;
+    if (cols == NB_ELTS_V8) {
         OPJ_UINT32 k;
-        for (k = 0; k < job->rh; ++k) {
-            job->v.mem[k] = aj[k * job->w];
+        for (k = 0; k < height; ++k) {
+            memcpy(tmp + NB_ELTS_V8 * k,
+                   array + k * stride_width,
+                   NB_ELTS_V8 * sizeof(OPJ_INT32));
         }
+    } else {
+        OPJ_UINT32 k;
+        for (k = 0; k < height; ++k) {
+            OPJ_UINT32 c;
+            for (c = 0; c < cols; c++) {
+                tmp[NB_ELTS_V8 * k + c] = array[c + k * stride_width];
+            }
+            for (; c < NB_ELTS_V8; c++) {
+                tmp[NB_ELTS_V8 * k + c] = 0;
+            }
+        }
+    }
+}
 
-        (*job->p_function)(job->v.mem, job->v.dn, job->v.sn, job->v.cas);
+/* Deinterleave result of forward transform, where cols <= NB_ELTS_V8 */
+/* and src contains NB_ELTS_V8 consecutive values for up to NB_ELTS_V8 */
+/* columns. */
+static INLINE void opj_dwt_deinterleave_v_cols(
+    const OPJ_INT32 * OPJ_RESTRICT src,
+    OPJ_INT32 * OPJ_RESTRICT dst,
+    OPJ_INT32 dn,
+    OPJ_INT32 sn,
+    OPJ_UINT32 stride_width,
+    OPJ_INT32 cas,
+    OPJ_UINT32 cols)
+{
+    OPJ_INT32 k;
+    OPJ_INT32 i = sn;
+    OPJ_INT32 * OPJ_RESTRICT l_dest = dst;
+    const OPJ_INT32 * OPJ_RESTRICT l_src = src + cas * NB_ELTS_V8;
+    OPJ_UINT32 c;
+
+    for (k = 0; k < 2; k++) {
+        while (i--) {
+            if (cols == NB_ELTS_V8) {
+                memcpy(l_dest, l_src, NB_ELTS_V8 * sizeof(OPJ_INT32));
+            } else {
+                c = 0;
+                switch (cols) {
+                case 7:
+                    l_dest[c] = l_src[c];
+                    c++; /* fallthru */
+                case 6:
+                    l_dest[c] = l_src[c];
+                    c++; /* fallthru */
+                case 5:
+                    l_dest[c] = l_src[c];
+                    c++; /* fallthru */
+                case 4:
+                    l_dest[c] = l_src[c];
+                    c++; /* fallthru */
+                case 3:
+                    l_dest[c] = l_src[c];
+                    c++; /* fallthru */
+                case 2:
+                    l_dest[c] = l_src[c];
+                    c++; /* fallthru */
+                default:
+                    l_dest[c] = l_src[c];
+                    break;
+                }
+            }
+            l_dest += stride_width;
+            l_src += 2 * NB_ELTS_V8;
+        }
 
-        opj_dwt_deinterleave_v(job->v.mem, aj, job->v.dn, job->v.sn, job->w,
-                               job->v.cas);
+        l_dest = dst + (OPJ_SIZE_T)sn * (OPJ_SIZE_T)stride_width;
+        l_src = src + (1 - cas) * NB_ELTS_V8;
+        i = dn;
     }
+}
 
-    opj_aligned_free(job->v.mem);
-    opj_free(job);
+
+/* Forward 5-3 transform, for the vertical pass, processing cols columns */
+/* where cols <= NB_ELTS_V8 */
+static void opj_dwt_encode_and_deinterleave_v(
+    void *arrayIn,
+    void *tmpIn,
+    OPJ_UINT32 height,
+    OPJ_BOOL even,
+    OPJ_UINT32 stride_width,
+    OPJ_UINT32 cols)
+{
+    OPJ_INT32* OPJ_RESTRICT array = (OPJ_INT32 * OPJ_RESTRICT)arrayIn;
+    OPJ_INT32* OPJ_RESTRICT tmp = (OPJ_INT32 * OPJ_RESTRICT)tmpIn;
+    const OPJ_UINT32 sn = (height + (even ? 1 : 0)) >> 1;
+    const OPJ_UINT32 dn = height - sn;
+
+    opj_dwt_fetch_cols_vertical_pass(arrayIn, tmpIn, height, stride_width, cols);
+
+#define OPJ_Sc(i) tmp[(i)*2* NB_ELTS_V8 + c]
+#define OPJ_Dc(i) tmp[((1+(i)*2))* NB_ELTS_V8 + c]
+
+#ifdef __SSE2__
+    if (height == 1) {
+        if (!even) {
+            OPJ_UINT32 c;
+            for (c = 0; c < NB_ELTS_V8; c++) {
+                tmp[c] *= 2;
+            }
+        }
+    } else if (even) {
+        OPJ_UINT32 c;
+        OPJ_UINT32 i;
+        i = 0;
+        if (i + 1 < sn) {
+            __m128i xmm_Si_0 = *(const __m128i*)(tmp + 4 * 0);
+            __m128i xmm_Si_1 = *(const __m128i*)(tmp + 4 * 1);
+            for (; i + 1 < sn; i++) {
+                __m128i xmm_Sip1_0 = *(const __m128i*)(tmp +
+                                                       (i + 1) * 2 * NB_ELTS_V8 + 4 * 0);
+                __m128i xmm_Sip1_1 = *(const __m128i*)(tmp +
+                                                       (i + 1) * 2 * NB_ELTS_V8 + 4 * 1);
+                __m128i xmm_Di_0 = *(const __m128i*)(tmp +
+                                                     (1 + i * 2) * NB_ELTS_V8 + 4 * 0);
+                __m128i xmm_Di_1 = *(const __m128i*)(tmp +
+                                                     (1 + i * 2) * NB_ELTS_V8 + 4 * 1);
+                xmm_Di_0 = _mm_sub_epi32(xmm_Di_0,
+                                         _mm_srai_epi32(_mm_add_epi32(xmm_Si_0, xmm_Sip1_0), 1));
+                xmm_Di_1 = _mm_sub_epi32(xmm_Di_1,
+                                         _mm_srai_epi32(_mm_add_epi32(xmm_Si_1, xmm_Sip1_1), 1));
+                *(__m128i*)(tmp + (1 + i * 2) * NB_ELTS_V8 + 4 * 0) =  xmm_Di_0;
+                *(__m128i*)(tmp + (1 + i * 2) * NB_ELTS_V8 + 4 * 1) =  xmm_Di_1;
+                xmm_Si_0 = xmm_Sip1_0;
+                xmm_Si_1 = xmm_Sip1_1;
+            }
+        }
+        if (((height) % 2) == 0) {
+            for (c = 0; c < NB_ELTS_V8; c++) {
+                OPJ_Dc(i) -= OPJ_Sc(i);
+            }
+        }
+        for (c = 0; c < NB_ELTS_V8; c++) {
+            OPJ_Sc(0) += (OPJ_Dc(0) + OPJ_Dc(0) + 2) >> 2;
+        }
+        i = 1;
+        if (i < dn) {
+            __m128i xmm_Dim1_0 = *(const __m128i*)(tmp + (1 +
+                                                   (i - 1) * 2) * NB_ELTS_V8 + 4 * 0);
+            __m128i xmm_Dim1_1 = *(const __m128i*)(tmp + (1 +
+                                                   (i - 1) * 2) * NB_ELTS_V8 + 4 * 1);
+            const __m128i xmm_two = _mm_set1_epi32(2);
+            for (; i < dn; i++) {
+                __m128i xmm_Di_0 = *(const __m128i*)(tmp +
+                                                     (1 + i * 2) * NB_ELTS_V8 + 4 * 0);
+                __m128i xmm_Di_1 = *(const __m128i*)(tmp +
+                                                     (1 + i * 2) * NB_ELTS_V8 + 4 * 1);
+                __m128i xmm_Si_0 = *(const __m128i*)(tmp +
+                                                     (i * 2) * NB_ELTS_V8 + 4 * 0);
+                __m128i xmm_Si_1 = *(const __m128i*)(tmp +
+                                                     (i * 2) * NB_ELTS_V8 + 4 * 1);
+                xmm_Si_0 = _mm_add_epi32(xmm_Si_0,
+                                         _mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(xmm_Dim1_0, xmm_Di_0), xmm_two), 2));
+                xmm_Si_1 = _mm_add_epi32(xmm_Si_1,
+                                         _mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(xmm_Dim1_1, xmm_Di_1), xmm_two), 2));
+                *(__m128i*)(tmp + (i * 2) * NB_ELTS_V8 + 4 * 0) = xmm_Si_0;
+                *(__m128i*)(tmp + (i * 2) * NB_ELTS_V8 + 4 * 1) = xmm_Si_1;
+                xmm_Dim1_0 = xmm_Di_0;
+                xmm_Dim1_1 = xmm_Di_1;
+            }
+        }
+        if (((height) % 2) == 1) {
+            for (c = 0; c < NB_ELTS_V8; c++) {
+                OPJ_Sc(i) += (OPJ_Dc(i - 1) + OPJ_Dc(i - 1) + 2) >> 2;
+            }
+        }
+    } else {
+        OPJ_UINT32 c;
+        OPJ_UINT32 i;
+        for (c = 0; c < NB_ELTS_V8; c++) {
+            OPJ_Sc(0) -= OPJ_Dc(0);
+        }
+        i = 1;
+        if (i < sn) {
+            __m128i xmm_Dim1_0 = *(const __m128i*)(tmp + (1 +
+                                                   (i - 1) * 2) * NB_ELTS_V8 + 4 * 0);
+            __m128i xmm_Dim1_1 = *(const __m128i*)(tmp + (1 +
+                                                   (i - 1) * 2) * NB_ELTS_V8 + 4 * 1);
+            for (; i < sn; i++) {
+                __m128i xmm_Di_0 = *(const __m128i*)(tmp +
+                                                     (1 + i * 2) * NB_ELTS_V8 + 4 * 0);
+                __m128i xmm_Di_1 = *(const __m128i*)(tmp +
+                                                     (1 + i * 2) * NB_ELTS_V8 + 4 * 1);
+                __m128i xmm_Si_0 = *(const __m128i*)(tmp +
+                                                     (i * 2) * NB_ELTS_V8 + 4 * 0);
+                __m128i xmm_Si_1 = *(const __m128i*)(tmp +
+                                                     (i * 2) * NB_ELTS_V8 + 4 * 1);
+                xmm_Si_0 = _mm_sub_epi32(xmm_Si_0,
+                                         _mm_srai_epi32(_mm_add_epi32(xmm_Di_0, xmm_Dim1_0), 1));
+                xmm_Si_1 = _mm_sub_epi32(xmm_Si_1,
+                                         _mm_srai_epi32(_mm_add_epi32(xmm_Di_1, xmm_Dim1_1), 1));
+                *(__m128i*)(tmp + (i * 2) * NB_ELTS_V8 + 4 * 0) = xmm_Si_0;
+                *(__m128i*)(tmp + (i * 2) * NB_ELTS_V8 + 4 * 1) = xmm_Si_1;
+                xmm_Dim1_0 = xmm_Di_0;
+                xmm_Dim1_1 = xmm_Di_1;
+            }
+        }
+        if (((height) % 2) == 1) {
+            for (c = 0; c < NB_ELTS_V8; c++) {
+                OPJ_Sc(i) -= OPJ_Dc(i - 1);
+            }
+        }
+        i = 0;
+        if (i + 1 < dn) {
+            __m128i xmm_Si_0 = *((const __m128i*)(tmp + 4 * 0));
+            __m128i xmm_Si_1 = *((const __m128i*)(tmp + 4 * 1));
+            const __m128i xmm_two = _mm_set1_epi32(2);
+            for (; i + 1 < dn; i++) {
+                __m128i xmm_Sip1_0 = *(const __m128i*)(tmp +
+                                                       (i + 1) * 2 * NB_ELTS_V8 + 4 * 0);
+                __m128i xmm_Sip1_1 = *(const __m128i*)(tmp +
+                                                       (i + 1) * 2 * NB_ELTS_V8 + 4 * 1);
+                __m128i xmm_Di_0 = *(const __m128i*)(tmp +
+                                                     (1 + i * 2) * NB_ELTS_V8 + 4 * 0);
+                __m128i xmm_Di_1 = *(const __m128i*)(tmp +
+                                                     (1 + i * 2) * NB_ELTS_V8 + 4 * 1);
+                xmm_Di_0 = _mm_add_epi32(xmm_Di_0,
+                                         _mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(xmm_Si_0, xmm_Sip1_0), xmm_two), 2));
+                xmm_Di_1 = _mm_add_epi32(xmm_Di_1,
+                                         _mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(xmm_Si_1, xmm_Sip1_1), xmm_two), 2));
+                *(__m128i*)(tmp + (1 + i * 2) * NB_ELTS_V8 + 4 * 0) = xmm_Di_0;
+                *(__m128i*)(tmp + (1 + i * 2) * NB_ELTS_V8 + 4 * 1) = xmm_Di_1;
+                xmm_Si_0 = xmm_Sip1_0;
+                xmm_Si_1 = xmm_Sip1_1;
+            }
+        }
+        if (((height) % 2) == 0) {
+            for (c = 0; c < NB_ELTS_V8; c++) {
+                OPJ_Dc(i) += (OPJ_Sc(i) + OPJ_Sc(i) + 2) >> 2;
+            }
+        }
+    }
+#else
+    if (even) {
+        OPJ_UINT32 c;
+        if (height > 1) {
+            OPJ_UINT32 i;
+            for (i = 0; i + 1 < sn; i++) {
+                for (c = 0; c < NB_ELTS_V8; c++) {
+                    OPJ_Dc(i) -= (OPJ_Sc(i) + OPJ_Sc(i + 1)) >> 1;
+                }
+            }
+            if (((height) % 2) == 0) {
+                for (c = 0; c < NB_ELTS_V8; c++) {
+                    OPJ_Dc(i) -= OPJ_Sc(i);
+                }
+            }
+            for (c = 0; c < NB_ELTS_V8; c++) {
+                OPJ_Sc(0) += (OPJ_Dc(0) + OPJ_Dc(0) + 2) >> 2;
+            }
+            for (i = 1; i < dn; i++) {
+                for (c = 0; c < NB_ELTS_V8; c++) {
+                    OPJ_Sc(i) += (OPJ_Dc(i - 1) + OPJ_Dc(i) + 2) >> 2;
+                }
+            }
+            if (((height) % 2) == 1) {
+                for (c = 0; c < NB_ELTS_V8; c++) {
+                    OPJ_Sc(i) += (OPJ_Dc(i - 1) + OPJ_Dc(i - 1) + 2) >> 2;
+                }
+            }
+        }
+    } else {
+        OPJ_UINT32 c;
+        if (height == 1) {
+            for (c = 0; c < NB_ELTS_V8; c++) {
+                OPJ_Sc(0) *= 2;
+            }
+        } else {
+            OPJ_UINT32 i;
+            for (c = 0; c < NB_ELTS_V8; c++) {
+                OPJ_Sc(0) -= OPJ_Dc(0);
+            }
+            for (i = 1; i < sn; i++) {
+                for (c = 0; c < NB_ELTS_V8; c++) {
+                    OPJ_Sc(i) -= (OPJ_Dc(i) + OPJ_Dc(i - 1)) >> 1;
+                }
+            }
+            if (((height) % 2) == 1) {
+                for (c = 0; c < NB_ELTS_V8; c++) {
+                    OPJ_Sc(i) -= OPJ_Dc(i - 1);
+                }
+            }
+            for (i = 0; i + 1 < dn; i++) {
+                for (c = 0; c < NB_ELTS_V8; c++) {
+                    OPJ_Dc(i) += (OPJ_Sc(i) + OPJ_Sc(i + 1) + 2) >> 2;
+                }
+            }
+            if (((height) % 2) == 0) {
+                for (c = 0; c < NB_ELTS_V8; c++) {
+                    OPJ_Dc(i) += (OPJ_Sc(i) + OPJ_Sc(i) + 2) >> 2;
+                }
+            }
+        }
+    }
+#endif
+
+    if (cols == NB_ELTS_V8) {
+        opj_dwt_deinterleave_v_cols(tmp, array, (OPJ_INT32)dn, (OPJ_INT32)sn,
+                                    stride_width, even ? 0 : 1, NB_ELTS_V8);
+    } else {
+        opj_dwt_deinterleave_v_cols(tmp, array, (OPJ_INT32)dn, (OPJ_INT32)sn,
+                                    stride_width, even ? 0 : 1, cols);
+    }
+}
+
+static void opj_v8dwt_encode_step1(OPJ_FLOAT32* fw,
+                                   OPJ_UINT32 end,
+                                   const OPJ_FLOAT32 cst)
+{
+    OPJ_UINT32 i;
+#ifdef __SSE__
+    __m128* vw = (__m128*) fw;
+    const __m128 vcst = _mm_set1_ps(cst);
+    for (i = 0; i < end; ++i) {
+        vw[0] = _mm_mul_ps(vw[0], vcst);
+        vw[1] = _mm_mul_ps(vw[1], vcst);
+        vw += 2 * (NB_ELTS_V8 * sizeof(OPJ_FLOAT32) / sizeof(__m128));
+    }
+#else
+    OPJ_UINT32 c;
+    for (i = 0; i < end; ++i) {
+        for (c = 0; c < NB_ELTS_V8; c++) {
+            fw[i * 2 * NB_ELTS_V8 + c] *= cst;
+        }
+    }
+#endif
+}
+
+static void opj_v8dwt_encode_step2(OPJ_FLOAT32* fl, OPJ_FLOAT32* fw,
+                                   OPJ_UINT32 end,
+                                   OPJ_UINT32 m,
+                                   OPJ_FLOAT32 cst)
+{
+    OPJ_UINT32 i;
+    OPJ_UINT32 imax = opj_uint_min(end, m);
+#ifdef __SSE__
+    __m128* vw = (__m128*) fw;
+    __m128 vcst = _mm_set1_ps(cst);
+    if (imax > 0) {
+        __m128* vl = (__m128*) fl;
+        vw[-2] = _mm_add_ps(vw[-2], _mm_mul_ps(_mm_add_ps(vl[0], vw[0]), vcst));
+        vw[-1] = _mm_add_ps(vw[-1], _mm_mul_ps(_mm_add_ps(vl[1], vw[1]), vcst));
+        vw += 2 * (NB_ELTS_V8 * sizeof(OPJ_FLOAT32) / sizeof(__m128));
+        i = 1;
+
+        for (; i < imax; ++i) {
+            vw[-2] = _mm_add_ps(vw[-2], _mm_mul_ps(_mm_add_ps(vw[-4], vw[0]), vcst));
+            vw[-1] = _mm_add_ps(vw[-1], _mm_mul_ps(_mm_add_ps(vw[-3], vw[1]), vcst));
+            vw += 2 * (NB_ELTS_V8 * sizeof(OPJ_FLOAT32) / sizeof(__m128));
+        }
+    }
+    if (m < end) {
+        assert(m + 1 == end);
+        vcst = _mm_add_ps(vcst, vcst);
+        vw[-2] = _mm_add_ps(vw[-2], _mm_mul_ps(vw[-4], vcst));
+        vw[-1] = _mm_add_ps(vw[-1], _mm_mul_ps(vw[-3], vcst));
+    }
+#else
+    OPJ_INT32 c;
+    if (imax > 0) {
+        for (c = 0; c < NB_ELTS_V8; c++) {
+            fw[-1 * NB_ELTS_V8 + c] += (fl[0 * NB_ELTS_V8 + c] + fw[0 * NB_ELTS_V8 + c]) *
+                                       cst;
+        }
+        fw += 2 * NB_ELTS_V8;
+        i = 1;
+        for (; i < imax; ++i) {
+            for (c = 0; c < NB_ELTS_V8; c++) {
+                fw[-1 * NB_ELTS_V8 + c] += (fw[-2 * NB_ELTS_V8 + c] + fw[0 * NB_ELTS_V8 + c]) *
+                                           cst;
+            }
+            fw += 2 * NB_ELTS_V8;
+        }
+    }
+    if (m < end) {
+        assert(m + 1 == end);
+        for (c = 0; c < NB_ELTS_V8; c++) {
+            fw[-1 * NB_ELTS_V8 + c] += (2 * fw[-2 * NB_ELTS_V8 + c]) * cst;
+        }
+    }
+#endif
+}
+
+/* Forward 9-7 transform, for the vertical pass, processing cols columns */
+/* where cols <= NB_ELTS_V8 */
+static void opj_dwt_encode_and_deinterleave_v_real(
+    void *arrayIn,
+    void *tmpIn,
+    OPJ_UINT32 height,
+    OPJ_BOOL even,
+    OPJ_UINT32 stride_width,
+    OPJ_UINT32 cols)
+{
+    OPJ_FLOAT32* OPJ_RESTRICT array = (OPJ_FLOAT32 * OPJ_RESTRICT)arrayIn;
+    OPJ_FLOAT32* OPJ_RESTRICT tmp = (OPJ_FLOAT32 * OPJ_RESTRICT)tmpIn;
+    const OPJ_INT32 sn = (OPJ_INT32)((height + (even ? 1 : 0)) >> 1);
+    const OPJ_INT32 dn = (OPJ_INT32)(height - (OPJ_UINT32)sn);
+    OPJ_INT32 a, b;
+
+    if (height == 1) {
+        return;
+    }
+
+    opj_dwt_fetch_cols_vertical_pass(arrayIn, tmpIn, height, stride_width, cols);
+
+    if (even) {
+        a = 0;
+        b = 1;
+    } else {
+        a = 1;
+        b = 0;
+    }
+    opj_v8dwt_encode_step2(tmp + a * NB_ELTS_V8,
+                           tmp + (b + 1) * NB_ELTS_V8,
+                           (OPJ_UINT32)dn,
+                           (OPJ_UINT32)opj_int_min(dn, sn - b),
+                           opj_dwt_alpha);
+    opj_v8dwt_encode_step2(tmp + b * NB_ELTS_V8,
+                           tmp + (a + 1) * NB_ELTS_V8,
+                           (OPJ_UINT32)sn,
+                           (OPJ_UINT32)opj_int_min(sn, dn - a),
+                           opj_dwt_beta);
+    opj_v8dwt_encode_step2(tmp + a * NB_ELTS_V8,
+                           tmp + (b + 1) * NB_ELTS_V8,
+                           (OPJ_UINT32)dn,
+                           (OPJ_UINT32)opj_int_min(dn, sn - b),
+                           opj_dwt_gamma);
+    opj_v8dwt_encode_step2(tmp + b * NB_ELTS_V8,
+                           tmp + (a + 1) * NB_ELTS_V8,
+                           (OPJ_UINT32)sn,
+                           (OPJ_UINT32)opj_int_min(sn, dn - a),
+                           opj_dwt_delta);
+    opj_v8dwt_encode_step1(tmp + b * NB_ELTS_V8, (OPJ_UINT32)dn,
+                           opj_K);
+    opj_v8dwt_encode_step1(tmp + a * NB_ELTS_V8, (OPJ_UINT32)sn,
+                           opj_invK);
+
+
+    if (cols == NB_ELTS_V8) {
+        opj_dwt_deinterleave_v_cols((OPJ_INT32*)tmp,
+                                    (OPJ_INT32*)array,
+                                    (OPJ_INT32)dn, (OPJ_INT32)sn,
+                                    stride_width, even ? 0 : 1, NB_ELTS_V8);
+    } else {
+        opj_dwt_deinterleave_v_cols((OPJ_INT32*)tmp,
+                                    (OPJ_INT32*)array,
+                                    (OPJ_INT32)dn, (OPJ_INT32)sn,
+                                    stride_width, even ? 0 : 1, cols);
+    }
 }
 
+
 /* <summary>                            */
 /* Forward 5-3 wavelet transform in 2-D. */
 /* </summary>                           */
 static INLINE OPJ_BOOL opj_dwt_encode_procedure(opj_thread_pool_t* tp,
         opj_tcd_tilecomp_t * tilec,
-        opj_encode_one_row_fnptr_type p_function)
+        opj_encode_and_deinterleave_v_fnptr_type p_encode_and_deinterleave_v,
+        opj_encode_and_deinterleave_h_one_row_fnptr_type
+        p_encode_and_deinterleave_h_one_row)
 {
     OPJ_INT32 i;
     OPJ_INT32 *bj = 00;
@@ -1188,11 +1742,11 @@ static INLINE OPJ_BOOL opj_dwt_encode_procedure(opj_thread_pool_t* tp,
 
     l_data_size = opj_dwt_max_resolution(tilec->resolutions, tilec->numresolutions);
     /* overflow check */
-    if (l_data_size > (SIZE_MAX / sizeof(OPJ_INT32))) {
+    if (l_data_size > (SIZE_MAX / (NB_ELTS_V8 * sizeof(OPJ_INT32)))) {
         /* FIXME event manager error callback */
         return OPJ_FALSE;
     }
-    l_data_size *= sizeof(OPJ_INT32);
+    l_data_size *= NB_ELTS_V8 * sizeof(OPJ_INT32);
     bj = (OPJ_INT32*)opj_aligned_32_malloc(l_data_size);
     /* l_data_size is equal to 0 when numresolutions == 1 but bj is not used */
     /* in that case, so do not error out */
@@ -1225,17 +1779,22 @@ static INLINE OPJ_BOOL opj_dwt_encode_procedure(opj_thread_pool_t* tp,
         dn = (OPJ_INT32)(rh - rh1);
 
         /* Perform vertical pass */
-        if (num_threads <= 1 || rw <= 1) {
-            for (j = 0; j < rw; ++j) {
-                OPJ_INT32* OPJ_RESTRICT aj = tiledp + j;
-                OPJ_UINT32 k;
-                for (k = 0; k < rh; ++k) {
-                    bj[k] = aj[k * w];
-                }
-
-                (*p_function)(bj, dn, sn, cas_col);
-
-                opj_dwt_deinterleave_v(bj, aj, dn, sn, w, cas_col);
+        if (num_threads <= 1 || rw < 2 * NB_ELTS_V8) {
+            for (j = 0; j + NB_ELTS_V8 - 1 < rw; j += NB_ELTS_V8) {
+                p_encode_and_deinterleave_v(tiledp + j,
+                                            bj,
+                                            rh,
+                                            cas_col == 0,
+                                            w,
+                                            NB_ELTS_V8);
+            }
+            if (j < rw) {
+                p_encode_and_deinterleave_v(tiledp + j,
+                                            bj,
+                                            rh,
+                                            cas_col == 0,
+                                            w,
+                                            rw - j);
             }
         }  else {
             OPJ_UINT32 num_jobs = (OPJ_UINT32)num_threads;
@@ -1244,7 +1803,7 @@ static INLINE OPJ_BOOL opj_dwt_encode_procedure(opj_thread_pool_t* tp,
             if (rw < num_jobs) {
                 num_jobs = rw;
             }
-            step_j = (rw / num_jobs);
+            step_j = ((rw / num_jobs) / NB_ELTS_V8) * NB_ELTS_V8;
 
             for (j = 0; j < num_jobs; j++) {
                 opj_dwt_encode_v_job_t* job;
@@ -1269,11 +1828,8 @@ static INLINE OPJ_BOOL opj_dwt_encode_procedure(opj_thread_pool_t* tp,
                 job->w = w;
                 job->tiledp = tiledp;
                 job->min_j = j * step_j;
-                job->max_j = (j + 1U) * step_j; /* this can overflow */
-                if (j == (num_jobs - 1U)) {  /* this will take care of the overflow */
-                    job->max_j = rw;
-                }
-                job->p_function = p_function;
+                job->max_j = (j + 1 == num_jobs) ? rw : (j + 1) * step_j;
+                job->p_encode_and_deinterleave_v = p_encode_and_deinterleave_v;
                 opj_thread_pool_submit_job(tp, opj_dwt_encode_v_func, job);
             }
             opj_thread_pool_wait_completion(tp, 0);
@@ -1286,12 +1842,8 @@ static INLINE OPJ_BOOL opj_dwt_encode_procedure(opj_thread_pool_t* tp,
         if (num_threads <= 1 || rh <= 1) {
             for (j = 0; j < rh; j++) {
                 OPJ_INT32* OPJ_RESTRICT aj = tiledp + j * w;
-                OPJ_UINT32 k;
-                for (k = 0; k < rw; k++) {
-                    bj[k] = aj[k];
-                }
-                (*p_function)(bj, dn, sn, cas_row);
-                opj_dwt_deinterleave_h(bj, aj, dn, sn, cas_row);
+                (*p_encode_and_deinterleave_h_one_row)(aj, bj, rw,
+                                                       cas_row == 0 ? OPJ_TRUE : OPJ_FALSE);
             }
         }  else {
             OPJ_UINT32 num_jobs = (OPJ_UINT32)num_threads;
@@ -1329,7 +1881,7 @@ static INLINE OPJ_BOOL opj_dwt_encode_procedure(opj_thread_pool_t* tp,
                 if (j == (num_jobs - 1U)) {  /* this will take care of the overflow */
                     job->max_j = rh;
                 }
-                job->p_function = p_function;
+                job->p_function = p_encode_and_deinterleave_h_one_row;
                 opj_thread_pool_submit_job(tp, opj_dwt_encode_h_func, job);
             }
             opj_thread_pool_wait_completion(tp, 0);
@@ -1349,7 +1901,9 @@ static INLINE OPJ_BOOL opj_dwt_encode_procedure(opj_thread_pool_t* tp,
 OPJ_BOOL opj_dwt_encode(opj_tcd_t *p_tcd,
                         opj_tcd_tilecomp_t * tilec)
 {
-    return opj_dwt_encode_procedure(p_tcd->thread_pool, tilec, opj_dwt_encode_1);
+    return opj_dwt_encode_procedure(p_tcd->thread_pool, tilec,
+                                    opj_dwt_encode_and_deinterleave_v,
+                                    opj_dwt_encode_and_deinterleave_h_one_row);
 }
 
 /* <summary>                            */
@@ -1388,7 +1942,8 @@ OPJ_BOOL opj_dwt_encode_real(opj_tcd_t *p_tcd,
                              opj_tcd_tilecomp_t * tilec)
 {
     return opj_dwt_encode_procedure(p_tcd->thread_pool, tilec,
-                                    opj_dwt_encode_1_real);
+                                    opj_dwt_encode_and_deinterleave_v_real,
+                                    opj_dwt_encode_and_deinterleave_h_one_row_real);
 }
 
 /* <summary>                */
@@ -1423,7 +1978,7 @@ void opj_dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, OPJ_UINT32 prec)
         if (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) {
             stepsize = 1.0;
         } else {
-            OPJ_FLOAT64 norm = opj_dwt_norms_real[orient][level];
+            OPJ_FLOAT64 norm = opj_dwt_getnorm_real(level, orient);
             stepsize = (1 << (gain)) / norm;
         }
         opj_dwt_encode_stepsize((OPJ_INT32) floor(stepsize * 8192.0),
@@ -1790,10 +2345,13 @@ static void opj_dwt_decode_partial_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn,
             OPJ_S(0) /= 2;
         } else {
             for (i = win_l_x0; i < win_l_x1; i++) {
-                OPJ_D(i) -= (OPJ_SS_(i) + OPJ_SS_(i + 1) + 2) >> 2;
+                OPJ_D(i) = opj_int_sub_no_overflow(OPJ_D(i),
+                                                   opj_int_add_no_overflow(opj_int_add_no_overflow(OPJ_SS_(i), OPJ_SS_(i + 1)),
+                                                           2) >> 2);
             }
             for (i = win_h_x0; i < win_h_x1; i++) {
-                OPJ_S(i) += (OPJ_DD_(i) + OPJ_DD_(i - 1)) >> 1;
+                OPJ_S(i) = opj_int_add_no_overflow(OPJ_S(i),
+                                                   opj_int_add_no_overflow(OPJ_DD_(i), OPJ_DD_(i - 1)) >> 1);
             }
         }
     }
@@ -1931,12 +2489,17 @@ static void opj_dwt_decode_partial_1_parallel(OPJ_INT32 *a,
         } else {
             for (i = win_l_x0; i < win_l_x1; i++) {
                 for (off = 0; off < 4; off++) {
-                    OPJ_D_off(i, off) -= (OPJ_SS__off(i, off) + OPJ_SS__off(i + 1, off) + 2) >> 2;
+                    OPJ_D_off(i, off) = opj_int_sub_no_overflow(
+                                            OPJ_D_off(i, off),
+                                            opj_int_add_no_overflow(
+                                                opj_int_add_no_overflow(OPJ_SS__off(i, off), OPJ_SS__off(i + 1, off)), 2) >> 2);
                 }
             }
             for (i = win_h_x0; i < win_h_x1; i++) {
                 for (off = 0; off < 4; off++) {
-                    OPJ_S_off(i, off) += (OPJ_DD__off(i, off) + OPJ_DD__off(i - 1, off)) >> 1;
+                    OPJ_S_off(i, off) = opj_int_add_no_overflow(
+                                            OPJ_S_off(i, off),
+                                            opj_int_add_no_overflow(OPJ_DD__off(i, off), OPJ_DD__off(i - 1, off)) >> 1);
                 }
             }
         }