Commit e7edcefbba for aom
commit e7edcefbba04330a68a2808b1676904a696e9f9a
Author: Lin Zheng <linzhen@google.com>
Date: Mon Oct 26 21:34:25 2026 +0000
Optimize AVX2 kernels and bit-exact transform/RD loops
Apply AVX2 SIMD and RD loop optimizations for ~1.5% encoder speed-up.
Change-Id: I75894155d83d85c571cfb4e59f750e582e73d620
diff --git a/aom_dsp/x86/sad4d_avx2.c b/aom_dsp/x86/sad4d_avx2.c
index 8f75f97789..d14f9fc3f2 100644
--- a/aom_dsp/x86/sad4d_avx2.c
+++ b/aom_dsp/x86/sad4d_avx2.c
@@ -54,12 +54,41 @@ static AOM_FORCE_INLINE void aom_sadMxNx4d_avx2(
ref1 = ref[1];
ref2 = ref[2];
ref3 = ref[3];
- sum_ref0 = _mm256_setzero_si256();
- sum_ref2 = _mm256_setzero_si256();
- sum_ref1 = _mm256_setzero_si256();
- sum_ref3 = _mm256_setzero_si256();
- for (i = 0; i < N; i++) {
+ src_reg = _mm256_loadu_si256((const __m256i *)src);
+ sum_ref0 =
+ _mm256_sad_epu8(_mm256_loadu_si256((const __m256i *)ref0), src_reg);
+ sum_ref1 =
+ _mm256_sad_epu8(_mm256_loadu_si256((const __m256i *)ref1), src_reg);
+ sum_ref2 =
+ _mm256_sad_epu8(_mm256_loadu_si256((const __m256i *)ref2), src_reg);
+ sum_ref3 =
+ _mm256_sad_epu8(_mm256_loadu_si256((const __m256i *)ref3), src_reg);
+ for (j = 32; j < M; j += 32) {
+ src_reg = _mm256_loadu_si256((const __m256i *)(src + j));
+ ref0_reg = _mm256_sad_epu8(_mm256_loadu_si256((const __m256i *)(ref0 + j)),
+ src_reg);
+ ref1_reg = _mm256_sad_epu8(_mm256_loadu_si256((const __m256i *)(ref1 + j)),
+ src_reg);
+ ref2_reg = _mm256_sad_epu8(_mm256_loadu_si256((const __m256i *)(ref2 + j)),
+ src_reg);
+ ref3_reg = _mm256_sad_epu8(_mm256_loadu_si256((const __m256i *)(ref3 + j)),
+ src_reg);
+ sum_ref0 = _mm256_add_epi32(sum_ref0, ref0_reg);
+ sum_ref1 = _mm256_add_epi32(sum_ref1, ref1_reg);
+ sum_ref2 = _mm256_add_epi32(sum_ref2, ref2_reg);
+ sum_ref3 = _mm256_add_epi32(sum_ref3, ref3_reg);
+ }
+ src += src_stride;
+ ref0 += ref_stride;
+ ref1 += ref_stride;
+ ref2 += ref_stride;
+ ref3 += ref_stride;
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC unroll 2
+#endif
+ for (i = 1; i < N; i++) {
for (j = 0; j < M; j += 32) {
// load src and all refs
src_reg = _mm256_loadu_si256((const __m256i *)(src + j));
@@ -203,11 +232,20 @@ static AOM_FORCE_INLINE void aom_sad16xNx3d_avx2(int N, const uint8_t *src,
ref0 = ref[0];
ref1 = ref[1];
ref2 = ref[2];
- sum_ref0 = _mm256_setzero_si256();
- sum_ref2 = _mm256_setzero_si256();
- sum_ref1 = _mm256_setzero_si256();
- for (int i = 0; i < N; i += 2) {
+ src_reg = yy_loadu2_128(src + src_stride, src);
+ sum_ref0 = _mm256_sad_epu8(yy_loadu2_128(ref0 + ref_stride, ref0), src_reg);
+ sum_ref1 = _mm256_sad_epu8(yy_loadu2_128(ref1 + ref_stride, ref1), src_reg);
+ sum_ref2 = _mm256_sad_epu8(yy_loadu2_128(ref2 + ref_stride, ref2), src_reg);
+ src += 2 * src_stride;
+ ref0 += 2 * ref_stride;
+ ref1 += 2 * ref_stride;
+ ref2 += 2 * ref_stride;
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC unroll 2
+#endif
+ for (int i = 2; i < N; i += 2) {
// load src and all refs
src_reg = yy_loadu2_128(src + src_stride, src);
ref0_reg = yy_loadu2_128(ref0 + ref_stride, ref0);
@@ -248,12 +286,23 @@ static AOM_FORCE_INLINE void aom_sad16xNx4d_avx2(int N, const uint8_t *src,
ref2 = ref[2];
ref3 = ref[3];
- sum_ref0 = _mm256_setzero_si256();
- sum_ref2 = _mm256_setzero_si256();
- sum_ref1 = _mm256_setzero_si256();
- sum_ref3 = _mm256_setzero_si256();
-
- for (int i = 0; i < N; i += 2) {
+ src_reg = yy_loadu2_128(src + src_stride, src);
+ sum_ref0 = _mm256_sad_epu8(yy_loadu2_128(ref0 + ref_stride, ref0), src_reg);
+ sum_ref1 = _mm256_sad_epu8(yy_loadu2_128(ref1 + ref_stride, ref1), src_reg);
+ sum_ref2 = _mm256_sad_epu8(yy_loadu2_128(ref2 + ref_stride, ref2), src_reg);
+ sum_ref3 = _mm256_sad_epu8(yy_loadu2_128(ref3 + ref_stride, ref3), src_reg);
+ src += 2 * src_stride;
+ ref0 += 2 * ref_stride;
+ ref1 += 2 * ref_stride;
+ ref2 += 2 * ref_stride;
+ ref3 += 2 * ref_stride;
+#if defined(__GNUC__) && !defined(__clang__)
+ __asm__(""
+ : "+r"(src), "+r"(ref0), "+r"(ref1), "+r"(ref2), "+r"(ref3),
+ "+x"(sum_ref0), "+x"(sum_ref1), "+x"(sum_ref2), "+x"(sum_ref3));
+#pragma GCC unroll 2
+#endif
+ for (int i = 2; i < N; i += 2) {
// load src and all refs
src_reg = yy_loadu2_128(src + src_stride, src);
ref0_reg = yy_loadu2_128(ref0 + ref_stride, ref0);
@@ -278,6 +327,11 @@ static AOM_FORCE_INLINE void aom_sad16xNx4d_avx2(int N, const uint8_t *src,
ref1 += 2 * ref_stride;
ref2 += 2 * ref_stride;
ref3 += 2 * ref_stride;
+#if defined(__GNUC__) && !defined(__clang__)
+ __asm__(""
+ : "+r"(src), "+r"(ref0), "+r"(ref1), "+r"(ref2), "+r"(ref3),
+ "+x"(sum_ref0), "+x"(sum_ref1), "+x"(sum_ref2), "+x"(sum_ref3));
+#endif
}
aggregate_and_store_sum(res, &sum_ref0, &sum_ref1, &sum_ref2, &sum_ref3);
diff --git a/aom_dsp/x86/subtract_avx2.c b/aom_dsp/x86/subtract_avx2.c
index b9e2a090c8..4dc96d1e4b 100644
--- a/aom_dsp/x86/subtract_avx2.c
+++ b/aom_dsp/x86/subtract_avx2.c
@@ -27,19 +27,88 @@ static inline void subtract32_avx2(int16_t *diff_ptr, const uint8_t *src_ptr,
_mm256_permute2x128_si256(diff0, diff1, 0x31));
}
+static inline void subtract_block_4xn_avx2(
+ int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
+ ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
+ int32_t j = 0;
+ for (; j + 3 < rows; j += 4) {
+ const __m128i s = _mm_setr_epi32(
+ *(const int32_t *)(src_ptr), *(const int32_t *)(src_ptr + src_stride),
+ *(const int32_t *)(src_ptr + src_stride * 2),
+ *(const int32_t *)(src_ptr + src_stride * 3));
+ const __m128i p =
+ _mm_setr_epi32(*(const int32_t *)(pred_ptr),
+ *(const int32_t *)(pred_ptr + pred_stride),
+ *(const int32_t *)(pred_ptr + pred_stride * 2),
+ *(const int32_t *)(pred_ptr + pred_stride * 3));
+ const __m256i d =
+ _mm256_sub_epi16(_mm256_cvtepu8_epi16(s), _mm256_cvtepu8_epi16(p));
+ const __m128i d_lo = _mm256_castsi256_si128(d);
+ const __m128i d_hi = _mm256_extracti128_si256(d, 1);
+ _mm_storel_epi64((__m128i *)(diff_ptr), d_lo);
+ _mm_storeh_pi((__m64 *)(diff_ptr + diff_stride), _mm_castsi128_ps(d_lo));
+ _mm_storel_epi64((__m128i *)(diff_ptr + diff_stride * 2), d_hi);
+ _mm_storeh_pi((__m64 *)(diff_ptr + diff_stride * 3),
+ _mm_castsi128_ps(d_hi));
+ src_ptr += src_stride * 4;
+ pred_ptr += pred_stride * 4;
+ diff_ptr += diff_stride * 4;
+ }
+ for (; j < rows; j += 2) {
+ const __m128i s =
+ _mm_setr_epi32(*(const int32_t *)(src_ptr),
+ *(const int32_t *)(src_ptr + src_stride), 0, 0);
+ const __m128i p =
+ _mm_setr_epi32(*(const int32_t *)(pred_ptr),
+ *(const int32_t *)(pred_ptr + pred_stride), 0, 0);
+ const __m128i d = _mm_sub_epi16(_mm_cvtepu8_epi16(s), _mm_cvtepu8_epi16(p));
+ _mm_storel_epi64((__m128i *)(diff_ptr), d);
+ _mm_storeh_pi((__m64 *)(diff_ptr + diff_stride), _mm_castsi128_ps(d));
+ src_ptr += src_stride * 2;
+ pred_ptr += pred_stride * 2;
+ diff_ptr += diff_stride * 2;
+ }
+}
+
+static inline void subtract_block_8xn_avx2(
+ int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
+ ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
+ for (int32_t j = 0; j < rows; j += 2) {
+ const __m128i s = _mm_unpacklo_epi64(
+ _mm_loadl_epi64((const __m128i *)(src_ptr)),
+ _mm_loadl_epi64((const __m128i *)(src_ptr + src_stride)));
+ const __m128i p = _mm_unpacklo_epi64(
+ _mm_loadl_epi64((const __m128i *)(pred_ptr)),
+ _mm_loadl_epi64((const __m128i *)(pred_ptr + pred_stride)));
+ const __m256i d =
+ _mm256_sub_epi16(_mm256_cvtepu8_epi16(s), _mm256_cvtepu8_epi16(p));
+ _mm_store_si128((__m128i *)(diff_ptr), _mm256_castsi256_si128(d));
+ _mm_store_si128((__m128i *)(diff_ptr + diff_stride),
+ _mm256_extracti128_si256(d, 1));
+ src_ptr += src_stride * 2;
+ pred_ptr += pred_stride * 2;
+ diff_ptr += diff_stride * 2;
+ }
+}
+
static inline void subtract_block_16xn_avx2(
int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
- for (int32_t j = 0; j < rows; ++j) {
- __m128i s = _mm_lddqu_si128((__m128i *)(src_ptr));
- __m128i p = _mm_lddqu_si128((__m128i *)(pred_ptr));
- __m256i s_0 = _mm256_cvtepu8_epi16(s);
- __m256i p_0 = _mm256_cvtepu8_epi16(p);
- const __m256i d_0 = _mm256_sub_epi16(s_0, p_0);
- _mm256_store_si256((__m256i *)(diff_ptr), d_0);
- src_ptr += src_stride;
- pred_ptr += pred_stride;
- diff_ptr += diff_stride;
+ for (int32_t j = 0; j < rows; j += 2) {
+ const __m128i s0 = _mm_lddqu_si128((const __m128i *)(src_ptr));
+ const __m128i p0 = _mm_lddqu_si128((const __m128i *)(pred_ptr));
+ const __m128i s1 = _mm_lddqu_si128((const __m128i *)(src_ptr + src_stride));
+ const __m128i p1 =
+ _mm_lddqu_si128((const __m128i *)(pred_ptr + pred_stride));
+ const __m256i d0 =
+ _mm256_sub_epi16(_mm256_cvtepu8_epi16(s0), _mm256_cvtepu8_epi16(p0));
+ const __m256i d1 =
+ _mm256_sub_epi16(_mm256_cvtepu8_epi16(s1), _mm256_cvtepu8_epi16(p1));
+ _mm256_store_si256((__m256i *)(diff_ptr), d0);
+ _mm256_store_si256((__m256i *)(diff_ptr + diff_stride), d1);
+ src_ptr += src_stride * 2;
+ pred_ptr += pred_stride * 2;
+ diff_ptr += diff_stride * 2;
}
}
@@ -85,6 +154,14 @@ void aom_subtract_block_avx2(int rows, int cols, int16_t *diff_ptr,
ptrdiff_t src_stride, const uint8_t *pred_ptr,
ptrdiff_t pred_stride) {
switch (cols) {
+ case 4:
+ subtract_block_4xn_avx2(rows, diff_ptr, diff_stride, src_ptr, src_stride,
+ pred_ptr, pred_stride);
+ break;
+ case 8:
+ subtract_block_8xn_avx2(rows, diff_ptr, diff_stride, src_ptr, src_stride,
+ pred_ptr, pred_stride);
+ break;
case 16:
subtract_block_16xn_avx2(rows, diff_ptr, diff_stride, src_ptr, src_stride,
pred_ptr, pred_stride);
diff --git a/av1/common/txb_common.c b/av1/common/txb_common.c
index ed3572684f..75dc36e223 100644
--- a/av1/common/txb_common.c
+++ b/av1/common/txb_common.c
@@ -337,7 +337,7 @@ static const int8_t av1_nz_map_ctx_offset_32x8[256] = {
21, 21, 21, 21, 21, 21, 21, 21, 21,
};
-const int8_t *av1_nz_map_ctx_offset[19] = {
+const int8_t *const av1_nz_map_ctx_offset[19] = {
av1_nz_map_ctx_offset_4x4, // TX_4x4
av1_nz_map_ctx_offset_8x8, // TX_8x8
av1_nz_map_ctx_offset_16x16, // TX_16x16
diff --git a/av1/common/txb_common.h b/av1/common/txb_common.h
index b5a11a7392..3325805058 100644
--- a/av1/common/txb_common.h
+++ b/av1/common/txb_common.h
@@ -17,7 +17,7 @@
extern const int16_t av1_eob_group_start[12];
extern const int16_t av1_eob_offset_bits[12];
-extern const int8_t *av1_nz_map_ctx_offset[TX_SIZES_ALL];
+extern const int8_t *const av1_nz_map_ctx_offset[TX_SIZES_ALL];
typedef struct txb_ctx {
int txb_skip_ctx;
@@ -77,7 +77,7 @@ static inline int get_br_ctx_2d(const uint8_t *const levels,
const int col = c >> bhl;
const int row = c - (col << bhl);
const int stride = (1 << bhl) + TX_PAD_HOR;
- const int pos = col * stride + row;
+ const int pos = c + (col << TX_PAD_HOR_LOG2);
int mag = AOMMIN(levels[pos + 1], MAX_BASE_BR_RANGE) +
AOMMIN(levels[pos + stride], MAX_BASE_BR_RANGE) +
AOMMIN(levels[pos + 1 + stride], MAX_BASE_BR_RANGE);
@@ -106,7 +106,7 @@ static AOM_FORCE_INLINE int get_br_ctx(const uint8_t *const levels,
const int col = c >> bhl;
const int row = c - (col << bhl);
const int stride = (1 << bhl) + TX_PAD_HOR;
- const int pos = col * stride + row;
+ const int pos = c + (col << TX_PAD_HOR_LOG2);
int mag = levels[pos + 1];
mag += levels[pos + stride];
switch (tx_class) {
@@ -150,23 +150,24 @@ static const uint8_t clip_max3[256] = {
static AOM_FORCE_INLINE int get_nz_mag(const uint8_t *const levels,
const int bhl, const TX_CLASS tx_class) {
int mag;
+ const ptrdiff_t stride = (1 << bhl) + TX_PAD_HOR;
// Note: AOMMIN(level, 3) is useless for decoder since level < 3.
- mag = clip_max3[levels[(1 << bhl) + TX_PAD_HOR]]; // { 0, 1 }
- mag += clip_max3[levels[1]]; // { 1, 0 }
+ mag = clip_max3[levels[stride]]; // { 0, 1 }
+ mag += clip_max3[levels[1]]; // { 1, 0 }
if (tx_class == TX_CLASS_2D) {
- mag += clip_max3[levels[(1 << bhl) + TX_PAD_HOR + 1]]; // { 1, 1 }
- mag += clip_max3[levels[(2 << bhl) + (2 << TX_PAD_HOR_LOG2)]]; // { 0, 2 }
- mag += clip_max3[levels[2]]; // { 2, 0 }
+ mag += clip_max3[levels[stride + 1]]; // { 1, 1 }
+ mag += clip_max3[levels[stride * 2]]; // { 0, 2 }
+ mag += clip_max3[levels[2]]; // { 2, 0 }
} else if (tx_class == TX_CLASS_VERT) {
mag += clip_max3[levels[2]]; // { 2, 0 }
mag += clip_max3[levels[3]]; // { 3, 0 }
mag += clip_max3[levels[4]]; // { 4, 0 }
} else {
- mag += clip_max3[levels[(2 << bhl) + (2 << TX_PAD_HOR_LOG2)]]; // { 0, 2 }
- mag += clip_max3[levels[(3 << bhl) + (3 << TX_PAD_HOR_LOG2)]]; // { 0, 3 }
- mag += clip_max3[levels[(4 << bhl) + (4 << TX_PAD_HOR_LOG2)]]; // { 0, 4 }
+ mag += clip_max3[levels[stride * 2]]; // { 0, 2 }
+ mag += clip_max3[levels[stride * 3]]; // { 0, 3 }
+ mag += clip_max3[levels[stride * 4]]; // { 0, 4 }
}
return mag;
diff --git a/av1/encoder/compound_type.c b/av1/encoder/compound_type.c
index 569cfa95c4..eb6ee9eed5 100644
--- a/av1/encoder/compound_type.c
+++ b/av1/encoder/compound_type.c
@@ -1440,14 +1440,16 @@ int av1_compound_type_rd(const AV1_COMP *const cpi, MACROBLOCK *x,
} else {
tmp_rate_mv = *rate_mv;
if (have_newmv_in_inter_mode(this_mode)) {
- InterPredParams inter_pred_params;
- av1_dist_wtd_comp_weight_assign(
- &cpi->common, mbmi, &inter_pred_params.conv_params.fwd_offset,
- &inter_pred_params.conv_params.bck_offset,
- &inter_pred_params.conv_params.use_dist_wtd_comp_avg, 1);
- int mask_value = inter_pred_params.conv_params.fwd_offset * 4;
- memset(xd->seg_mask, mask_value,
- sizeof(xd->seg_mask[0]) * 2 * MAX_SB_SQUARE);
+ if (cur_type == COMPOUND_DISTWTD) {
+ InterPredParams inter_pred_params;
+ av1_dist_wtd_comp_weight_assign(
+ &cpi->common, mbmi, &inter_pred_params.conv_params.fwd_offset,
+ &inter_pred_params.conv_params.bck_offset,
+ &inter_pred_params.conv_params.use_dist_wtd_comp_avg, 1);
+ int mask_value = inter_pred_params.conv_params.fwd_offset * 4;
+ memset(xd->seg_mask, mask_value,
+ sizeof(xd->seg_mask[0]) * 2 * MAX_SB_SQUARE);
+ }
tmp_rate_mv = av1_interinter_compound_motion_search(cpi, x, cur_mv,
bsize, this_mode);
}
diff --git a/av1/encoder/encodetxb.c b/av1/encoder/encodetxb.c
index 50cf0e4f6b..0c9c1a5cc4 100644
--- a/av1/encoder/encodetxb.c
+++ b/av1/encoder/encodetxb.c
@@ -484,20 +484,26 @@ void av1_write_intra_coeffs_mb(const AV1_COMMON *const cm, MACROBLOCK *x,
uint8_t av1_get_txb_entropy_context(const tran_low_t *qcoeff,
const SCAN_ORDER *scan_order, int eob) {
- const int16_t *const scan = scan_order->scan;
- int cul_level = 0;
- int c;
-
if (eob == 0) return 0;
- for (c = 0; c < eob; ++c) {
- const int32_t v = qcoeff[scan[c]];
- if (!v) continue;
- cul_level += abs(v);
- if (cul_level > COEFF_CONTEXT_MASK) break;
+ const int32_t dc_val = qcoeff[0];
+ int cul_level = abs(dc_val);
+ if (cul_level < COEFF_CONTEXT_MASK && eob > 1) {
+ const int16_t *const __restrict scan = scan_order->scan;
+ int c = 1;
+ for (; c + 3 < eob; c += 4) {
+ cul_level += abs(qcoeff[scan[c]]) + abs(qcoeff[scan[c + 1]]) +
+ abs(qcoeff[scan[c + 2]]) + abs(qcoeff[scan[c + 3]]);
+ if (cul_level >= COEFF_CONTEXT_MASK) break;
+ }
+ if (cul_level < COEFF_CONTEXT_MASK) {
+ for (; c < eob; ++c) {
+ cul_level += abs(qcoeff[scan[c]]);
+ }
+ }
}
cul_level = AOMMIN(COEFF_CONTEXT_MASK, cul_level);
- set_dc_sign(&cul_level, qcoeff[0]);
+ set_dc_sign(&cul_level, dc_val);
return (uint8_t)cul_level;
}
diff --git a/av1/encoder/mcomp.c b/av1/encoder/mcomp.c
index aa622506a5..583a50f35f 100644
--- a/av1/encoder/mcomp.c
+++ b/av1/encoder/mcomp.c
@@ -356,21 +356,24 @@ static inline int mv_err_cost_(const MV *mv,
static inline int mvsad_err_cost(const FULLPEL_MV *mv, const FULLPEL_MV *ref_mv,
const int *mvjcost, const int *const mvcost[2],
int sad_per_bit, MV_COST_TYPE mv_cost_type) {
- const MV diff = { GET_MV_SUBPEL(mv->row - ref_mv->row),
- GET_MV_SUBPEL(mv->col - ref_mv->col) };
-
switch (mv_cost_type) {
- case MV_COST_ENTROPY:
+ case MV_COST_ENTROPY: {
+ const MV diff = { GET_MV_SUBPEL(mv->row - ref_mv->row),
+ GET_MV_SUBPEL(mv->col - ref_mv->col) };
return ROUND_POWER_OF_TWO(
(unsigned)mv_cost(&diff, mvjcost, CONVERT_TO_CONST_MVCOST(mvcost)) *
sad_per_bit,
AV1_PROB_COST_SHIFT);
+ }
case MV_COST_L1_LOWRES:
- return (SAD_LAMBDA_LOWRES * (abs(diff.row) + abs(diff.col))) >> 3;
+ return SAD_LAMBDA_LOWRES *
+ (abs(mv->row - ref_mv->row) + abs(mv->col - ref_mv->col));
case MV_COST_L1_MIDRES:
- return (SAD_LAMBDA_MIDRES * (abs(diff.row) + abs(diff.col))) >> 3;
+ return SAD_LAMBDA_MIDRES *
+ (abs(mv->row - ref_mv->row) + abs(mv->col - ref_mv->col));
case MV_COST_L1_HDRES:
- return (SAD_LAMBDA_HDRES * (abs(diff.row) + abs(diff.col))) >> 3;
+ return SAD_LAMBDA_HDRES *
+ (abs(mv->row - ref_mv->row) + abs(mv->col - ref_mv->col));
case MV_COST_NONE: return 0;
default: assert(0 && "Invalid rd_cost_type"); return 0;
}
@@ -1308,6 +1311,9 @@ static inline void update_best_site(unsigned int sad, const FULLPEL_MV *best_mv,
}
}
+#if defined(__GNUC__) && !defined(__clang__)
+__attribute__((optimize("no-tree-slp-vectorize")))
+#endif
static int diamond_search_sad(FULLPEL_MV start_mv, unsigned int start_mv_sad,
const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
const int search_step, int *num00,
@@ -1729,6 +1735,11 @@ int av1_refining_search_8p_c(const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
for (int i = 0; i < SEARCH_RANGE_8P; ++i) {
int best_site = -1;
+ const uint8_t *const best_buf = get_buf_from_fullmv(ref, best_mv);
+ const int in_range = (best_mv->row > mv_limits->row_min) &
+ (best_mv->row < mv_limits->row_max) &
+ (best_mv->col > mv_limits->col_min) &
+ (best_mv->col < mv_limits->col_max);
for (int j = 0; j < 8; ++j) {
grid_coord = grid_center + neighbors[j].coord_offset;
@@ -1739,10 +1750,12 @@ int av1_refining_search_8p_c(const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
best_mv->col + neighbors[j].coord.col };
do_refine_search_grid[grid_coord] = 1;
- if (av1_is_fullmv_in_range(mv_limits, mv)) {
- unsigned int sad;
- sad = get_mvpred_compound_sad(
- ms_params, src, get_buf_from_fullmv(ref, &mv), ref_stride);
+ if (in_range || av1_is_fullmv_in_range(mv_limits, mv)) {
+ unsigned int sad = get_mvpred_compound_sad(
+ ms_params, src,
+ best_buf + neighbors[j].coord.row * ref_stride +
+ neighbors[j].coord.col,
+ ref_stride);
if (sad < best_sad) {
sad += mvsad_err_cost_(&mv, mv_cost_params);
@@ -3540,6 +3553,7 @@ unsigned int av1_refine_warped_mv(MACROBLOCKD *xd, const AV1_COMMON *const cm,
const int *pts_inref0, int total_samples,
WARP_SEARCH_METHOD search_method,
int num_iterations) {
+ if (num_iterations <= 0) return 0;
MB_MODE_INFO *mbmi = xd->mi[0];
const MV *neighbors = warp_search_info[search_method].neighbors;
@@ -3558,6 +3572,7 @@ unsigned int av1_refine_warped_mv(MACROBLOCKD *xd, const AV1_COMMON *const cm,
// Calculate the center position's error
assert(av1_is_subpelmv_in_range(mv_limits, *best_mv));
bestmse = compute_motion_cost(xd, cm, ms_params, bsize, best_mv);
+ unsigned int dst_y_valid = 1;
// MV search
int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE];
@@ -3597,6 +3612,9 @@ unsigned int av1_refine_warped_mv(MACROBLOCKD *xd, const AV1_COMMON *const cm,
best_wm_params = mbmi->wm_params;
best_num_proj_ref = mbmi->num_proj_ref;
bestmse = thismse;
+ dst_y_valid = 1;
+ } else {
+ dst_y_valid = 0;
}
}
}
@@ -3613,7 +3631,7 @@ unsigned int av1_refine_warped_mv(MACROBLOCKD *xd, const AV1_COMMON *const cm,
mbmi->wm_params = best_wm_params;
mbmi->num_proj_ref = best_num_proj_ref;
- return bestmse;
+ return dst_y_valid;
}
#endif // !CONFIG_REALTIME_ONLY
diff --git a/av1/encoder/motion_search_facade.c b/av1/encoder/motion_search_facade.c
index d6ff2c05a5..f09c9112d9 100644
--- a/av1/encoder/motion_search_facade.c
+++ b/av1/encoder/motion_search_facade.c
@@ -560,7 +560,7 @@ int av1_joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x,
const int_mv init_mv[2] = { cur_mv[0], cur_mv[1] };
const int refs[2] = { mbmi->ref_frame[0], mbmi->ref_frame[1] };
const MvCosts *mv_costs = x->mv_costs;
- int_mv ref_mv[2];
+ const int_mv ref_mv[2] = { av1_get_ref_mv(x, 0), av1_get_ref_mv(x, 1) };
int ite, ref;
// Get the prediction block from the 'other' reference frame.
@@ -606,8 +606,8 @@ int av1_joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x,
}
}
}
+ const FULLPEL_MV start_fullmv = get_fullmv_from_mv(&cur_mv[id].as_mv);
for (ref = 0; ref < 2; ++ref) {
- ref_mv[ref] = av1_get_ref_mv(x, ref);
// Swap out the reference frame for a version that's been scaled to
// match the resolution of the current frame, allowing the existing
// motion search code to be used without additional modifications.
@@ -654,7 +654,6 @@ int av1_joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x,
const search_site_config *src_search_sites =
av1_get_search_site_config(cpi, x, search_method);
// Use the mv result from the single mode as mv predictor.
- const FULLPEL_MV start_fullmv = get_fullmv_from_mv(&cur_mv[id].as_mv);
av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize,
&ref_mv[id].as_mv, start_fullmv,
src_search_sites, search_method,
@@ -759,8 +758,7 @@ int av1_joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x,
*rate_mv = 0;
for (ref = 0; ref < 2; ++ref) {
- const int_mv curr_ref_mv = av1_get_ref_mv(x, ref);
- *rate_mv += av1_mv_bit_cost(&cur_mv[ref].as_mv, &curr_ref_mv.as_mv,
+ *rate_mv += av1_mv_bit_cost(&cur_mv[ref].as_mv, &ref_mv[ref].as_mv,
mv_costs->nmv_joint_cost,
mv_costs->mv_cost_stack, MV_COST_WEIGHT);
}
diff --git a/av1/encoder/rd.c b/av1/encoder/rd.c
index d379858a3b..cb5dfd4813 100644
--- a/av1/encoder/rd.c
+++ b/av1/encoder/rd.c
@@ -1460,23 +1460,32 @@ void av1_set_rd_speed_thresholds(AV1_COMP *cpi) {
rd->thresh_mult[THR_D45_PRED] = 2500;
}
+#if HAVE_AVX2 && (defined(__GNUC__) || defined(__clang__))
+__attribute__((target("avx2")))
+#endif
static inline void update_thr_fact(int (*factor_buf)[MAX_MODES],
THR_MODES best_mode_index,
THR_MODES mode_start, THR_MODES mode_end,
BLOCK_SIZE min_size, BLOCK_SIZE max_size,
int max_rd_thresh_factor) {
- for (THR_MODES mode = mode_start; mode < mode_end; ++mode) {
- for (BLOCK_SIZE bs = min_size; bs <= max_size; ++bs) {
- int *const fact = &factor_buf[bs][mode];
- if (mode == best_mode_index) {
- *fact -= (*fact >> RD_THRESH_LOG_DEC_FACTOR);
- } else {
- *fact = AOMMIN(*fact + RD_THRESH_INC, max_rd_thresh_factor);
- }
+ if (mode_start >= mode_end) return;
+ const int best_in_range =
+ (best_mode_index >= mode_start && best_mode_index < mode_end);
+ for (BLOCK_SIZE bs = min_size; bs <= max_size; ++bs) {
+ int *__restrict const row = factor_buf[bs];
+ const int best_val = best_in_range ? row[best_mode_index] : 0;
+ for (THR_MODES mode = mode_start; mode < mode_end; ++mode) {
+ row[mode] = AOMMIN(row[mode] + RD_THRESH_INC, max_rd_thresh_factor);
+ }
+ if (best_in_range) {
+ row[best_mode_index] = best_val - (best_val >> RD_THRESH_LOG_DEC_FACTOR);
}
}
}
+#if HAVE_AVX2 && (defined(__GNUC__) || defined(__clang__))
+__attribute__((target("avx2")))
+#endif
void av1_update_rd_thresh_fact(
const AV1_COMMON *const cm, int (*factor_buf)[MAX_MODES],
int use_adaptive_rd_thresh, BLOCK_SIZE bsize, THR_MODES best_mode_index,
@@ -1497,10 +1506,16 @@ void av1_update_rd_thresh_fact(
max_size = AOMMIN(bsize + 2, (int)cm->seq_params->sb_size);
}
- update_thr_fact(factor_buf, best_mode_index, inter_mode_start, inter_mode_end,
- min_size, max_size, max_rd_thresh_factor);
- update_thr_fact(factor_buf, best_mode_index, intra_mode_start, intra_mode_end,
- min_size, max_size, max_rd_thresh_factor);
+ if (inter_mode_start <= inter_mode_end &&
+ inter_mode_end == intra_mode_start) {
+ update_thr_fact(factor_buf, best_mode_index, inter_mode_start,
+ intra_mode_end, min_size, max_size, max_rd_thresh_factor);
+ } else {
+ update_thr_fact(factor_buf, best_mode_index, inter_mode_start,
+ inter_mode_end, min_size, max_size, max_rd_thresh_factor);
+ update_thr_fact(factor_buf, best_mode_index, intra_mode_start,
+ intra_mode_end, min_size, max_size, max_rd_thresh_factor);
+ }
}
int av1_get_intra_cost_penalty(int qindex, int qdelta,
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index 28649da880..5e0afbc8ef 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -1817,6 +1817,7 @@ static int64_t motion_mode_rd(
mbmi->mv[0].as_mv.row, mbmi->mv[0].as_mv.col,
&mbmi->wm_params, mi_row, mi_col)) {
assert(!is_comp_pred);
+ unsigned int dst_y_valid = 0;
if (have_newmv_in_inter_mode(this_mode)) {
// Refine MV for NEWMV mode
const int_mv mv0 = mbmi->mv[0];
@@ -1829,9 +1830,10 @@ static int64_t motion_mode_rd(
&ref_mv.as_mv, NULL);
// Refine MV in a small range.
- av1_refine_warped_mv(xd, cm, &ms_params, bsize, pts0, pts_inref0,
- total_samples, cpi->sf.mv_sf.warp_search_method,
- cpi->sf.mv_sf.warp_search_iters);
+ dst_y_valid = av1_refine_warped_mv(xd, cm, &ms_params, bsize, pts0,
+ pts_inref0, total_samples,
+ cpi->sf.mv_sf.warp_search_method,
+ cpi->sf.mv_sf.warp_search_iters);
if (mv0.as_int != mbmi->mv[0].as_int) {
// Keep the refined MV and WM parameters.
@@ -1848,7 +1850,8 @@ static int64_t motion_mode_rd(
}
// Build the warped predictor
- av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, 0,
+ av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
+ dst_y_valid ? AOM_PLANE_U : AOM_PLANE_Y,
av1_num_planes(cm) - 1);
} else {
continue;
diff --git a/av1/encoder/tx_search.c b/av1/encoder/tx_search.c
index 6281191572..b804ce0a29 100644
--- a/av1/encoder/tx_search.c
+++ b/av1/encoder/tx_search.c
@@ -23,6 +23,9 @@
#include "av1/encoder/tx_prune_model_weights.h"
#include "av1/encoder/tx_search.h"
#include "av1/encoder/txb_rdopt.h"
+#if HAVE_AVX2 && (defined(__x86_64__) || defined(_M_X64))
+#include <immintrin.h>
+#endif
#define PROB_THRESH_OFFSET_TX_TYPE 100
@@ -1454,41 +1457,186 @@ static inline float get_adaptive_thresholds(
return prune_2D_adaptive_thresholds[tx_size][pruning_aggressiveness];
}
+#if HAVE_AVX2 && defined(__x86_64__) && \
+ (defined(__GNUC__) || defined(__clang__))
+__attribute__((target("avx2")))
+#endif
static inline void get_energy_distribution_finer(const int16_t *diff,
int stride, int bw, int bh,
float *hordist,
float *verdist) {
- // First compute downscaled block energy values (esq); downscale factors
- // are defined by w_shift and h_shift.
- unsigned int esq[256];
const int w_shift = bw <= 8 ? 0 : 1;
const int h_shift = bh <= 8 ? 0 : 1;
const int esq_w = bw >> w_shift;
const int esq_h = bh >> h_shift;
- const int esq_sz = esq_w * esq_h;
+ uint32_t col_sum[16] = { 0 };
+ uint32_t row_sum[16] = { 0 };
+ uint64_t total = 0;
int i, j;
- memset(esq, 0, esq_sz * sizeof(esq[0]));
- if (w_shift) {
- for (i = 0; i < bh; i++) {
- unsigned int *cur_esq_row = esq + (i >> h_shift) * esq_w;
- const int16_t *cur_diff_row = diff + i * stride;
- for (j = 0; j < bw; j += 2) {
- cur_esq_row[j >> 1] += (cur_diff_row[j] * cur_diff_row[j] +
- cur_diff_row[j + 1] * cur_diff_row[j + 1]);
+
+#if HAVE_AVX2 && defined(__x86_64__) && \
+ (defined(__GNUC__) || defined(__clang__))
+ if (bw == 4) {
+ __m128i v_col = _mm_setzero_si128();
+ if (h_shift == 0) {
+ for (i = 0; i < esq_h; i++) {
+ const __m128i d = _mm_cvtepi16_epi32(
+ _mm_loadl_epi64((const __m128i *)(diff + i * stride)));
+ const __m128i sq = _mm_mullo_epi32(d, d);
+ v_col = _mm_add_epi32(v_col, sq);
+ const __m128i s1 = _mm_hadd_epi32(sq, sq);
+ const __m128i s2 = _mm_hadd_epi32(s1, s1);
+ row_sum[i] = (uint32_t)_mm_cvtsi128_si32(s2);
+ }
+ } else {
+ for (i = 0; i < esq_h; i++) {
+ const __m128i d0 =
+ _mm_loadl_epi64((const __m128i *)(diff + (2 * i) * stride));
+ const __m128i d1 =
+ _mm_loadl_epi64((const __m128i *)(diff + (2 * i + 1) * stride));
+ const __m128i d01 = _mm_unpacklo_epi16(d0, d1);
+ const __m128i sq = _mm_madd_epi16(d01, d01);
+ v_col = _mm_add_epi32(v_col, sq);
+ const __m128i s1 = _mm_hadd_epi32(sq, sq);
+ const __m128i s2 = _mm_hadd_epi32(s1, s1);
+ row_sum[i] = (uint32_t)_mm_cvtsi128_si32(s2);
+ }
+ }
+ _mm_storeu_si128((__m128i *)col_sum, v_col);
+ const __m128i t1 = _mm_hadd_epi32(v_col, v_col);
+ const __m128i t2 = _mm_hadd_epi32(t1, t1);
+ total = (uint32_t)_mm_cvtsi128_si32(t2);
+ } else if (bw == 8) {
+ __m256i v_col = _mm256_setzero_si256();
+ if (h_shift == 0) {
+ for (i = 0; i < esq_h; i++) {
+ const __m256i d = _mm256_cvtepi16_epi32(
+ _mm_loadu_si128((const __m128i *)(diff + i * stride)));
+ const __m256i sq = _mm256_mullo_epi32(d, d);
+ v_col = _mm256_add_epi32(v_col, sq);
+ const __m128i sq128 = _mm_add_epi32(_mm256_castsi256_si128(sq),
+ _mm256_extracti128_si256(sq, 1));
+ const __m128i s1 = _mm_hadd_epi32(sq128, sq128);
+ const __m128i s2 = _mm_hadd_epi32(s1, s1);
+ row_sum[i] = (uint32_t)_mm_cvtsi128_si32(s2);
+ }
+ } else {
+ for (i = 0; i < esq_h; i++) {
+ const __m128i d0 =
+ _mm_loadu_si128((const __m128i *)(diff + (2 * i) * stride));
+ const __m128i d1 =
+ _mm_loadu_si128((const __m128i *)(diff + (2 * i + 1) * stride));
+ const __m256i d0_256 = _mm256_cvtepi16_epi32(d0);
+ const __m256i d1_256 = _mm256_cvtepi16_epi32(d1);
+ const __m256i sq = _mm256_add_epi32(_mm256_mullo_epi32(d0_256, d0_256),
+ _mm256_mullo_epi32(d1_256, d1_256));
+ v_col = _mm256_add_epi32(v_col, sq);
+ const __m128i sq128 = _mm_add_epi32(_mm256_castsi256_si128(sq),
+ _mm256_extracti128_si256(sq, 1));
+ const __m128i s1 = _mm_hadd_epi32(sq128, sq128);
+ const __m128i s2 = _mm_hadd_epi32(s1, s1);
+ row_sum[i] = (uint32_t)_mm_cvtsi128_si32(s2);
+ }
+ }
+ _mm256_storeu_si256((__m256i *)col_sum, v_col);
+ const __m128i c128 = _mm_add_epi32(_mm256_castsi256_si128(v_col),
+ _mm256_extracti128_si256(v_col, 1));
+ const __m128i t1 = _mm_hadd_epi32(c128, c128);
+ const __m128i t2 = _mm_hadd_epi32(t1, t1);
+ total = (uint32_t)_mm_cvtsi128_si32(t2);
+ } else if (bw == 16) {
+ __m256i v_col = _mm256_setzero_si256();
+ if (h_shift == 0) {
+ for (i = 0; i < esq_h; i++) {
+ const __m256i d =
+ _mm256_loadu_si256((const __m256i *)(diff + i * stride));
+ const __m256i sq = _mm256_madd_epi16(d, d);
+ v_col = _mm256_add_epi32(v_col, sq);
+ const __m128i sq128 = _mm_add_epi32(_mm256_castsi256_si128(sq),
+ _mm256_extracti128_si256(sq, 1));
+ const __m128i s1 = _mm_hadd_epi32(sq128, sq128);
+ const __m128i s2 = _mm_hadd_epi32(s1, s1);
+ row_sum[i] = (uint32_t)_mm_cvtsi128_si32(s2);
+ }
+ } else {
+ for (i = 0; i < esq_h; i++) {
+ const __m256i d0 =
+ _mm256_loadu_si256((const __m256i *)(diff + (2 * i) * stride));
+ const __m256i d1 =
+ _mm256_loadu_si256((const __m256i *)(diff + (2 * i + 1) * stride));
+ const __m256i sq = _mm256_add_epi32(_mm256_madd_epi16(d0, d0),
+ _mm256_madd_epi16(d1, d1));
+ v_col = _mm256_add_epi32(v_col, sq);
+ const __m128i sq128 = _mm_add_epi32(_mm256_castsi256_si128(sq),
+ _mm256_extracti128_si256(sq, 1));
+ const __m128i s1 = _mm_hadd_epi32(sq128, sq128);
+ const __m128i s2 = _mm_hadd_epi32(s1, s1);
+ row_sum[i] = (uint32_t)_mm_cvtsi128_si32(s2);
}
}
+ _mm256_storeu_si256((__m256i *)col_sum, v_col);
+ const __m128i c128 = _mm_add_epi32(_mm256_castsi256_si128(v_col),
+ _mm256_extracti128_si256(v_col, 1));
+ const __m128i t1 = _mm_hadd_epi32(c128, c128);
+ const __m128i t2 = _mm_hadd_epi32(t1, t1);
+ total = (uint32_t)_mm_cvtsi128_si32(t2);
} else {
- for (i = 0; i < bh; i++) {
- unsigned int *cur_esq_row = esq + (i >> h_shift) * esq_w;
- const int16_t *cur_diff_row = diff + i * stride;
+ __m256i v_col_lo = _mm256_setzero_si256();
+ __m256i v_col_hi = _mm256_setzero_si256();
+ for (i = 0; i < esq_h; i++) {
+ const int16_t *r0 = diff + (2 * i) * stride;
+ const int16_t *r1 = diff + (2 * i + 1) * stride;
+ const __m256i d0_lo = _mm256_loadu_si256((const __m256i *)r0);
+ const __m256i d0_hi = _mm256_loadu_si256((const __m256i *)(r0 + 16));
+ const __m256i d1_lo = _mm256_loadu_si256((const __m256i *)r1);
+ const __m256i d1_hi = _mm256_loadu_si256((const __m256i *)(r1 + 16));
+ const __m256i sq_lo = _mm256_add_epi32(_mm256_madd_epi16(d0_lo, d0_lo),
+ _mm256_madd_epi16(d1_lo, d1_lo));
+ const __m256i sq_hi = _mm256_add_epi32(_mm256_madd_epi16(d0_hi, d0_hi),
+ _mm256_madd_epi16(d1_hi, d1_hi));
+ v_col_lo = _mm256_add_epi32(v_col_lo, sq_lo);
+ v_col_hi = _mm256_add_epi32(v_col_hi, sq_hi);
+ const __m256i sq_sum = _mm256_add_epi32(sq_lo, sq_hi);
+ const __m128i sq128 = _mm_add_epi32(_mm256_castsi256_si128(sq_sum),
+ _mm256_extracti128_si256(sq_sum, 1));
+ const __m128i s1 = _mm_hadd_epi32(sq128, sq128);
+ const __m128i s2 = _mm_hadd_epi32(s1, s1);
+ row_sum[i] = (uint32_t)_mm_cvtsi128_si32(s2);
+ }
+ _mm256_storeu_si256((__m256i *)col_sum, v_col_lo);
+ _mm256_storeu_si256((__m256i *)(col_sum + 8), v_col_hi);
+ const __m256i v_col_all = _mm256_add_epi32(v_col_lo, v_col_hi);
+ const __m128i c128 = _mm_add_epi32(_mm256_castsi256_si128(v_col_all),
+ _mm256_extracti128_si256(v_col_all, 1));
+ const __m128i t1 = _mm_hadd_epi32(c128, c128);
+ const __m128i t2 = _mm_hadd_epi32(t1, t1);
+ total = (uint32_t)_mm_cvtsi128_si32(t2);
+ }
+#else
+ memset(col_sum, 0, esq_w * sizeof(col_sum[0]));
+ memset(row_sum, 0, esq_h * sizeof(row_sum[0]));
+ for (i = 0; i < bh; i++) {
+ const int16_t *cur_diff_row = diff + i * stride;
+ uint32_t r_sum = 0;
+ if (w_shift) {
+ for (j = 0; j < bw; j += 2) {
+ const uint32_t sq =
+ (uint32_t)(cur_diff_row[j] * cur_diff_row[j] +
+ cur_diff_row[j + 1] * cur_diff_row[j + 1]);
+ col_sum[j >> 1] += sq;
+ r_sum += sq;
+ }
+ } else {
for (j = 0; j < bw; j++) {
- cur_esq_row[j] += cur_diff_row[j] * cur_diff_row[j];
+ const uint32_t sq = (uint32_t)(cur_diff_row[j] * cur_diff_row[j]);
+ col_sum[j] += sq;
+ r_sum += sq;
}
}
+ row_sum[i >> h_shift] += r_sum;
+ total += r_sum;
}
-
- uint64_t total = 0;
- for (i = 0; i < esq_sz; i++) total += esq[i];
+#endif
// Output hordist and verdist arrays are normalized 1D projections of esq
if (total == 0) {
@@ -1500,22 +1648,8 @@ static inline void get_energy_distribution_finer(const int16_t *diff,
}
const float e_recip = 1.0f / (float)total;
- memset(hordist, 0, (esq_w - 1) * sizeof(hordist[0]));
- memset(verdist, 0, (esq_h - 1) * sizeof(verdist[0]));
- const unsigned int *cur_esq_row;
- for (i = 0; i < esq_h - 1; i++) {
- cur_esq_row = esq + i * esq_w;
- for (j = 0; j < esq_w - 1; j++) {
- hordist[j] += (float)cur_esq_row[j];
- verdist[i] += (float)cur_esq_row[j];
- }
- verdist[i] += (float)cur_esq_row[j];
- }
- cur_esq_row = esq + i * esq_w;
- for (j = 0; j < esq_w - 1; j++) hordist[j] += (float)cur_esq_row[j];
-
- for (j = 0; j < esq_w - 1; j++) hordist[j] *= e_recip;
- for (i = 0; i < esq_h - 1; i++) verdist[i] *= e_recip;
+ for (j = 0; j < esq_w - 1; j++) hordist[j] = (float)col_sum[j] * e_recip;
+ for (i = 0; i < esq_h - 1; i++) verdist[i] = (float)row_sum[i] * e_recip;
}
static inline bool check_bit_mask(uint16_t mask, int val) {
@@ -1530,6 +1664,10 @@ static inline void unset_bit_mask(uint16_t *mask, int val) {
*mask &= ~(1 << val);
}
+#if HAVE_AVX2 && defined(__x86_64__) && \
+ (defined(__GNUC__) || defined(__clang__))
+__attribute__((target("avx2")))
+#endif
static void prune_tx_2D(MACROBLOCK *x, BLOCK_SIZE bsize, TX_SIZE tx_size,
int blk_row, int blk_col, TxSetType tx_set_type,
TX_TYPE_PRUNE_MODE prune_2d_txfm_mode, int *txk_map,
@@ -1895,9 +2033,13 @@ static inline uint16_t get_tx_mask(
if ((prune >> max_idx) & 0x01) prune &= ~(1 << max_idx);
allowed_tx_mask &= (~prune);
}
- for (i = 0; i < TX_TYPES; i++) {
- if (allowed_tx_mask & (1 << i)) num_allowed++;
+#if defined(__GNUC__) || defined(__clang__)
+ num_allowed = __builtin_popcount(allowed_tx_mask);
+#else
+ for (uint16_t mask = allowed_tx_mask; mask != 0; mask &= mask - 1) {
+ num_allowed++;
}
+#endif
assert(num_allowed > 0);
if (num_allowed > 2 && cpi->sf.tx_sf.tx_type_search.prune_tx_type_est_rd) {
@@ -2198,13 +2340,17 @@ static void search_tx_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane,
: AV1_XFORM_QUANT_FP,
cpi->oxcf.q_cfg.quant_b_adapt, &quant_param);
+ const int use_qmatrix =
+ av1_use_qmatrix(&cm->quant_params, xd, mbmi->segment_id);
+ uint16_t rem_tx_mask = allowed_tx_mask;
// Iterate through all transform type candidates.
- for (int idx = 0; idx < TX_TYPES; ++idx) {
+ for (int idx = 0; idx < TX_TYPES && rem_tx_mask != 0; ++idx) {
const TX_TYPE tx_type = (TX_TYPE)txk_map[idx];
- if (tx_type == TX_TYPE_INVALID || !check_bit_mask(allowed_tx_mask, tx_type))
+ if (tx_type == TX_TYPE_INVALID || !check_bit_mask(rem_tx_mask, tx_type))
continue;
+ rem_tx_mask &= ~(uint16_t)(1 << tx_type);
txfm_param.tx_type = tx_type;
- if (av1_use_qmatrix(&cm->quant_params, xd, mbmi->segment_id)) {
+ if (use_qmatrix) {
av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, tx_type,
&quant_param);
}
diff --git a/av1/encoder/txb_rdopt.c b/av1/encoder/txb_rdopt.c
index a4df665832..f032171651 100644
--- a/av1/encoder/txb_rdopt.c
+++ b/av1/encoder/txb_rdopt.c
@@ -86,13 +86,12 @@ static inline void update_coeff_general(
}
}
-static AOM_FORCE_INLINE void update_coeff_simple(
- int *accu_rate, int si, int eob, TX_SIZE tx_size, TX_CLASS tx_class,
- int bhl, int64_t rdmult, int shift, const int16_t *dequant,
- const int16_t *scan, const LV_MAP_COEFF_COST *txb_costs,
- const tran_low_t *tcoeff, tran_low_t *qcoeff, tran_low_t *dqcoeff,
- uint8_t *levels, int sharpness, const qm_val_t *iqmatrix,
- const qm_val_t *qmatrix) {
+static AOM_FORCE_INLINE int update_coeff_simple(
+ int si, int eob, TX_SIZE tx_size, TX_CLASS tx_class, int bhl,
+ int64_t rdmult, int shift, const int16_t *dequant, const int16_t *scan,
+ const LV_MAP_COEFF_COST *txb_costs, const tran_low_t *tcoeff,
+ tran_low_t *qcoeff, tran_low_t *dqcoeff, uint8_t *levels, int sharpness,
+ const qm_val_t *iqmatrix, const qm_val_t *qmatrix) {
(void)eob;
// this simple version assumes the coeff's scan_idx is not DC (scan_idx != 0)
// and not the last (scan_idx != eob - 1)
@@ -103,7 +102,7 @@ static AOM_FORCE_INLINE void update_coeff_simple(
const int coeff_ctx =
get_lower_levels_ctx(levels, ci, bhl, tx_size, tx_class);
if (qc == 0) {
- *accu_rate += txb_costs->base_cost[coeff_ctx][0];
+ return txb_costs->base_cost[coeff_ctx][0];
} else {
const tran_low_t abs_qc = abs(qc);
const tran_low_t abs_tqc = abs(tcoeff[ci]);
@@ -112,8 +111,7 @@ static AOM_FORCE_INLINE void update_coeff_simple(
const int *base_cost = txb_costs->base_cost[coeff_ctx];
const int rate = base_cost[1] + av1_cost_literal(1);
if (abs_dqc < abs_tqc) {
- *accu_rate += rate;
- return;
+ return rate;
}
const int allow_lower_qc = sharpness ? 0 : 1;
@@ -135,182 +133,51 @@ static AOM_FORCE_INLINE void update_coeff_simple(
qcoeff[ci] = 0;
dqcoeff[ci] = 0;
levels[get_padded_idx(ci, bhl)] = 0;
- *accu_rate += rate_low;
- return;
+ return rate_low;
}
}
- *accu_rate += rate;
+ return rate;
} else {
- int rate_low = 0;
- const int rate = get_two_coeff_cost_simple(
- ci, abs_qc, coeff_ctx, txb_costs, bhl, tx_class, levels, &rate_low);
if (abs_dqc < abs_tqc) {
- *accu_rate += rate;
- return;
- }
-
- const int allow_lower_qc = sharpness ? (abs_qc > 1) : 1;
- if (allow_lower_qc) {
- const int dqv = get_dqv(dequant, scan[si], iqmatrix);
- const tran_low_t abs_qc_low = abs_qc - 1;
- const tran_low_t abs_dqc_low = (abs_qc_low * dqv) >> shift;
- int64_t dist_diff_0, dist_diff_low_0;
- if (qmatrix == NULL) {
- const int64_t abs_tqc2 = (int64_t)abs_tqc << 1;
- dist_diff_0 =
- ((int64_t)abs_dqc * (abs_dqc - abs_tqc2)) * (1LL << (2 * shift));
- dist_diff_low_0 = ((int64_t)abs_dqc_low * (abs_dqc_low - abs_tqc2)) *
- (1LL << (2 * shift));
- } else {
- const int64_t dist0 = get_coeff_dist(abs_tqc, 0, shift, qmatrix, ci);
- dist_diff_0 =
- get_coeff_dist(abs_tqc, abs_dqc, shift, qmatrix, ci) - dist0;
- dist_diff_low_0 =
- get_coeff_dist(abs_tqc, abs_dqc_low, shift, qmatrix, ci) - dist0;
- }
- const int64_t rd = RDCOST(rdmult, rate, dist_diff_0);
- const int64_t rd_low = RDCOST(rdmult, rate_low, dist_diff_low_0);
- if (rd_low < rd) {
- const int sign = (qc < 0) ? 1 : 0;
- qcoeff[ci] = (-sign ^ abs_qc_low) + sign;
- dqcoeff[ci] = (-sign ^ abs_dqc_low) + sign;
- levels[get_padded_idx(ci, bhl)] = AOMMIN(abs_qc_low, INT8_MAX);
- *accu_rate += rate_low;
- return;
+ int rate = txb_costs->base_cost[coeff_ctx][AOMMIN(abs_qc, 3)] +
+ av1_cost_literal(1);
+ if (abs_qc > NUM_BASE_LEVELS) {
+ const int br_ctx = get_br_ctx(levels, ci, bhl, tx_class);
+ rate += get_br_cost(abs_qc, txb_costs->lps_cost[br_ctx]);
}
+ return rate;
}
- *accu_rate += rate;
- }
- }
-}
-
-static AOM_FORCE_INLINE void update_coeff_eob(
- int *accu_rate, int64_t *accu_dist, int *eob, int *nz_num, int *nz_ci,
- int si, TX_SIZE tx_size, TX_CLASS tx_class, int bhl, int width,
- int dc_sign_ctx, int64_t rdmult, int shift, const int16_t *dequant,
- const int16_t *scan, const LV_MAP_EOB_COST *txb_eob_costs,
- const LV_MAP_COEFF_COST *txb_costs, const tran_low_t *tcoeff,
- tran_low_t *qcoeff, tran_low_t *dqcoeff, uint8_t *levels, int sharpness,
- const qm_val_t *iqmatrix, const qm_val_t *qmatrix, int is_noise_pattern) {
- assert(si != *eob - 1);
- const int ci = scan[si];
- const tran_low_t qc = qcoeff[ci];
- const int coeff_ctx =
- get_lower_levels_ctx(levels, ci, bhl, tx_size, tx_class);
- if (qc == 0) {
- *accu_rate += txb_costs->base_cost[coeff_ctx][0];
- } else {
- const int dqv = get_dqv(dequant, scan[si], iqmatrix);
- int lower_level = 0;
- const tran_low_t abs_qc = abs(qc);
- const tran_low_t tqc = tcoeff[ci];
- const tran_low_t dqc = dqcoeff[ci];
- const int sign = (qc < 0) ? 1 : 0;
-
- tran_low_t qc_low = 0, dqc_low = 0;
- tran_low_t abs_qc_low = 0;
- int rate_low;
-
- if (abs_qc == 1) {
- rate_low = txb_costs->base_cost[coeff_ctx][0];
- } else {
- get_qc_dqc_low(abs_qc, sign, dqv, shift, &qc_low, &dqc_low);
- abs_qc_low = abs_qc - 1;
- rate_low =
- get_coeff_cost_general(0, ci, abs_qc_low, sign, coeff_ctx,
- dc_sign_ctx, txb_costs, bhl, tx_class, levels);
- }
- int64_t dist, dist_low;
- if (qmatrix == NULL) {
- const int64_t tqc2 = (int64_t)tqc * 2;
- dist = ((int64_t)dqc * (dqc - tqc2)) * (1LL << (2 * shift));
- dist_low =
- (abs_qc == 1)
- ? 0
- : (((int64_t)dqc_low * (dqc_low - tqc2)) * (1LL << (2 * shift)));
- } else {
- const int64_t dist0 = get_coeff_dist(tqc, 0, shift, qmatrix, ci);
- dist = get_coeff_dist(tqc, dqc, shift, qmatrix, ci) - dist0;
- dist_low =
- (abs_qc == 1)
- ? 0
- : (get_coeff_dist(tqc, dqc_low, shift, qmatrix, ci) - dist0);
- }
-
- int rate =
- get_coeff_cost_general(0, ci, abs_qc, sign, coeff_ctx, dc_sign_ctx,
- txb_costs, bhl, tx_class, levels);
- int64_t rd = RDCOST(rdmult, *accu_rate + rate, *accu_dist + dist);
- int64_t rd_low =
- RDCOST(rdmult, *accu_rate + rate_low, *accu_dist + dist_low);
-
- int lower_level_new_eob = 0;
- const int new_eob = si + 1;
- const int coeff_ctx_new_eob = get_lower_levels_ctx_eob(bhl, width, si);
- const int new_eob_cost =
- get_eob_cost(new_eob, txb_eob_costs, txb_costs, tx_class);
- int rate_coeff_eob =
- new_eob_cost + get_coeff_cost_eob(ci, abs_qc, sign, coeff_ctx_new_eob,
- dc_sign_ctx, txb_costs, bhl,
- tx_class);
- int64_t dist_new_eob = dist;
- int64_t rd_new_eob = RDCOST(rdmult, rate_coeff_eob, dist_new_eob);
-
- if (abs_qc_low > 0) {
- const int rate_coeff_eob_low =
- new_eob_cost + get_coeff_cost_eob(ci, abs_qc_low, sign,
- coeff_ctx_new_eob, dc_sign_ctx,
- txb_costs, bhl, tx_class);
- const int64_t dist_new_eob_low = dist_low;
- const int64_t rd_new_eob_low =
- RDCOST(rdmult, rate_coeff_eob_low, dist_new_eob_low);
- if (rd_new_eob_low < rd_new_eob) {
- lower_level_new_eob = 1;
- rd_new_eob = rd_new_eob_low;
- rate_coeff_eob = rate_coeff_eob_low;
- dist_new_eob = dist_new_eob_low;
+ int rate_low = 0;
+ const int rate = get_two_coeff_cost_simple(
+ ci, abs_qc, coeff_ctx, txb_costs, bhl, tx_class, levels, &rate_low);
+ const int dqv = get_dqv(dequant, ci, iqmatrix);
+ const tran_low_t abs_qc_low = abs_qc - 1;
+ const tran_low_t abs_dqc_low = (abs_qc_low * dqv) >> shift;
+ int64_t dist_diff_0, dist_diff_low_0;
+ if (qmatrix == NULL) {
+ const int64_t abs_tqc2 = (int64_t)abs_tqc << 1;
+ dist_diff_0 =
+ ((int64_t)abs_dqc * (abs_dqc - abs_tqc2)) * (1LL << (2 * shift));
+ dist_diff_low_0 = ((int64_t)abs_dqc_low * (abs_dqc_low - abs_tqc2)) *
+ (1LL << (2 * shift));
+ } else {
+ const int64_t dist0 = get_coeff_dist(abs_tqc, 0, shift, qmatrix, ci);
+ dist_diff_0 =
+ get_coeff_dist(abs_tqc, abs_dqc, shift, qmatrix, ci) - dist0;
+ dist_diff_low_0 =
+ get_coeff_dist(abs_tqc, abs_dqc_low, shift, qmatrix, ci) - dist0;
}
- }
-
- const int min_eob_cutoff = is_noise_pattern ? 8 : 5;
- const int qc_threshold = (si <= min_eob_cutoff) ? 2 : 1;
- const int allow_lower_qc = sharpness ? abs_qc > qc_threshold : 1;
-
- if (allow_lower_qc) {
+ const int64_t rd = RDCOST(rdmult, rate, dist_diff_0);
+ const int64_t rd_low = RDCOST(rdmult, rate_low, dist_diff_low_0);
if (rd_low < rd) {
- lower_level = 1;
- rd = rd_low;
- rate = rate_low;
- dist = dist_low;
+ const int sign = (qc < 0) ? 1 : 0;
+ qcoeff[ci] = (-sign ^ abs_qc_low) + sign;
+ dqcoeff[ci] = (-sign ^ abs_dqc_low) + sign;
+ levels[get_padded_idx(ci, bhl)] = AOMMIN(abs_qc_low, INT8_MAX);
+ return rate_low;
}
- }
-
- if ((sharpness == 0 || new_eob >= min_eob_cutoff) && rd_new_eob < rd) {
- for (int ni = 0; ni < *nz_num; ++ni) {
- int last_ci = nz_ci[ni];
- levels[get_padded_idx(last_ci, bhl)] = 0;
- qcoeff[last_ci] = 0;
- dqcoeff[last_ci] = 0;
- }
- *eob = new_eob;
- *nz_num = 0;
- *accu_rate = rate_coeff_eob;
- *accu_dist = dist_new_eob;
- lower_level = lower_level_new_eob;
- } else {
- *accu_rate += rate;
- *accu_dist += dist;
- }
-
- if (lower_level) {
- qcoeff[ci] = qc_low;
- dqcoeff[ci] = dqc_low;
- levels[get_padded_idx(ci, bhl)] = AOMMIN(abs_qc_low, INT8_MAX);
- }
- if (qcoeff[ci]) {
- nz_ci[*nz_num] = ci;
- ++*nz_num;
+ return rate;
}
}
}
@@ -373,31 +240,166 @@ static AOM_FORCE_INLINE void update_coeff_eob_facade(
int *accu_rate, int64_t *accu_dist, int *eob, int *nz_num, int *nz_ci,
int *si, TX_SIZE tx_size, TX_CLASS tx_class, int bhl, int width,
int dc_sign_ctx, int64_t rdmult, int shift, const int16_t *dequant,
- const int16_t *scan, const LV_MAP_EOB_COST *txb_eob_costs,
- const LV_MAP_COEFF_COST *txb_costs, const tran_low_t *tcoeff,
- tran_low_t *qcoeff, tran_low_t *dqcoeff, uint8_t *levels, int sharpness,
+ const int16_t *__restrict scan,
+ const LV_MAP_EOB_COST *__restrict txb_eob_costs,
+ const LV_MAP_COEFF_COST *__restrict txb_costs,
+ const tran_low_t *__restrict tcoeff, tran_low_t *__restrict qcoeff,
+ tran_low_t *__restrict dqcoeff, uint8_t *__restrict levels, int sharpness,
const qm_val_t *iqmatrix, const qm_val_t *qmatrix, int max_nz_num,
int is_noise_pattern) {
- for (; *si >= 0 && *nz_num <= max_nz_num; --*si) {
- update_coeff_eob(accu_rate, accu_dist, eob, nz_num, nz_ci, *si, tx_size,
- tx_class, bhl, width, dc_sign_ctx, rdmult, shift, dequant,
- scan, txb_eob_costs, txb_costs, tcoeff, qcoeff, dqcoeff,
- levels, sharpness, iqmatrix, qmatrix, is_noise_pattern);
+ int local_rate = *accu_rate;
+ int64_t local_dist = *accu_dist;
+ int local_eob = *eob;
+ int local_nz_num = *nz_num;
+ int local_si = *si;
+ for (; local_si >= 0 && local_nz_num <= max_nz_num; --local_si) {
+ assert(local_si != local_eob - 1);
+ const int ci = scan[local_si];
+ const tran_low_t qc = qcoeff[ci];
+ const int coeff_ctx =
+ get_lower_levels_ctx(levels, ci, bhl, tx_size, tx_class);
+ if (qc == 0) {
+ local_rate += txb_costs->base_cost[coeff_ctx][0];
+ } else {
+ int lower_level = 0;
+ const tran_low_t abs_qc = abs(qc);
+ const tran_low_t tqc = tcoeff[ci];
+ const tran_low_t dqc = dqcoeff[ci];
+ const int sign = (qc < 0) ? 1 : 0;
+
+ tran_low_t qc_low = 0, dqc_low = 0;
+ tran_low_t abs_qc_low = 0;
+ int rate_low;
+
+ if (abs_qc == 1) {
+ rate_low = txb_costs->base_cost[coeff_ctx][0];
+ } else {
+ const int dqv = get_dqv(dequant, ci, iqmatrix);
+ get_qc_dqc_low(abs_qc, sign, dqv, shift, &qc_low, &dqc_low);
+ abs_qc_low = abs_qc - 1;
+ rate_low = get_coeff_cost_general(0, ci, abs_qc_low, sign, coeff_ctx,
+ dc_sign_ctx, txb_costs, bhl, tx_class,
+ levels);
+ }
+
+ int64_t dist, dist_low;
+ if (qmatrix == NULL) {
+ const int64_t tqc2 = (int64_t)tqc * 2;
+ dist = ((int64_t)dqc * (dqc - tqc2)) * (1LL << (2 * shift));
+ dist_low = (abs_qc == 1) ? 0
+ : (((int64_t)dqc_low * (dqc_low - tqc2)) *
+ (1LL << (2 * shift)));
+ } else {
+ const int64_t dist0 = get_coeff_dist(tqc, 0, shift, qmatrix, ci);
+ dist = get_coeff_dist(tqc, dqc, shift, qmatrix, ci) - dist0;
+ dist_low =
+ (abs_qc == 1)
+ ? 0
+ : (get_coeff_dist(tqc, dqc_low, shift, qmatrix, ci) - dist0);
+ }
+
+ int rate =
+ get_coeff_cost_general(0, ci, abs_qc, sign, coeff_ctx, dc_sign_ctx,
+ txb_costs, bhl, tx_class, levels);
+ int64_t rd = RDCOST(rdmult, local_rate + rate, local_dist + dist);
+ int64_t rd_low =
+ RDCOST(rdmult, local_rate + rate_low, local_dist + dist_low);
+
+ int lower_level_new_eob = 0;
+ const int new_eob = local_si + 1;
+ const int coeff_ctx_new_eob =
+ get_lower_levels_ctx_eob(bhl, width, local_si);
+ const int new_eob_cost =
+ get_eob_cost(new_eob, txb_eob_costs, txb_costs, tx_class);
+ int rate_coeff_eob =
+ new_eob_cost + get_coeff_cost_eob(ci, abs_qc, sign, coeff_ctx_new_eob,
+ dc_sign_ctx, txb_costs, bhl,
+ tx_class);
+ int64_t dist_new_eob = dist;
+ int64_t rd_new_eob = RDCOST(rdmult, rate_coeff_eob, dist_new_eob);
+
+ if (abs_qc_low > 0) {
+ const int rate_coeff_eob_low =
+ new_eob_cost + get_coeff_cost_eob(ci, abs_qc_low, sign,
+ coeff_ctx_new_eob, dc_sign_ctx,
+ txb_costs, bhl, tx_class);
+ const int64_t dist_new_eob_low = dist_low;
+ const int64_t rd_new_eob_low =
+ RDCOST(rdmult, rate_coeff_eob_low, dist_new_eob_low);
+ if (rd_new_eob_low < rd_new_eob) {
+ lower_level_new_eob = 1;
+ rd_new_eob = rd_new_eob_low;
+ rate_coeff_eob = rate_coeff_eob_low;
+ dist_new_eob = dist_new_eob_low;
+ }
+ }
+
+ const int min_eob_cutoff = is_noise_pattern ? 8 : 5;
+ const int qc_threshold = (local_si <= min_eob_cutoff) ? 2 : 1;
+ const int allow_lower_qc = sharpness ? abs_qc > qc_threshold : 1;
+
+ if (allow_lower_qc) {
+ if (rd_low < rd) {
+ lower_level = 1;
+ rd = rd_low;
+ rate = rate_low;
+ dist = dist_low;
+ }
+ }
+
+ if ((sharpness == 0 || new_eob >= min_eob_cutoff) && rd_new_eob < rd) {
+ for (int ni = 0; ni < local_nz_num; ++ni) {
+ int last_ci = nz_ci[ni];
+ levels[get_padded_idx(last_ci, bhl)] = 0;
+ qcoeff[last_ci] = 0;
+ dqcoeff[last_ci] = 0;
+ }
+ local_eob = new_eob;
+ local_nz_num = 0;
+ local_rate = rate_coeff_eob;
+ local_dist = dist_new_eob;
+ lower_level = lower_level_new_eob;
+ } else {
+ local_rate += rate;
+ local_dist += dist;
+ }
+
+ if (lower_level) {
+ qcoeff[ci] = qc_low;
+ dqcoeff[ci] = dqc_low;
+ levels[get_padded_idx(ci, bhl)] = AOMMIN(abs_qc_low, INT8_MAX);
+ }
+ if (qcoeff[ci]) {
+ nz_ci[local_nz_num] = ci;
+ ++local_nz_num;
+ }
+ }
}
+ *accu_rate = local_rate;
+ *accu_dist = local_dist;
+ *eob = local_eob;
+ *nz_num = local_nz_num;
+ *si = local_si;
}
static AOM_FORCE_INLINE void update_coeff_simple_facade(
int *accu_rate, int *si, int eob, TX_SIZE tx_size, TX_CLASS tx_class,
int bhl, int64_t rdmult, int shift, const int16_t *dequant,
- const int16_t *scan, const LV_MAP_COEFF_COST *txb_costs,
- const tran_low_t *tcoeff, tran_low_t *qcoeff, tran_low_t *dqcoeff,
- uint8_t *levels, int sharpness, const qm_val_t *iqmatrix,
- const qm_val_t *qmatrix) {
- for (; *si >= 1; --*si) {
- update_coeff_simple(accu_rate, *si, eob, tx_size, tx_class, bhl, rdmult,
- shift, dequant, scan, txb_costs, tcoeff, qcoeff,
- dqcoeff, levels, sharpness, iqmatrix, qmatrix);
+ const int16_t *__restrict scan,
+ const LV_MAP_COEFF_COST *__restrict txb_costs,
+ const tran_low_t *__restrict tcoeff, tran_low_t *__restrict qcoeff,
+ tran_low_t *__restrict dqcoeff, uint8_t *__restrict levels, int sharpness,
+ const qm_val_t *iqmatrix, const qm_val_t *qmatrix) {
+ int local_rate = *accu_rate;
+ int local_si = *si;
+ for (; local_si >= 1; --local_si) {
+ local_rate +=
+ update_coeff_simple(local_si, eob, tx_size, tx_class, bhl, rdmult,
+ shift, dequant, scan, txb_costs, tcoeff, qcoeff,
+ dqcoeff, levels, sharpness, iqmatrix, qmatrix);
}
+ *accu_rate = local_rate;
+ *si = local_si;
}
int av1_optimize_txb(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
@@ -512,9 +514,14 @@ int av1_optimize_txb(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
txb_costs, bhl, tx_class);
const tran_low_t tqc = tcoeff[ci];
const tran_low_t dqc = dqcoeff[ci];
- const int64_t dist = get_coeff_dist(tqc, dqc, shift, qmatrix, ci);
- const int64_t dist0 = get_coeff_dist(tqc, 0, shift, qmatrix, ci);
- accu_dist += dist - dist0;
+ if (qmatrix == NULL) {
+ accu_dist +=
+ ((int64_t)dqc * (dqc - (int64_t)tqc * 2)) * (1LL << (2 * shift));
+ } else {
+ const int64_t dist = get_coeff_dist(tqc, dqc, shift, qmatrix, ci);
+ const int64_t dist0 = get_coeff_dist(tqc, 0, shift, qmatrix, ci);
+ accu_dist += dist - dist0;
+ }
--si;
}
@@ -526,19 +533,20 @@ int av1_optimize_txb(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
dequant, scan, txb_eob_costs, txb_costs, tcoeff, qcoeff, dqcoeff, \
levels, sharpness, iqmatrix, qmatrix, max_nz_num, is_noise_pattern); \
break
- switch (tx_class) {
- UPDATE_COEFF_EOB_CASE(TX_CLASS_2D);
- UPDATE_COEFF_EOB_CASE(TX_CLASS_HORIZ);
- UPDATE_COEFF_EOB_CASE(TX_CLASS_VERT);
+ if (si >= 0) {
+ switch (tx_class) {
+ UPDATE_COEFF_EOB_CASE(TX_CLASS_2D);
+ UPDATE_COEFF_EOB_CASE(TX_CLASS_HORIZ);
+ UPDATE_COEFF_EOB_CASE(TX_CLASS_VERT);
#undef UPDATE_COEFF_EOB_CASE
- default: assert(false);
+ default: assert(false);
+ }
}
if (si == -1 && nz_num <= max_nz_num && sharpness == 0) {
update_skip(&accu_rate, accu_dist, &eob, nz_num, nz_ci, rdmult, skip_cost,
non_skip_cost, qcoeff, dqcoeff);
- }
-
+ } else if (si >= 1) {
#define UPDATE_COEFF_SIMPLE_CASE(tx_class_literal) \
case tx_class_literal: \
update_coeff_simple_facade(&accu_rate, &si, eob, tx_size, \
@@ -546,12 +554,13 @@ int av1_optimize_txb(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
scan, txb_costs, tcoeff, qcoeff, dqcoeff, \
levels, sharpness, iqmatrix, qmatrix); \
break
- switch (tx_class) {
- UPDATE_COEFF_SIMPLE_CASE(TX_CLASS_2D);
- UPDATE_COEFF_SIMPLE_CASE(TX_CLASS_HORIZ);
- UPDATE_COEFF_SIMPLE_CASE(TX_CLASS_VERT);
+ switch (tx_class) {
+ UPDATE_COEFF_SIMPLE_CASE(TX_CLASS_2D);
+ UPDATE_COEFF_SIMPLE_CASE(TX_CLASS_HORIZ);
+ UPDATE_COEFF_SIMPLE_CASE(TX_CLASS_VERT);
#undef UPDATE_COEFF_SIMPLE_CASE
- default: assert(false);
+ default: assert(false);
+ }
}
// DC position
@@ -564,16 +573,17 @@ int av1_optimize_txb(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
levels, iqmatrix, qmatrix);
}
- const int tx_type_cost = get_tx_type_cost(x, xd, plane, tx_size, tx_type,
- cm->features.reduced_tx_set_used);
- if (eob == 0)
+ p->eobs[block] = eob;
+ if (eob == 0) {
accu_rate += skip_cost;
- else
+ p->txb_entropy_ctx[block] = 0;
+ } else {
+ const int tx_type_cost = get_tx_type_cost(x, xd, plane, tx_size, tx_type,
+ cm->features.reduced_tx_set_used);
accu_rate += non_skip_cost + tx_type_cost;
-
- p->eobs[block] = eob;
- p->txb_entropy_ctx[block] =
- av1_get_txb_entropy_context(qcoeff, scan_order, p->eobs[block]);
+ p->txb_entropy_ctx[block] =
+ av1_get_txb_entropy_context(qcoeff, scan_order, eob);
+ }
*rate_cost = accu_rate;
return eob;
@@ -586,31 +596,84 @@ static AOM_FORCE_INLINE int warehouse_efficients_txb(
const PLANE_TYPE plane_type, const LV_MAP_COEFF_COST *const coeff_costs,
const MACROBLOCKD *const xd, const TX_TYPE tx_type, const TX_CLASS tx_class,
int reduced_tx_set_used) {
- const tran_low_t *const qcoeff = p->qcoeff + BLOCK_OFFSET(block);
+ const tran_low_t *const __restrict qcoeff = p->qcoeff + BLOCK_OFFSET(block);
const int txb_skip_ctx = txb_ctx->txb_skip_ctx;
- const int bhl = get_txb_bhl(tx_size);
- const int width = get_txb_wide(tx_size);
- const int height = get_txb_high(tx_size);
- const SCAN_ORDER *const scan_order = get_scan(tx_size, tx_type);
- const int16_t *const scan = scan_order->scan;
- uint8_t levels_buf[TX_PAD_2D];
- uint8_t *const levels = set_levels(levels_buf, height);
- DECLARE_ALIGNED(16, int8_t, coeff_contexts[MAX_TX_SQUARE]);
const int eob_multi_size = txsize_log2_minus4[tx_size];
const LV_MAP_EOB_COST *const eob_costs =
&x->coeff_costs.eob_costs[eob_multi_size][plane_type];
int cost = coeff_costs->txb_skip_cost[txb_skip_ctx][0];
- if (eob > 1) av1_txb_init_levels(qcoeff, width, height, levels);
-
cost += get_tx_type_cost(x, xd, plane, tx_size, tx_type, reduced_tx_set_used);
-
cost += get_eob_cost(eob, eob_costs, coeff_costs, tx_class);
- av1_get_nz_map_contexts(levels, scan, eob, tx_size, tx_class, coeff_contexts);
-
const int (*lps_cost)[COEFF_BASE_RANGE + 1 + COEFF_BASE_RANGE + 1] =
coeff_costs->lps_cost;
+
+ if (eob == 1) {
+ const tran_low_t v = qcoeff[0];
+ if (v) {
+ const int sign = AOMSIGN(v);
+ const int level = (v ^ sign) - sign;
+ cost += coeff_costs->base_eob_cost[0][AOMMIN(level, 3) - 1];
+ if (level > NUM_BASE_LEVELS) {
+ cost += get_br_cost(level, lps_cost[0]);
+ }
+ const int sign01 = (sign ^ sign) - sign;
+ const int dc_sign_ctx = txb_ctx->dc_sign_ctx;
+ cost += coeff_costs->dc_sign_cost[dc_sign_ctx][sign01];
+ }
+ return cost;
+ }
+
+ const int bhl = get_txb_bhl(tx_size);
+ const int width = get_txb_wide(tx_size);
+ const SCAN_ORDER *const scan_order = get_scan(tx_size, tx_type);
+ const int16_t *const __restrict scan = scan_order->scan;
+ const int (*base_cost)[8] = coeff_costs->base_cost;
+
+ if (eob == 2 && tx_class == TX_CLASS_2D) {
+ const int pos1 = scan[1];
+ const tran_low_t v1 = qcoeff[pos1];
+ int level1 = 0;
+ if (v1) {
+ const int sign1 = AOMSIGN(v1);
+ level1 = (v1 ^ sign1) - sign1;
+ const int coeff_ctx1 = get_lower_levels_ctx_eob(bhl, width, 1);
+ cost += coeff_costs->base_eob_cost[coeff_ctx1][AOMMIN(level1, 3) - 1];
+ if (level1 > NUM_BASE_LEVELS) {
+ const int ctx1 = get_br_ctx_eob(pos1, bhl, TX_CLASS_2D);
+ cost += get_br_cost(level1, lps_cost[ctx1]);
+ }
+ cost += av1_cost_literal(1);
+ }
+ const tran_low_t v0 = qcoeff[0];
+ if (!v0) {
+ cost += base_cost[0][0];
+ } else {
+ const int sign0 = AOMSIGN(v0);
+ const int level0 = (v0 ^ sign0) - sign0;
+ cost += base_cost[0][AOMMIN(level0, 3)];
+ const int sign01 = (sign0 ^ sign0) - sign0;
+ const int dc_sign_ctx = txb_ctx->dc_sign_ctx;
+ cost += coeff_costs->dc_sign_cost[dc_sign_ctx][sign01];
+ if (level0 > NUM_BASE_LEVELS) {
+ const int mag =
+ (pos1 == 1 || pos1 == (1 << bhl) || pos1 == (1 << bhl) + 1)
+ ? AOMMIN(level1, INT8_MAX)
+ : 0;
+ const int ctx0 = AOMMIN((mag + 1) >> 1, 6);
+ cost += get_br_cost(level0, lps_cost[ctx0]);
+ }
+ }
+ return cost;
+ }
+
+ const int height = get_txb_high(tx_size);
+ uint8_t levels_buf[TX_PAD_2D];
+ uint8_t *const __restrict levels = set_levels(levels_buf, height);
+
+ av1_txb_init_levels(qcoeff, width, height, levels);
+
int c = eob - 1;
{
const int pos = scan[c];
@@ -619,37 +682,64 @@ static AOM_FORCE_INLINE int warehouse_efficients_txb(
if (v) {
const int sign = AOMSIGN(v);
const int level = (v ^ sign) - sign;
- const int coeff_ctx = coeff_contexts[pos];
+ const int coeff_ctx = get_lower_levels_ctx_eob(bhl, width, c);
cost += coeff_costs->base_eob_cost[coeff_ctx][AOMMIN(level, 3) - 1];
- // sign bit cost
if (level > NUM_BASE_LEVELS) {
const int ctx = get_br_ctx_eob(pos, bhl, tx_class);
cost += get_br_cost(level, lps_cost[ctx]);
}
- if (c) {
- cost += av1_cost_literal(1);
+ cost += av1_cost_literal(1);
+ }
+ }
+
+ if (eob <= ((width << bhl) >> 4) + 3) {
+ for (c = eob - 2; c >= 1; --c) {
+ const int pos = scan[c];
+ const int coeff_ctx =
+ get_lower_levels_ctx(levels, pos, bhl, tx_size, tx_class);
+ const int level = abs(qcoeff[pos]);
+ if (level <= NUM_BASE_LEVELS) {
+ cost +=
+ base_cost[coeff_ctx][level] + ((level > 0) << AV1_PROB_COST_SHIFT);
} else {
- const int sign01 = (sign ^ sign) - sign;
- const int dc_sign_ctx = txb_ctx->dc_sign_ctx;
- cost += coeff_costs->dc_sign_cost[dc_sign_ctx][sign01];
- return cost;
+ cost += base_cost[coeff_ctx][3] + av1_cost_literal(1);
+ const int ctx = get_br_ctx(levels, pos, bhl, tx_class);
+ cost += get_br_cost(level, lps_cost[ctx]);
+ }
+ }
+ const tran_low_t v = qcoeff[0];
+ const int coeff_ctx =
+ (tx_class == TX_CLASS_2D)
+ ? 0
+ : get_lower_levels_ctx(levels, 0, bhl, tx_size, tx_class);
+ if (!v) {
+ cost += base_cost[coeff_ctx][0];
+ } else {
+ const int sign = AOMSIGN(v);
+ const int level = (v ^ sign) - sign;
+ cost += base_cost[coeff_ctx][AOMMIN(level, 3)];
+ const int sign01 = (sign ^ sign) - sign;
+ const int dc_sign_ctx = txb_ctx->dc_sign_ctx;
+ cost += coeff_costs->dc_sign_cost[dc_sign_ctx][sign01];
+ if (level > NUM_BASE_LEVELS) {
+ const int ctx = get_br_ctx(levels, 0, bhl, tx_class);
+ cost += get_br_cost(level, lps_cost[ctx]);
}
}
+ return cost;
}
- const int (*base_cost)[8] = coeff_costs->base_cost;
+
+ DECLARE_ALIGNED(16, int8_t, coeff_contexts[MAX_TX_SQUARE]);
+ av1_get_nz_map_contexts(levels, scan, eob, tx_size, tx_class, coeff_contexts);
for (c = eob - 2; c >= 1; --c) {
const int pos = scan[c];
const int coeff_ctx = coeff_contexts[pos];
- const tran_low_t v = qcoeff[pos];
- if (!v) {
- cost += base_cost[coeff_ctx][0];
- continue;
- }
- const int level = abs(v);
- cost += base_cost[coeff_ctx][AOMMIN(level, 3)];
- // sign bit cost
- cost += av1_cost_literal(1);
- if (level > NUM_BASE_LEVELS) {
+ const int level = abs(qcoeff[pos]);
+ if (level <= NUM_BASE_LEVELS) {
+ cost +=
+ base_cost[coeff_ctx][level] + ((level > 0) << AV1_PROB_COST_SHIFT);
+ } else {
+ cost += base_cost[coeff_ctx][3] + av1_cost_literal(1);
const int ctx = get_br_ctx(levels, pos, bhl, tx_class);
cost += get_br_cost(level, lps_cost[ctx]);
}
diff --git a/av1/encoder/txb_rdopt_utils.h b/av1/encoder/txb_rdopt_utils.h
index b7cdd922d7..1ceee6610a 100644
--- a/av1/encoder/txb_rdopt_utils.h
+++ b/av1/encoder/txb_rdopt_utils.h
@@ -85,6 +85,7 @@ static int get_eob_cost(int eob, const LV_MAP_EOB_COST *txb_eob_costs,
static inline int get_golomb_cost(int abs_qc) {
if (abs_qc >= 1 + NUM_BASE_LEVELS + COEFF_BASE_RANGE) {
const int r = abs_qc - COEFF_BASE_RANGE - NUM_BASE_LEVELS;
+ if (r < 32) return golomb_bits_cost[r];
const int length = get_msb(r) + 1;
return av1_cost_literal(2 * length - 1);
}
diff --git a/av1/encoder/x86/temporal_filter_avx2.c b/av1/encoder/x86/temporal_filter_avx2.c
index 3d1c9fea9f..0514b1c13b 100644
--- a/av1/encoder/x86/temporal_filter_avx2.c
+++ b/av1/encoder/x86/temporal_filter_avx2.c
@@ -316,6 +316,37 @@ static inline __m256 approx_exp_avx2(__m256 y) {
#undef C
}
+// Bit-exact AVX2 double-precision implementation of exp(-x) for x in [0, 7]
+static inline __m256d exact_exp_neg_pd_avx2(__m256d x) {
+ x = _mm256_min_pd(x, _mm256_set1_pd(7.0));
+ const __m256d inv_ln2 = _mm256_set1_pd(1.44269504088896340736);
+ const __m256d ln2_hi = _mm256_set1_pd(0.6931471805596629565116);
+ const __m256d ln2_lo = _mm256_set1_pd(0.2823529056303157712259e-12);
+ const __m256d k = _mm256_round_pd(
+ _mm256_mul_pd(x, inv_ln2), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
+ const __m256d r = _mm256_add_pd(_mm256_sub_pd(_mm256_mul_pd(k, ln2_hi), x),
+ _mm256_mul_pd(k, ln2_lo));
+ const __m256d c1 = _mm256_set1_pd(1.0);
+ const __m256d c2 = _mm256_set1_pd(0.5);
+ const __m256d c3 = _mm256_set1_pd(1.0 / 6.0);
+ const __m256d c4 = _mm256_set1_pd(1.0 / 24.0);
+ const __m256d c5 = _mm256_set1_pd(1.0 / 120.0);
+ const __m256d c6 = _mm256_set1_pd(1.0 / 720.0);
+ const __m256d c7 = _mm256_set1_pd(1.0 / 5040.0);
+ __m256d p = _mm256_add_pd(_mm256_mul_pd(c7, r), c6);
+ p = _mm256_add_pd(_mm256_mul_pd(p, r), c5);
+ p = _mm256_add_pd(_mm256_mul_pd(p, r), c4);
+ p = _mm256_add_pd(_mm256_mul_pd(p, r), c3);
+ p = _mm256_add_pd(_mm256_mul_pd(p, r), c2);
+ p = _mm256_add_pd(_mm256_mul_pd(p, r), c1);
+ p = _mm256_add_pd(_mm256_mul_pd(p, r), c1);
+ const __m128i ki = _mm256_cvtpd_epi32(k);
+ const __m256i ki64 =
+ _mm256_cvtepi32_epi64(_mm_sub_epi32(_mm_set1_epi32(1023), ki));
+ const __m256d pow2 = _mm256_castsi256_pd(_mm256_slli_epi64(ki64, 52));
+ return _mm256_mul_pd(p, pow2);
+}
+
static void apply_temporal_filter(
const uint8_t *frame1, const unsigned int stride, const uint8_t *frame2,
const unsigned int stride2, const int block_width, const int block_height,
@@ -383,101 +414,75 @@ static void apply_temporal_filter(
subblock_mses_scaled[idx] = subblock_mses[idx] * inv_factor;
d_factor_decayed[idx] = d_factor[idx] * decay_factor;
}
- if (tf_wgt_calc_lvl == 0) {
- for (int i = 0, k = 0; i < block_height; i++) {
- const int y32_blk_raster_offset = (i >= (block_height >> 1)) << 1;
- const int y16_blk_raster_offset =
- ((i % (block_height >> 1)) >= (block_height >> 2)) << 1;
- for (int j = 0; j < block_width; j++, k++) {
- const int pixel_value = frame2[i * stride2 + j];
- uint32_t diff_sse = acc_5x5_sse[i][j] + luma_sse_sum[i * BW + j];
-
- const double window_error = diff_sse * inv_num_ref_pixels;
- const int x32_blk_raster_offset = (j >= (block_width >> 1));
- const int x16_blk_raster_offset =
- ((j % (block_width >> 1)) >= (block_width >> 2));
- const int subblock_idx =
- ((y32_blk_raster_offset + x32_blk_raster_offset) << 2) +
- (y16_blk_raster_offset + x16_blk_raster_offset);
- const double combined_error =
- weight_factor * window_error + subblock_mses_scaled[subblock_idx];
-
- double scaled_error = combined_error * d_factor_decayed[subblock_idx];
- scaled_error = AOMMIN(scaled_error, 7);
- const int weight = (int)(exp(-scaled_error) * TF_WEIGHT_SCALE);
-
- count[k] += weight;
- accumulator[k] += weight * pixel_value;
- }
- }
- } else {
- __m256d subblock_mses_reg[NUM_16X16];
- __m256d d_factor_mul_n_decay_qr_invs[NUM_16X16];
- const __m256 zero = _mm256_set1_ps(0.0f);
- const __m256 point_five = _mm256_set1_ps(0.5f);
- const __m256 seven = _mm256_set1_ps(7.0f);
- const __m256d inv_num_ref_pixel_256bit = _mm256_set1_pd(inv_num_ref_pixels);
- const __m256d weight_factor_256bit = _mm256_set1_pd(weight_factor);
- const __m256 tf_weight_scale = _mm256_set1_ps((float)TF_WEIGHT_SCALE);
- // Maintain registers to hold mse and d_factor at subblock level.
- for (int i = 0; i < NUM_16X16; i++) {
- subblock_mses_reg[i] = _mm256_set1_pd(subblock_mses_scaled[i]);
- d_factor_mul_n_decay_qr_invs[i] = _mm256_set1_pd(d_factor_decayed[i]);
- }
-
- for (int i = 0; i < block_height; i++) {
- const int y32_blk_raster_offset = (i >= (block_height >> 1)) << 1;
- const int y16_blk_raster_offset =
- ((i % (block_height >> 1)) >= (block_height >> 2)) << 1;
- uint32_t *luma_sse_sum_temp = luma_sse_sum + i * BW;
- for (int j = 0; j < block_width; j += 8) {
- const __m256i acc_sse =
- _mm256_lddqu_si256((__m256i *)(acc_5x5_sse[i] + j));
- const __m256i luma_sse =
- _mm256_lddqu_si256((__m256i *)((luma_sse_sum_temp + j)));
-
- // uint32_t diff_sse = acc_5x5_sse[i][j] + luma_sse_sum[i * BW + j];
- const __m256i diff_sse = _mm256_add_epi32(acc_sse, luma_sse);
-
- const __m256d diff_sse_pd_1 =
- _mm256_cvtepi32_pd(_mm256_castsi256_si128(diff_sse));
- const __m256d diff_sse_pd_2 =
- _mm256_cvtepi32_pd(_mm256_extracti128_si256(diff_sse, 1));
-
- // const double window_error = diff_sse * inv_num_ref_pixels;
- const __m256d window_error_1 =
- _mm256_mul_pd(diff_sse_pd_1, inv_num_ref_pixel_256bit);
- const __m256d window_error_2 =
- _mm256_mul_pd(diff_sse_pd_2, inv_num_ref_pixel_256bit);
-
- // const int subblock_idx = (y32 * 2 + x32) * 4 + (y16 * 2 + x16);
- const int x32_blk_raster_offset = (j >= (block_width >> 1));
- const int x16_blk_raster_offset =
- ((j % (block_width >> 1)) >= (block_width >> 2));
- const int subblock_idx =
- ((y32_blk_raster_offset + x32_blk_raster_offset) << 2) +
- (y16_blk_raster_offset + x16_blk_raster_offset);
- const __m256d blk_error = subblock_mses_reg[subblock_idx];
-
- // const double combined_error =
- // weight_factor *window_error + subblock_mses_scaled[subblock_idx];
- const __m256d combined_error_1 = _mm256_add_pd(
- _mm256_mul_pd(window_error_1, weight_factor_256bit), blk_error);
-
- const __m256d combined_error_2 = _mm256_add_pd(
- _mm256_mul_pd(window_error_2, weight_factor_256bit), blk_error);
-
- // d_factor_decayed[subblock_idx]
- const __m256d d_fact_mul_n_decay =
- d_factor_mul_n_decay_qr_invs[subblock_idx];
-
- // double scaled_error = combined_error *
- // d_factor_decayed[subblock_idx];
- const __m256d scaled_error_1 =
- _mm256_mul_pd(combined_error_1, d_fact_mul_n_decay);
- const __m256d scaled_error_2 =
- _mm256_mul_pd(combined_error_2, d_fact_mul_n_decay);
+ __m256d subblock_mses_reg[NUM_16X16];
+ __m256d d_factor_mul_n_decay_qr_invs[NUM_16X16];
+ const __m256 zero = _mm256_set1_ps(0.0f);
+ const __m256 point_five = _mm256_set1_ps(0.5f);
+ const __m256 seven = _mm256_set1_ps(7.0f);
+ const __m256d inv_num_ref_pixel_256bit = _mm256_set1_pd(inv_num_ref_pixels);
+ const __m256d weight_factor_256bit = _mm256_set1_pd(weight_factor);
+ const __m256 tf_weight_scale = _mm256_set1_ps((float)TF_WEIGHT_SCALE);
+ const __m256d tf_weight_scale_pd = _mm256_set1_pd((double)TF_WEIGHT_SCALE);
+ // Maintain registers to hold mse and d_factor at subblock level.
+ for (int i = 0; i < NUM_16X16; i++) {
+ subblock_mses_reg[i] = _mm256_set1_pd(subblock_mses_scaled[i]);
+ d_factor_mul_n_decay_qr_invs[i] = _mm256_set1_pd(d_factor_decayed[i]);
+ }
+ for (int i = 0; i < block_height; i++) {
+ const int y32_blk_raster_offset = (i >= (block_height >> 1)) << 1;
+ const int y16_blk_raster_offset =
+ ((i % (block_height >> 1)) >= (block_height >> 2)) << 1;
+ uint32_t *luma_sse_sum_temp = luma_sse_sum + i * BW;
+ for (int j = 0; j < block_width; j += 8) {
+ const __m256i acc_sse =
+ _mm256_lddqu_si256((__m256i *)(acc_5x5_sse[i] + j));
+ const __m256i luma_sse =
+ _mm256_lddqu_si256((__m256i *)((luma_sse_sum_temp + j)));
+
+ const __m256i diff_sse = _mm256_add_epi32(acc_sse, luma_sse);
+
+ const __m256d diff_sse_pd_1 =
+ _mm256_cvtepi32_pd(_mm256_castsi256_si128(diff_sse));
+ const __m256d diff_sse_pd_2 =
+ _mm256_cvtepi32_pd(_mm256_extracti128_si256(diff_sse, 1));
+
+ const __m256d window_error_1 =
+ _mm256_mul_pd(diff_sse_pd_1, inv_num_ref_pixel_256bit);
+ const __m256d window_error_2 =
+ _mm256_mul_pd(diff_sse_pd_2, inv_num_ref_pixel_256bit);
+
+ const int x32_blk_raster_offset = (j >= (block_width >> 1));
+ const int x16_blk_raster_offset =
+ ((j % (block_width >> 1)) >= (block_width >> 2));
+ const int subblock_idx =
+ ((y32_blk_raster_offset + x32_blk_raster_offset) << 2) +
+ (y16_blk_raster_offset + x16_blk_raster_offset);
+ const __m256d blk_error = subblock_mses_reg[subblock_idx];
+
+ const __m256d combined_error_1 = _mm256_add_pd(
+ _mm256_mul_pd(window_error_1, weight_factor_256bit), blk_error);
+
+ const __m256d combined_error_2 = _mm256_add_pd(
+ _mm256_mul_pd(window_error_2, weight_factor_256bit), blk_error);
+
+ const __m256d d_fact_mul_n_decay =
+ d_factor_mul_n_decay_qr_invs[subblock_idx];
+
+ const __m256d scaled_error_1 =
+ _mm256_mul_pd(combined_error_1, d_fact_mul_n_decay);
+ const __m256d scaled_error_2 =
+ _mm256_mul_pd(combined_error_2, d_fact_mul_n_decay);
+
+ __m256i weights_in_32bit;
+ if (tf_wgt_calc_lvl == 0) {
+ const __m128i w1 = _mm256_cvttpd_epi32(_mm256_mul_pd(
+ exact_exp_neg_pd_avx2(scaled_error_1), tf_weight_scale_pd));
+ const __m128i w2 = _mm256_cvttpd_epi32(_mm256_mul_pd(
+ exact_exp_neg_pd_avx2(scaled_error_2), tf_weight_scale_pd));
+ weights_in_32bit =
+ _mm256_inserti128_si256(_mm256_castsi128_si256(w1), w2, 0x1);
+ } else {
const __m128 scaled_error_ps_1 = _mm256_cvtpd_ps(scaled_error_1);
const __m128 scaled_error_ps_2 = _mm256_cvtpd_ps(scaled_error_2);
@@ -494,32 +499,32 @@ static void apply_temporal_filter(
_mm256_mul_ps(exp_result, tf_weight_scale);
const __m256 round_result =
_mm256_add_ps(scale_weight_exp_result, point_five);
- __m256i weights_in_32bit = _mm256_cvttps_epi32(round_result);
-
- __m128i weights_in_16bit =
- _mm_packus_epi32(_mm256_castsi256_si128(weights_in_32bit),
- _mm256_extractf128_si256(weights_in_32bit, 0x1));
-
- // count[k] += weight;
- // accumulator[k] += weight * pixel_value;
- const int stride_idx = i * stride2 + j;
- const __m128i count_array =
- _mm_loadu_si128((__m128i *)(count + stride_idx));
- _mm_storeu_si128((__m128i *)(count + stride_idx),
- _mm_add_epi16(count_array, weights_in_16bit));
-
- const __m256i accumulator_array =
- _mm256_loadu_si256((__m256i *)(accumulator + stride_idx));
- const __m128i pred_values =
- _mm_loadl_epi64((__m128i *)(frame2 + stride_idx));
-
- const __m256i pred_values_u32 = _mm256_cvtepu8_epi32(pred_values);
- const __m256i mull_frame2_weight_u32 =
- _mm256_mullo_epi32(pred_values_u32, weights_in_32bit);
- _mm256_storeu_si256(
- (__m256i *)(accumulator + stride_idx),
- _mm256_add_epi32(accumulator_array, mull_frame2_weight_u32));
+ weights_in_32bit = _mm256_cvttps_epi32(round_result);
}
+
+ __m128i weights_in_16bit =
+ _mm_packus_epi32(_mm256_castsi256_si128(weights_in_32bit),
+ _mm256_extractf128_si256(weights_in_32bit, 0x1));
+
+ // count[k] += weight;
+ // accumulator[k] += weight * pixel_value;
+ const int stride_idx = i * stride2 + j;
+ const __m128i count_array =
+ _mm_loadu_si128((__m128i *)(count + stride_idx));
+ _mm_storeu_si128((__m128i *)(count + stride_idx),
+ _mm_add_epi16(count_array, weights_in_16bit));
+
+ const __m256i accumulator_array =
+ _mm256_loadu_si256((__m256i *)(accumulator + stride_idx));
+ const __m128i pred_values =
+ _mm_loadl_epi64((__m128i *)(frame2 + stride_idx));
+
+ const __m256i pred_values_u32 = _mm256_cvtepu8_epi32(pred_values);
+ const __m256i mull_frame2_weight_u32 =
+ _mm256_mullo_epi32(pred_values_u32, weights_in_32bit);
+ _mm256_storeu_si256(
+ (__m256i *)(accumulator + stride_idx),
+ _mm256_add_epi32(accumulator_array, mull_frame2_weight_u32));
}
}
}