Commit 8f87187c0c for aom

commit 8f87187c0c12b87b72a148b95a6679ee243c41c4
Author: Lin Zheng <linzhen@google.com>
Date:   Sun Nov 8 23:00:35 2026 +0000

    Highway: Add AVX512 variance, mse, and var stats

    Function / Block Size    │ AVX2 (ns) │ AVX512 (ns) │ Speedup (x)
    ─────────────────────────┼───────────┼─────────────┼────────────
     variance 16x4           │    3.67   │     3.52    │    1.04x
     variance 16x8           │    5.47   │     5.01    │    1.09x
     variance 16x16          │   10.09   │     7.99    │    1.26x
     variance 16x32          │   18.39   │    14.16    │    1.30x
     variance 16x64          │   39.76   │    27.25    │    1.46x
     variance 32x8           │    8.32   │     6.52    │    1.28x
     variance 32x16          │   18.58   │    10.68    │    1.74x
     variance 32x32          │   30.17   │    20.90    │    1.44x
     variance 32x64          │   59.39   │    39.85    │    1.49x
     variance 64x16          │   27.51   │    22.80    │    1.21x
     variance 64x32          │   52.99   │    30.63    │    1.73x
     variance 64x64          │  105.18   │    59.44    │    1.77x
     variance 64x128         │  207.84   │   118.49    │    1.75x
     variance 128x64         │  220.94   │   106.01    │    2.08x
     variance 128x128        │  439.94   │   210.40    │    2.09x
     mse16x16                │   10.22   │     7.61    │    1.34x
     get_blk_sse_sum 64x64   │  140.32   │   105.47    │    1.33x
     calc_variance_stat 64x64│  409.00   │   169.71    │    2.41x

    Change-Id: I4318dfa229d6d162aad69b25eec2ee524e4ae9ed

diff --git a/aom_dsp/aom_dsp.cmake b/aom_dsp/aom_dsp.cmake
index 869152568a..2c6ee2537a 100644
--- a/aom_dsp/aom_dsp.cmake
+++ b/aom_dsp/aom_dsp.cmake
@@ -188,7 +188,8 @@ if(CONFIG_AV1_ENCODER)
   if(CONFIG_HIGHWAY)
     list(APPEND AOM_DSP_ENCODER_SOURCES "${AOM_ROOT}/aom_dsp/reduce_sum_hwy.h"
                 "${AOM_ROOT}/aom_dsp/sad_hwy.h"
-                "${AOM_ROOT}/aom_dsp/subtract_hwy.h")
+                "${AOM_ROOT}/aom_dsp/subtract_hwy.h"
+                "${AOM_ROOT}/aom_dsp/variance_hwy.h")
   endif()

   # Flow estimation library and grain/noise table/model.
@@ -274,7 +275,8 @@ if(CONFIG_AV1_ENCODER)
                 "${AOM_ROOT}/aom_dsp/x86/sad_hwy_avx2.cc")
     list(APPEND AOM_DSP_ENCODER_INTRIN_AVX512
                 "${AOM_ROOT}/aom_dsp/x86/sad_hwy_avx512.cc"
-                "${AOM_ROOT}/aom_dsp/x86/subtract_hwy_avx512.cc")
+                "${AOM_ROOT}/aom_dsp/x86/subtract_hwy_avx512.cc"
+                "${AOM_ROOT}/aom_dsp/x86/variance_hwy_avx512.cc")
     list(REMOVE_ITEM AOM_DSP_ENCODER_INTRIN_AVX2
                      "${AOM_ROOT}/aom_dsp/x86/sad_impl_avx2.c")
   endif()
diff --git a/aom_dsp/aom_dsp_rtcd_defs.pl b/aom_dsp/aom_dsp_rtcd_defs.pl
index ed27e7d0fe..c8b28deb93 100755
--- a/aom_dsp/aom_dsp_rtcd_defs.pl
+++ b/aom_dsp/aom_dsp_rtcd_defs.pl
@@ -827,7 +827,11 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
   specialize qw/aom_sse sse4_1 avx2 neon neon_dotprod/;

   add_proto qw/void/, "aom_get_blk_sse_sum", "const int16_t *data, int stride, int bw, int bh, int *x_sum, int64_t *x2_sum";
-  specialize qw/aom_get_blk_sse_sum sse2 avx2 neon sve/;
+  if (aom_config("CONFIG_HIGHWAY") eq "yes") {
+    specialize qw/aom_get_blk_sse_sum sse2 avx2 avx512 neon sve/;
+  } else {
+    specialize qw/aom_get_blk_sse_sum sse2 avx2 neon sve/;
+  }

   if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") {
     add_proto qw/void aom_highbd_subtract_block/, "int rows, int cols, 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";
@@ -1413,7 +1417,11 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
   add_proto qw/unsigned int aom_mse8x16/, "const uint8_t *src_ptr, int  source_stride, const uint8_t *ref_ptr, int  recon_stride, unsigned int *sse";
   add_proto qw/unsigned int aom_mse8x8/, "const uint8_t *src_ptr, int  source_stride, const uint8_t *ref_ptr, int  recon_stride, unsigned int *sse";

