+#define OPJ_S_off(i,off) a[(OPJ_UINT32)(i)*2*4+off]
+#define OPJ_D_off(i,off) a[(1+(OPJ_UINT32)(i)*2)*4+off]
+#define OPJ_S__off(i,off) ((i)<0?OPJ_S_off(0,off):((i)>=sn?OPJ_S_off(sn-1,off):OPJ_S_off(i,off)))
+#define OPJ_D__off(i,off) ((i)<0?OPJ_D_off(0,off):((i)>=dn?OPJ_D_off(dn-1,off):OPJ_D_off(i,off)))
+#define OPJ_SS__off(i,off) ((i)<0?OPJ_S_off(0,off):((i)>=dn?OPJ_S_off(dn-1,off):OPJ_S_off(i,off)))
+#define OPJ_DD__off(i,off) ((i)<0?OPJ_D_off(0,off):((i)>=sn?OPJ_D_off(sn-1,off):OPJ_D_off(i,off)))
+
+static void opj_dwt_decode_partial_1_parallel(OPJ_INT32 *a,
+ OPJ_UINT32 nb_cols,
+ OPJ_INT32 dn, OPJ_INT32 sn,
+ OPJ_INT32 cas,
+ OPJ_INT32 win_l_x0,
+ OPJ_INT32 win_l_x1,
+ OPJ_INT32 win_h_x0,
+ OPJ_INT32 win_h_x1)
+{
+ OPJ_INT32 i;
+ OPJ_UINT32 off;
+
+ (void)nb_cols;
+
+ if (!cas) {
+ if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */
+
+ /* Naive version is :
+ for (i = win_l_x0; i < i_max; i++) {
+ OPJ_S(i) -= (OPJ_D_(i - 1) + OPJ_D_(i) + 2) >> 2;
+ }
+ for (i = win_h_x0; i < win_h_x1; i++) {
+ OPJ_D(i) += (OPJ_S_(i) + OPJ_S_(i + 1)) >> 1;
+ }
+ but the compiler doesn't manage to unroll it to avoid bound
+ checking in OPJ_S_ and OPJ_D_ macros
+ */
+
+ i = win_l_x0;
+ if (i < win_l_x1) {
+ OPJ_INT32 i_max;
+
+ /* Left-most case */
+ for (off = 0; off < 4; off++) {
+ OPJ_S_off(i, off) -= (OPJ_D__off(i - 1, off) + OPJ_D__off(i, off) + 2) >> 2;
+ }
+ i ++;
+
+ i_max = win_l_x1;
+ if (i_max > dn) {
+ i_max = dn;
+ }
+
+#ifdef __SSE2__
+ if (i + 1 < i_max) {
+ const __m128i two = _mm_set1_epi32(2);
+ __m128i Dm1 = _mm_load_si128((__m128i * const)(a + 4 + (i - 1) * 8));
+ for (; i + 1 < i_max; i += 2) {
+ /* No bound checking */
+ __m128i S = _mm_load_si128((__m128i * const)(a + i * 8));
+ __m128i D = _mm_load_si128((__m128i * const)(a + 4 + i * 8));
+ __m128i S1 = _mm_load_si128((__m128i * const)(a + (i + 1) * 8));
+ __m128i D1 = _mm_load_si128((__m128i * const)(a + 4 + (i + 1) * 8));
+ S = _mm_sub_epi32(S,
+ _mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(Dm1, D), two), 2));
+ S1 = _mm_sub_epi32(S1,
+ _mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(D, D1), two), 2));
+ _mm_store_si128((__m128i*)(a + i * 8), S);
+ _mm_store_si128((__m128i*)(a + (i + 1) * 8), S1);
+ Dm1 = D1;
+ }
+ }
+#endif
+
+ for (; i < i_max; i++) {
+ /* No bound checking */
+ for (off = 0; off < 4; off++) {
+ OPJ_S_off(i, off) -= (OPJ_D_off(i - 1, off) + OPJ_D_off(i, off) + 2) >> 2;
+ }
+ }
+ for (; i < win_l_x1; i++) {
+ /* Right-most case */
+ for (off = 0; off < 4; off++) {
+ OPJ_S_off(i, off) -= (OPJ_D__off(i - 1, off) + OPJ_D__off(i, off) + 2) >> 2;
+ }
+ }
+ }
+
+ i = win_h_x0;
+ if (i < win_h_x1) {
+ OPJ_INT32 i_max = win_h_x1;
+ if (i_max >= sn) {
+ i_max = sn - 1;
+ }
+
+#ifdef __SSE2__
+ if (i + 1 < i_max) {
+ __m128i S = _mm_load_si128((__m128i * const)(a + i * 8));
+ for (; i + 1 < i_max; i += 2) {
+ /* No bound checking */
+ __m128i D = _mm_load_si128((__m128i * const)(a + 4 + i * 8));
+ __m128i S1 = _mm_load_si128((__m128i * const)(a + (i + 1) * 8));
+ __m128i D1 = _mm_load_si128((__m128i * const)(a + 4 + (i + 1) * 8));
+ __m128i S2 = _mm_load_si128((__m128i * const)(a + (i + 2) * 8));
+ D = _mm_add_epi32(D, _mm_srai_epi32(_mm_add_epi32(S, S1), 1));
+ D1 = _mm_add_epi32(D1, _mm_srai_epi32(_mm_add_epi32(S1, S2), 1));
+ _mm_store_si128((__m128i*)(a + 4 + i * 8), D);
+ _mm_store_si128((__m128i*)(a + 4 + (i + 1) * 8), D1);
+ S = S2;
+ }
+ }
+#endif
+
+ for (; i < i_max; i++) {
+ /* No bound checking */
+ for (off = 0; off < 4; off++) {
+ OPJ_D_off(i, off) += (OPJ_S_off(i, off) + OPJ_S_off(i + 1, off)) >> 1;
+ }
+ }
+ for (; i < win_h_x1; i++) {
+ /* Right-most case */
+ for (off = 0; off < 4; off++) {
+ OPJ_D_off(i, off) += (OPJ_S__off(i, off) + OPJ_S__off(i + 1, off)) >> 1;
+ }
+ }
+ }
+ }
+ } else {
+ if (!sn && dn == 1) { /* NEW : CASE ONE ELEMENT */
+ for (off = 0; off < 4; off++) {
+ OPJ_S_off(0, off) /= 2;
+ }
+ } 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;
+ }
+ }
+ 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;
+ }
+ }
+ }
+ }
+}
+