-  specialize qw/aom_mse16x16          sse2 avx2 neon neon_dotprod/;
+  if (aom_config("CONFIG_HIGHWAY") eq "yes") {
+    specialize qw/aom_mse16x16          sse2 avx2 avx512 neon neon_dotprod/;
+  } else {
+    specialize qw/aom_mse16x16          sse2 avx2 neon neon_dotprod/;
+  }
   specialize qw/aom_mse16x8           sse2      neon neon_dotprod/;
   specialize qw/aom_mse8x16           sse2      neon neon_dotprod/;
   specialize qw/aom_mse8x8            sse2      neon neon_dotprod/;
@@ -1457,11 +1465,19 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
   specialize qw/aom_mse_wxh_16bit  sse2 avx2 neon/;

   add_proto qw/int64_t/, "aom_calc_variance_stat", "const uint8_t *src, int stride, int bw, int bh";
-  specialize qw/aom_calc_variance_stat avx2/;
+  if (aom_config("CONFIG_HIGHWAY") eq "yes") {
+    specialize qw/aom_calc_variance_stat avx2 avx512/;
+  } else {
+    specialize qw/aom_calc_variance_stat avx2/;
+  }

   if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") {
     add_proto qw/int64_t/, "aom_highbd_calc_variance_stat", "const uint16_t *src, int stride, int bw, int bh";
-    specialize qw/aom_highbd_calc_variance_stat avx2/;
+    if (aom_config("CONFIG_HIGHWAY") eq "yes") {
+      specialize qw/aom_highbd_calc_variance_stat avx2 avx512/;
+    } else {
+      specialize qw/aom_highbd_calc_variance_stat avx2/;
+    }
   }

   add_proto qw/uint64_t/, "aom_mse_16xh_16bit", "uint8_t *dst, int dstride,uint16_t *src, int w, int h";
@@ -1490,6 +1506,20 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
   specialize qw/aom_variance4x8       sse2      neon neon_dotprod/;
   specialize qw/aom_variance4x4       sse2      neon/;

+  if (aom_config("CONFIG_HIGHWAY") eq "yes") {
+    specialize qw/aom_variance128x128 avx512/;
+    specialize qw/aom_variance128x64  avx512/;
+    specialize qw/aom_variance64x128  avx512/;
+    specialize qw/aom_variance64x64   avx512/;
+    specialize qw/aom_variance64x32   avx512/;
+    specialize qw/aom_variance32x64   avx512/;
+    specialize qw/aom_variance32x32   avx512/;
+    specialize qw/aom_variance32x16   avx512/;
+    specialize qw/aom_variance16x32   avx512/;
+    specialize qw/aom_variance16x16   avx512/;
+    specialize qw/aom_variance16x8    avx512/;
+  }
+
   specialize qw/aom_sub_pixel_variance128x128   avx2 neon neon_dotprod/, "$ssse3_asm";
   specialize qw/aom_sub_pixel_variance128x64    avx2 neon neon_dotprod/, "$ssse3_asm";
   specialize qw/aom_sub_pixel_variance64x128    avx2 neon neon_dotprod/, "$ssse3_asm";
@@ -1532,6 +1562,13 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
     specialize qw/aom_variance16x64 neon neon_dotprod sse2 avx2/;
     specialize qw/aom_variance64x16 neon neon_dotprod sse2 avx2/;

+    if (aom_config("CONFIG_HIGHWAY") eq "yes") {
+      specialize qw/aom_variance16x4  avx512/;
+      specialize qw/aom_variance32x8  avx512/;
+      specialize qw/aom_variance16x64 avx512/;
+      specialize qw/aom_variance64x16 avx512/;
+    }
+
     specialize qw/aom_sub_pixel_variance4x16 neon neon_dotprod/, "$ssse3_asm";
     specialize qw/aom_sub_pixel_variance16x4 neon neon_dotprod avx2/, "$ssse3_asm";
     specialize qw/aom_sub_pixel_variance8x32 neon neon_dotprod/, "$ssse3_asm";
diff --git a/aom_dsp/variance_hwy.h b/aom_dsp/variance_hwy.h
new file mode 100644
index 0000000000..73d2cd09d3
--- /dev/null
+++ b/aom_dsp/variance_hwy.h
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 2026, Alliance for Open Media. All rights reserved.
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#ifndef AOM_AOM_DSP_VARIANCE_HWY_H_
+#define AOM_AOM_DSP_VARIANCE_HWY_H_
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "config/aom_config.h"
+#include "config/aom_dsp_rtcd.h"
+
+#include "aom_dsp/reduce_sum_hwy.h"
+#include "third_party/highway/hwy/highway.h"
+
+HWY_BEFORE_NAMESPACE();
+
+namespace {
+namespace HWY_NAMESPACE {
+
+namespace hn = hwy::HWY_NAMESPACE;
+
+template <class D, class VHalf>
+HWY_ATTR HWY_INLINE hn::VFromD<D> Combine2Rows(D d, VHalf r0, VHalf r1) {
+  HWY_IF_CONSTEXPR(hn::MaxLanes(d) * sizeof(hn::TFromD<D>) >= 32) {
+    return hn::ConcatLowerLower(d, hn::ResizeBitCast(d, r1),
+                                hn::ResizeBitCast(d, r0));
+  }
+  return hn::Combine(d, r1, r0);
+}
+
+template <class D, class VQuarter>
+HWY_ATTR HWY_INLINE hn::VFromD<D> Combine4Rows(D d, VQuarter r0, VQuarter r1,
+                                               VQuarter r2, VQuarter r3) {
+  HWY_IF_CONSTEXPR(hn::MaxLanes(d) * sizeof(hn::TFromD<D>) == 64) {
+    auto v = hn::ResizeBitCast(d, r0);
+    v = hn::InsertBlock<1>(v, r1);
+    v = hn::InsertBlock<2>(v, r2);
+    return hn::InsertBlock<3>(v, r3);
+  }
+  constexpr hn::Half<D> d_half;
+  auto r01 = Combine2Rows(d_half, r0, r1);
+  auto r23 = Combine2Rows(d_half, r2, r3);
+  return Combine2Rows(d, r01, r23);
+}
+
+template <int RowsPerVec, class D>
+HWY_ATTR HWY_INLINE hn::VFromD<D> LoadRowsU(D full_tag,
+                                            const hn::TFromD<D> *ptr,
+                                            ptrdiff_t stride) {
+  HWY_IF_CONSTEXPR(RowsPerVec == 4) {
+    constexpr hn::Half<hn::Half<D>> row_tag;
+    const hn::TFromD<D> *ptr2 = ptr + stride * 2;
+    return Combine4Rows(
+        full_tag, hn::LoadU(row_tag, ptr), hn::LoadU(row_tag, ptr + stride),
+        hn::LoadU(row_tag, ptr2), hn::LoadU(row_tag, ptr2 + stride));
+  }
+  HWY_IF_CONSTEXPR(RowsPerVec == 2) {
+    constexpr hn::Half<D> row_tag;
+    return Combine2Rows(full_tag, hn::LoadU(row_tag, ptr),
+                        hn::LoadU(row_tag, ptr + stride));
+  }
+  return hn::LoadU(full_tag, ptr);
+}
+
+template <class DU8, class DI32, class DI16>
+HWY_ATTR HWY_INLINE void VarianceKernel(DU8 du8, DI32 di32, DI16 di16,
+                                        hn::VFromD<DU8> src,
+                                        hn::VFromD<DU8> ref,
+                                        hn::VFromD<DI32> *sse,
+                                        hn::VFromD<DI16> *sum) {
+  constexpr hn::Repartition<int8_t, DU8> di8;
+  const auto adj_sub =
+      hn::BitCast(di8, hn::Set(di16, static_cast<int16_t>(0xff01)));
+  const auto s_lo = hn::InterleaveLower(du8, src, ref);
+  const auto s_hi = hn::InterleaveUpper(du8, src, ref);
+  const auto diff_lo = hn::SatWidenMulPairwiseAdd(di16, s_lo, adj_sub);
+  const auto diff_hi = hn::SatWidenMulPairwiseAdd(di16, s_hi, adj_sub);
+
+  *sum = hn::Add(*sum, hn::Add(diff_lo, diff_hi));
+  const auto madd_lo = hn::WidenMulPairwiseAdd(di32, diff_lo, diff_lo);
+  const auto madd_hi = hn::WidenMulPairwiseAdd(di32, diff_hi, diff_hi);
+  *sse = hn::Add(*sse, hn::Add(madd_lo, madd_hi));
+}
+
+template <class DI32>
+HWY_ATTR HWY_INLINE int VarianceFinalFrom32BitSum(DI32 di32,
+                                                  hn::VFromD<DI32> vsse,
+                                                  hn::VFromD<DI32> vsum32,
+                                                  unsigned int *const sse) {
+  constexpr hn::BlockDFromD<DI32> d128;
+  const auto sse128 = BlockReduceSum(di32, vsse);
+  const auto sum128 = BlockReduceSum(di32, vsum32);
+  const auto pair0 = hn::InterleaveLower(d128, sse128, sum128);
+  const auto pair1 = hn::InterleaveUpper(d128, sse128, sum128);
+  const auto sum_pair = hn::Add(pair0, pair1);
+  constexpr hn::FixedTag<int32_t, 2> d64;
+  const auto res =
+      hn::Add(hn::LowerHalf(d64, sum_pair), hn::UpperHalf(d64, sum_pair));
+  *sse = static_cast<unsigned int>(hn::GetLane(res));
+  return hn::ExtractLane(res, 1);
+}
+
+template <class DI32, class DI16>
+HWY_ATTR HWY_INLINE int VarianceFinalFrom16BitSum(DI32 di32, DI16 di16,
+                                                  hn::VFromD<DI32> vsse,
+                                                  hn::VFromD<DI16> vsum,
+                                                  unsigned int *const sse) {
+  const auto one = hn::Set(di16, int16_t{ 1 });
+  const auto vsum32 = hn::WidenMulPairwiseAdd(di32, vsum, one);
+  return VarianceFinalFrom32BitSum(di32, vsse, vsum32, sse);
+}
+
+template <int BlockWidth>
+HWY_ATTR HWY_INLINE void VarianceBlock(
+    const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride,
+    int h, hn::Vec<hn::ScalableTag<int32_t>> *vsse,
+    hn::Vec<hn::ScalableTag<int16_t>> *vsum) {
+  constexpr hn::ScalableTag<uint8_t> du8;
+  constexpr hn::ScalableTag<int16_t> di16;
+  constexpr hn::ScalableTag<int32_t> di32;
+  constexpr int vw = hn::MaxLanes(du8);
+  constexpr int kRowsPerVec = (BlockWidth < vw) ? (vw / BlockWidth) : 1;
+  constexpr int kRowSpan = (BlockWidth < vw) ? vw : BlockWidth;
+  assert(h % kRowsPerVec == 0);
+
+  *vsum = hn::Zero(di16);
+  for (int i = 0; i < h; i += kRowsPerVec) {
+    for (int j = 0; j < kRowSpan; j += vw) {
+      const auto s = LoadRowsU<kRowsPerVec>(du8, src + j, src_stride);
+      const auto r = LoadRowsU<kRowsPerVec>(du8, ref + j, ref_stride);
+      VarianceKernel(du8, di32, di16, s, r, vsse, vsum);
+    }
+    src += kRowsPerVec * src_stride;
+    ref += kRowsPerVec * ref_stride;
+  }
+}
+
+template <int BlockWidth, int BlockHeight>
+HWY_ATTR HWY_INLINE void GetBlockVar(const uint8_t *src, int src_stride,
+                                     const uint8_t *ref, int ref_stride,
+                                     unsigned int *sse, int *sum) {
+  constexpr hn::ScalableTag<uint8_t> du8;
+  constexpr hn::ScalableTag<int16_t> di16;
+  constexpr hn::ScalableTag<int32_t> di32;
+  constexpr int vw = hn::MaxLanes(du8);
+  constexpr int kRowsPerVec = (BlockWidth < vw) ? (vw / BlockWidth) : 1;
+  // Each int16_t lane in vsum accumulates 2 pixel diffs per iteration of vw
+  // bytes. With 128 diffs per lane (128 * 255 = 32640 <= 32767), we can safely
+  // accumulate up to 64 * vw pixels before widening vsum to 32-bit.
+  constexpr int kMaxPixelsPerChunk = 64 * vw;
+  constexpr int kChunkHeight = (BlockWidth * BlockHeight <= kMaxPixelsPerChunk)
+                                   ? BlockHeight
+                                   : (kMaxPixelsPerChunk / BlockWidth);
+  static_assert(BlockHeight % kRowsPerVec == 0,
+                "BlockHeight must be a multiple of kRowsPerVec.");
+  static_assert(BlockHeight % kChunkHeight == 0,
+                "BlockHeight must be a multiple of kChunkHeight.");
+  static_assert(kChunkHeight % kRowsPerVec == 0,
+                "kChunkHeight must be a multiple of kRowsPerVec.");
+
+  auto vsse = hn::Zero(di32);
+  HWY_IF_CONSTEXPR(kChunkHeight == BlockHeight) {
+    hn::Vec<decltype(di16)> vsum;
+    VarianceBlock<BlockWidth>(src, src_stride, ref, ref_stride, BlockHeight,
+                              &vsse, &vsum);
+    *sum = VarianceFinalFrom16BitSum(di32, di16, vsse, vsum, sse);
+  }
+  HWY_IF_CONSTEXPR(kChunkHeight != BlockHeight) {
+    auto vsum32 = hn::Zero(di32);
+    const auto one = hn::Set(di16, int16_t{ 1 });
+    for (int i = 0; i < BlockHeight / kChunkHeight; ++i) {
+      hn::Vec<decltype(di16)> vsum16;
+      VarianceBlock<BlockWidth>(src, src_stride, ref, ref_stride, kChunkHeight,
+                                &vsse, &vsum16);
+      vsum32 = hn::Add(vsum32, hn::WidenMulPairwiseAdd(di32, vsum16, one));
+      src += kChunkHeight * src_stride;
+      ref += kChunkHeight * ref_stride;
+    }
+    *sum = VarianceFinalFrom32BitSum(di32, vsse, vsum32, sse);
+  }
+}
+
+template <int BlockWidth, int BlockHeight, int Bits>
+HWY_ATTR HWY_INLINE unsigned int VarianceWxH(const uint8_t *src, int src_stride,
+                                             const uint8_t *ref, int ref_stride,
+                                             unsigned int *sse) {
+  int sum = 0;
+  GetBlockVar<BlockWidth, BlockHeight>(src, src_stride, ref, ref_stride, sse,
+                                       &sum);
+  return *sse -
+         static_cast<unsigned int>((static_cast<int64_t>(sum) * sum) >> Bits);
+}
+
+HWY_ATTR HWY_INLINE void GetBlkSseSum(const int16_t *data, int stride, int bw,
+                                      int bh, int *x_sum, int64_t *x2_sum) {
+  constexpr hn::ScalableTag<int16_t> di16;
+  constexpr hn::ScalableTag<int32_t> di32;
+  constexpr hn::ScalableTag<uint32_t> du32;
+  constexpr hn::ScalableTag<uint64_t> du64;
+  constexpr int kLanes = hn::MaxLanes(di16);
+
+  if (bw <= 0 || bh <= 0) {
+    *x_sum = 0;
+    *x2_sum = 0;
+    return;
+  }
+  if (bw < kLanes || bw % kLanes != 0) {
+    aom_get_blk_sse_sum_avx2(data, stride, bw, bh, x_sum, x2_sum);
+    return;
+  }
+
+  const auto one = hn::Set(di16, int16_t{ 1 });
+  auto sum_32 = hn::Zero(di32);
+  auto sse_64 = hn::Zero(du64);
+
+  for (int i = 0; i < bh; ++i) {
+    for (int j = 0; j < bw; j += kLanes) {
+      const auto d = hn::LoadU(di16, data + j);
+      sum_32 = hn::Add(sum_32, hn::WidenMulPairwiseAdd(di32, d, one));
+      const auto sq = hn::BitCast(du32, hn::WidenMulPairwiseAdd(di32, d, d));
+      const auto sq_lo = hn::PromoteLowerTo(du64, sq);
+      const auto sq_hi = hn::PromoteUpperTo(du64, sq);
+      sse_64 = hn::Add(sse_64, hn::Add(sq_lo, sq_hi));
+    }
+    data += stride;
+  }
+  *x_sum = static_cast<int>(hn::ReduceSum(di32, sum_32));
+  *x2_sum = static_cast<int64_t>(hn::ReduceSum(du64, sse_64));
+}
+
+HWY_ATTR HWY_INLINE void LoadRowHorizFilterU8(
+    const uint8_t *src_row, int x, int bw,
+    hn::Vec<hn::ScalableTag<int16_t>> *u16_curr_out,
+    hn::Vec<hn::ScalableTag<int16_t>> *u16_H_out) {
+  constexpr hn::ScalableTag<int16_t> di16;
+  constexpr hn::Rebind<uint8_t, decltype(di16)> du8_half;
+  constexpr int kCols = hn::MaxLanes(du8_half);
+  static_assert(kCols == 16 || kCols == 32, "kCols must be 16 or 32.");
+  alignas(64) static constexpr int16_t kLeftIdx[32] = {
+    0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14,
+    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30
+  };
+  alignas(64) static constexpr int16_t kRightIdx32[32] = {
+    1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16,
+    17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 31
+  };
+  alignas(32) static constexpr int16_t kRightIdx16[16] = {
+    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15
+  };
+
+  const auto u16_curr = hn::PromoteTo(di16, hn::LoadU(du8_half, src_row + x));
+  hn::Vec<decltype(di16)> u16_left;
+  hn::Vec<decltype(di16)> u16_right;
+
+  if (x == 0) {
+    u16_left =
+        hn::TableLookupLanes(u16_curr, hn::SetTableIndices(di16, kLeftIdx));
+  } else {
+    u16_left = hn::PromoteTo(di16, hn::LoadU(du8_half, src_row + x - 1));
+  }
+
+  if (x + kCols < bw) {
+    u16_right = hn::PromoteTo(di16, hn::LoadU(du8_half, src_row + x + 1));
+  } else {
+    const int16_t *right_idx = (kCols == 32) ? kRightIdx32 : kRightIdx16;
+    u16_right =
+        hn::TableLookupLanes(u16_curr, hn::SetTableIndices(di16, right_idx));
+  }
+
+  *u16_curr_out = u16_curr;
+  *u16_H_out =
+      hn::Add(hn::Add(u16_left, u16_right), hn::ShiftLeft<1>(u16_curr));
+}
+
+HWY_ATTR HWY_INLINE int64_t CalcVarianceStat(const uint8_t *src, int stride,
+                                             int bw, int bh) {
+  constexpr hn::ScalableTag<int16_t> di16;
+  constexpr hn::ScalableTag<int32_t> di32;
+  constexpr int kCols = hn::MaxLanes(di16);
+
+  if (bw <= 0 || bh <= 0) return 0;
+  if (bw == 4 || bw == 8 || bw == 16) {
+    return aom_calc_variance_stat_avx2(src, stride, bw, bh);
+  }
+  if (bw % kCols != 0) {
+    return aom_calc_variance_stat_c(src, stride, bw, bh);
+  }
+
+  auto acc_var = hn::Zero(di32);
+
+  for (int x = 0; x < bw; x += kCols) {
+    hn::Vec<decltype(di16)> u16_curr, H_curr;
+    LoadRowHorizFilterU8(src, x, bw, &u16_curr, &H_curr);
+    auto H_top = H_curr;
+
+    for (int y = 0; y < bh - 1; ++y) {
+      hn::Vec<decltype(di16)> u16_next, H_bot;
+      LoadRowHorizFilterU8(src + (y + 1) * stride, x, bw, &u16_next, &H_bot);
+      const auto u16_V =
+          hn::Add(hn::Add(H_top, H_bot), hn::ShiftLeft<1>(H_curr));
+      const auto u16_sum = hn::ShiftRight<4>(u16_V);
+      const auto diff = hn::Sub(u16_curr, u16_sum);
+      acc_var = hn::Add(acc_var, hn::WidenMulPairwiseAdd(di32, diff, diff));
+      H_top = H_curr;
+      H_curr = H_bot;
+      u16_curr = u16_next;
+    }
+    {
+      const auto u16_V =
+          hn::Add(hn::Add(H_top, H_curr), hn::ShiftLeft<1>(H_curr));
+      const auto u16_sum = hn::ShiftRight<4>(u16_V);
+      const auto diff = hn::Sub(u16_curr, u16_sum);
+      acc_var = hn::Add(acc_var, hn::WidenMulPairwiseAdd(di32, diff, diff));
+    }
+  }
+  return static_cast<int64_t>(hn::ReduceSum(di32, acc_var)) << 4;
+}
+
+#if CONFIG_AV1_HIGHBITDEPTH
+HWY_ATTR HWY_INLINE void HighbdLoadRowHorizFilterU16(
+    const uint16_t *src_row, int x, int bw,
+    hn::Vec<hn::ScalableTag<int16_t>> *v_curr_out,
+    hn::Vec<hn::ScalableTag<uint16_t>> *u16_H_out) {
+  constexpr hn::ScalableTag<uint16_t> du16;
+  constexpr hn::ScalableTag<int16_t> di16;
+  constexpr int kCols = hn::MaxLanes(du16);
+  static_assert(kCols == 16 || kCols == 32, "kCols must be 16 or 32.");
+  alignas(64) static constexpr uint16_t kLeftIdx[32] = {
+    0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14,
+    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30
+  };
+  alignas(64) static constexpr uint16_t kRightIdx32[32] = {
+    1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16,
+    17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 31
+  };
+  alignas(32) static constexpr uint16_t kRightIdx16[16] = {
+    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15
+  };
+
+  const auto v_curr = hn::LoadU(du16, src_row + x);
+  // Input pixels must be <= 4095 (12-bit) so that the 3x3 Gaussian filter sum
+  // u16_V = H_top + 2 * H_curr + H_bot <= 16 * 4095 = 65520 fits in uint16_t.
+  assert(hn::AllTrue(du16, hn::Le(v_curr, hn::Set(du16, uint16_t{ 4095 }))));
+  hn::Vec<decltype(du16)> v_left;
+  hn::Vec<decltype(du16)> v_right;
+
+  if (x == 0) {
+    v_left = hn::TableLookupLanes(v_curr, hn::SetTableIndices(du16, kLeftIdx));
+  } else {
+    v_left = hn::LoadU(du16, src_row + x - 1);
+  }
+
+  if (x + kCols < bw) {
+    v_right = hn::LoadU(du16, src_row + x + 1);
+  } else {
+    const uint16_t *right_idx = (kCols == 32) ? kRightIdx32 : kRightIdx16;
+    v_right =
+        hn::TableLookupLanes(v_curr, hn::SetTableIndices(du16, right_idx));
+  }
+
+  *v_curr_out = hn::BitCast(di16, v_curr);
+  *u16_H_out = hn::Add(hn::Add(v_left, v_right), hn::ShiftLeft<1>(v_curr));
+}
+
+// Assumes 8/10/12-bit input pixels (src[i] <= 4095) so that the 16-weight 3x3
+// Gaussian filter sum (<= 65520) does not overflow uint16_t.
+HWY_ATTR HWY_INLINE int64_t HighbdCalcVarianceStat(const uint16_t *src,
+                                                   int stride, int bw, int bh) {
+  constexpr hn::ScalableTag<uint16_t> du16;
+  constexpr hn::ScalableTag<int16_t> di16;
+  constexpr hn::ScalableTag<int32_t> di32;
+  constexpr hn::ScalableTag<int64_t> di64;
+  constexpr int kCols = hn::MaxLanes(du16);
+
+  if (bw <= 0 || bh <= 0) return 0;
+  if (bw == 4 || bw == 8 || bw == 16) {
+    return aom_highbd_calc_variance_stat_avx2(src, stride, bw, bh);
+  }
+  if (bw % kCols != 0) {
+    return aom_highbd_calc_variance_stat_c(src, stride, bw, bh);
+  }
+
+  auto acc_var_64 = hn::Zero(di64);
+
+  for (int x = 0; x < bw; x += kCols) {
+    hn::Vec<decltype(di16)> v_curr;
+    hn::Vec<decltype(du16)> H_curr;
+    HighbdLoadRowHorizFilterU16(src, x, bw, &v_curr, &H_curr);
+    auto H_top = H_curr;
+
+    for (int y = 0; y < bh - 1; ++y) {
+      hn::Vec<decltype(di16)> v_next;
+      hn::Vec<decltype(du16)> H_bot;
+      HighbdLoadRowHorizFilterU16(src + (y + 1) * stride, x, bw, &v_next,
+                                  &H_bot);
+      const auto u16_V =
+          hn::Add(hn::Add(H_top, H_bot), hn::ShiftLeft<1>(H_curr));
+      const auto u16_sum = hn::BitCast(di16, hn::ShiftRight<4>(u16_V));
+      const auto diff = hn::Sub(v_curr, u16_sum);
+      const auto diff_sq = hn::WidenMulPairwiseAdd(di32, diff, diff);
+      acc_var_64 =
+          hn::Add(acc_var_64, hn::Add(hn::PromoteLowerTo(di64, diff_sq),
+                                      hn::PromoteUpperTo(di64, diff_sq)));
+      H_top = H_curr;
+      H_curr = H_bot;
+      v_curr = v_next;
+    }
+    {
+      const auto u16_V =
+          hn::Add(hn::Add(H_top, H_curr), hn::ShiftLeft<1>(H_curr));
+      const auto u16_sum = hn::BitCast(di16, hn::ShiftRight<4>(u16_V));
+      const auto diff = hn::Sub(v_curr, u16_sum);
+      const auto diff_sq = hn::WidenMulPairwiseAdd(di32, diff, diff);
+      acc_var_64 =
+          hn::Add(acc_var_64, hn::Add(hn::PromoteLowerTo(di64, diff_sq),
+                                      hn::PromoteUpperTo(di64, diff_sq)));
+    }
+  }
+  return static_cast<int64_t>(hn::ReduceSum(di64, acc_var_64)) << 4;
+}
+#endif  // CONFIG_AV1_HIGHBITDEPTH
+
+}  // namespace HWY_NAMESPACE
+}  // namespace
+
+#define FVAR(w, h, bits, suffix)                                              \
+  extern "C" unsigned int aom_variance##w##x##h##_##suffix(                   \
+      const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, \
+      unsigned int *sse);                                                     \
+  HWY_ATTR unsigned int aom_variance##w##x##h##_##suffix(                     \
+      const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, \
+      unsigned int *sse) {                                                    \
+    return HWY_NAMESPACE::VarianceWxH<w, h, bits>(src, src_stride, ref,       \
+                                                  ref_stride, sse);           \
+  }
+
+#define FMSE16X16(suffix)                                                     \
+  extern "C" unsigned int aom_mse16x16_##suffix(                              \
+      const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, \
+      unsigned int *sse);                                                     \
+  HWY_ATTR unsigned int aom_mse16x16_##suffix(                                \
+      const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, \
+      unsigned int *sse) {                                                    \
+    int sum = 0;                                                              \
+    HWY_NAMESPACE::GetBlockVar<16, 16>(src, src_stride, ref, ref_stride, sse, \
+                                       &sum);                                 \
+    return *sse;                                                              \
+  }
+
+#define FGET_BLK_SSE_SUM(suffix)                                              \
+  extern "C" void aom_get_blk_sse_sum_##suffix(const int16_t *data,           \
+                                               int stride, int bw, int bh,    \
+                                               int *x_sum, int64_t *x2_sum);  \
+  HWY_ATTR void aom_get_blk_sse_sum_##suffix(const int16_t *data, int stride, \
+                                             int bw, int bh, int *x_sum,      \
+                                             int64_t *x2_sum) {               \
+    HWY_NAMESPACE::GetBlkSseSum(data, stride, bw, bh, x_sum, x2_sum);         \
+  }
+
+#if CONFIG_AV1_HIGHBITDEPTH
+#define FHIGHBD_CALC_VAR_STAT(suffix)                                  \
+  extern "C" int64_t aom_highbd_calc_variance_stat_##suffix(           \
+      const uint16_t *src, int stride, int bw, int bh);                \
+  HWY_ATTR int64_t aom_highbd_calc_variance_stat_##suffix(             \
+      const uint16_t *src, int stride, int bw, int bh) {               \
+    return HWY_NAMESPACE::HighbdCalcVarianceStat(src, stride, bw, bh); \
+  }
+#else
+#define FHIGHBD_CALC_VAR_STAT(suffix)
+#endif
+
+#define FCALC_VAR_STAT(suffix)                                   \
+  extern "C" int64_t aom_calc_variance_stat_##suffix(            \
+      const uint8_t *src, int stride, int bw, int bh);           \
+  HWY_ATTR int64_t aom_calc_variance_stat_##suffix(              \
+      const uint8_t *src, int stride, int bw, int bh) {          \
+    return HWY_NAMESPACE::CalcVarianceStat(src, stride, bw, bh); \
+  }                                                              \
+  FHIGHBD_CALC_VAR_STAT(suffix)
+
+#if !CONFIG_REALTIME_ONLY
+#define FOR_EACH_VAR_RECT_BLOCK_SIZE(X, suffix) \
+  X(64, 16, 10, suffix)                         \
+  X(32, 8, 8, suffix)                           \
+  X(16, 64, 10, suffix)                         \
+  X(16, 4, 6, suffix)
+#else
+#define FOR_EACH_VAR_RECT_BLOCK_SIZE(X, suffix)
+#endif
+
+#define FOR_EACH_VAR_BLOCK_SIZE(X, suffix) \
+  X(128, 128, 14, suffix)                  \
+  X(128, 64, 13, suffix)                   \
+  X(64, 128, 13, suffix)                   \
+  X(64, 64, 12, suffix)                    \
+  X(64, 32, 11, suffix)                    \
+  X(32, 64, 11, suffix)                    \
+  X(32, 32, 10, suffix)                    \
+  X(32, 16, 9, suffix)                     \
+  X(16, 32, 9, suffix)                     \
+  X(16, 16, 8, suffix)                     \
+  X(16, 8, 7, suffix)                      \
+  FOR_EACH_VAR_RECT_BLOCK_SIZE(X, suffix)
+
+HWY_AFTER_NAMESPACE();
+
+#endif  // AOM_AOM_DSP_VARIANCE_HWY_H_
diff --git a/aom_dsp/x86/variance_hwy_avx512.cc b/aom_dsp/x86/variance_hwy_avx512.cc
new file mode 100644
index 0000000000..8532c333bb
--- /dev/null
+++ b/aom_dsp/x86/variance_hwy_avx512.cc
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2026, Alliance for Open Media. All rights reserved.
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#define HWY_BASELINE_TARGETS HWY_AVX3_DL
+#define HWY_BROKEN_32BIT 0
+
+#include "aom_dsp/variance_hwy.h"
+
+FOR_EACH_VAR_BLOCK_SIZE(FVAR, avx512)
+FMSE16X16(avx512)
+FGET_BLK_SSE_SUM(avx512)
+FCALC_VAR_STAT(avx512)
diff --git a/test/sum_squares_test.cc b/test/sum_squares_test.cc
index 309912f3c1..60959a266f 100644
--- a/test/sum_squares_test.cc
+++ b/test/sum_squares_test.cc
@@ -594,7 +594,7 @@ TEST_P(SSE_Sum_Test, ExtremeValues) { RunTest(false, GET_PARAM(1), 1); }

 TEST_P(SSE_Sum_Test, DISABLED_Speed) { RunTest(true, GET_PARAM(1), 10000); }

-#if HAVE_SSE2 || HAVE_AVX2 || HAVE_NEON
+#if HAVE_SSE2 || HAVE_AVX2 || (CONFIG_HIGHWAY && HAVE_AVX512) || HAVE_NEON
 const TX_SIZE kValidBlockSize[] = { TX_4X4,   TX_8X8,   TX_16X16, TX_32X32,
                                     TX_64X64, TX_4X8,   TX_8X4,   TX_8X16,
                                     TX_16X8,  TX_16X32, TX_32X16, TX_64X32,
@@ -618,6 +618,14 @@ INSTANTIATE_TEST_SUITE_P(AVX2, SSE_Sum_Test,
                                  ValuesIn(kValidBlockSize)));
 #endif  // HAVE_AVX2

+#if CONFIG_HIGHWAY && HAVE_AVX512
+TestSSE_SumFuncs sse_sum_avx512[] = { TestSSE_SumFuncs(
+    &aom_get_blk_sse_sum_c, &aom_get_blk_sse_sum_avx512) };
+INSTANTIATE_TEST_SUITE_P(AVX512, SSE_Sum_Test,
+                         Combine(ValuesIn(sse_sum_avx512),
+                                 ValuesIn(kValidBlockSize)));
+#endif  // CONFIG_HIGHWAY && HAVE_AVX512
+
 #if HAVE_NEON
 TestSSE_SumFuncs sse_sum_neon[] = { TestSSE_SumFuncs(
     &aom_get_blk_sse_sum_c, &aom_get_blk_sse_sum_neon) };
diff --git a/test/variance_test.cc b/test/variance_test.cc
index 781f57446e..abf109491e 100644
--- a/test/variance_test.cc
+++ b/test/variance_test.cc
@@ -3868,7 +3868,7 @@ INSTANTIATE_TEST_SUITE_P(SVE, AvxHBDVarianceTest,
 #endif  // CONFIG_AV1_HIGHBITDEPTH
 #endif  // HAVE_SVE

-#if HAVE_AVX2
+#if HAVE_AVX2 || (CONFIG_HIGHWAY && HAVE_AVX512)
 using CalcVarianceStatFunc = int64_t (*)(const uint8_t *src, int stride, int bw,
                                          int bh);

@@ -3906,8 +3906,10 @@ TEST_P(CalcVarianceStatTest, CompareWithC) {
   }
 }

+#if HAVE_AVX2
 INSTANTIATE_TEST_SUITE_P(AVX2, CalcVarianceStatTest,
                          ::testing::Values(&aom_calc_variance_stat_avx2));
+#endif  // HAVE_AVX2

 #if CONFIG_AV1_HIGHBITDEPTH
 using CalcVarianceStatHbdFunc = int64_t (*)(const uint16_t *src, int stride,
@@ -3947,10 +3949,49 @@ TEST_P(CalcVarianceStatHbdTest, CompareWithC) {
   }
 }

+#if HAVE_AVX2
 INSTANTIATE_TEST_SUITE_P(
     AVX2, CalcVarianceStatHbdTest,
     ::testing::Values(&aom_highbd_calc_variance_stat_avx2));
-#endif  // CONFIG_AV1_HIGHBITDEPTH
 #endif  // HAVE_AVX2
+#endif  // CONFIG_AV1_HIGHBITDEPTH
+#endif  // HAVE_AVX2 || (CONFIG_HIGHWAY && HAVE_AVX512)
+
+#if CONFIG_HIGHWAY && HAVE_AVX512
+INSTANTIATE_TEST_SUITE_P(AVX512, AvxMseTest,
+                         ::testing::Values(MseParams(4, 4,
+                                                     &aom_mse16x16_avx512)));
+
+const VarianceParams kArrayVariance_avx512[] = {
+  VarianceParams(7, 7, &aom_variance128x128_avx512),
+  VarianceParams(7, 6, &aom_variance128x64_avx512),
+  VarianceParams(6, 7, &aom_variance64x128_avx512),
+  VarianceParams(6, 6, &aom_variance64x64_avx512),
+  VarianceParams(6, 5, &aom_variance64x32_avx512),
+  VarianceParams(5, 6, &aom_variance32x64_avx512),
+  VarianceParams(5, 5, &aom_variance32x32_avx512),
+  VarianceParams(5, 4, &aom_variance32x16_avx512),
+  VarianceParams(4, 5, &aom_variance16x32_avx512),
+  VarianceParams(4, 4, &aom_variance16x16_avx512),
+  VarianceParams(4, 3, &aom_variance16x8_avx512),
+#if !CONFIG_REALTIME_ONLY
+  VarianceParams(6, 4, &aom_variance64x16_avx512),
+  VarianceParams(4, 6, &aom_variance16x64_avx512),
+  VarianceParams(5, 3, &aom_variance32x8_avx512),
+  VarianceParams(4, 2, &aom_variance16x4_avx512),
+#endif
+};
+INSTANTIATE_TEST_SUITE_P(AVX512, AvxVarianceTest,
+                         ::testing::ValuesIn(kArrayVariance_avx512));
+
+INSTANTIATE_TEST_SUITE_P(AVX512, CalcVarianceStatTest,
+                         ::testing::Values(&aom_calc_variance_stat_avx512));
+
+#if CONFIG_AV1_HIGHBITDEPTH
+INSTANTIATE_TEST_SUITE_P(
+    AVX512, CalcVarianceStatHbdTest,
+    ::testing::Values(&aom_highbd_calc_variance_stat_avx512));
+#endif  // CONFIG_AV1_HIGHBITDEPTH
+#endif  // CONFIG_HIGHWAY && HAVE_AVX512

 }  // namespace