| #!/usr/bin/env python3 |
| ## 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. |
| ## |
| # Precompute libaom AV1 wedge / inter-intra blending masks at codegen time |
| # so they can live in `.rdata` and be COW shared across processes instead |
| # of being computed at runtime into writable `.data` buffers. |
| # |
| # Output is a header fragment included by av1/common/reconinter.c that |
| # defines: |
| # - wedge_mask_obl (input to wedge_mask_buf generation) |
| # - wedge_mask_buf (compound prediction masks, indexed by offset) |
| # - smooth_interintra_mask_buf |
| # - wedge_masks (offsets into wedge_mask_buf) |
| # |
| # The algorithms in this file mirror init_wedge_master_masks(), |
| # init_wedge_masks() and init_smooth_interintra_masks() in |
| # av1/common/reconinter.c. They must stay in sync with that source. If those |
| # helpers, the master tables, the wedge codebooks, the block-size enum, or |
| # ii_weights1d ever change upstream, regenerate the .inc by running this |
| # script and committing the result. |
| # |
| # Regenerate: |
| # python3 source/libaom/tools/gen_wedge_masks_data.py |
| # --output source/libaom/av1/common/wedge_masks_data.inc |
| |
| import argparse |
| import os |
| import sys |
| import textwrap |
| |
| # ----------------------------------------------------------------------------- |
| # Constants (must match reconinter.h / enums.h). |
| # ----------------------------------------------------------------------------- |
| MAX_WEDGE_TYPES = 16 |
| MAX_WEDGE_SIZE_LOG2 = 5 |
| MAX_WEDGE_SIZE = 1 << MAX_WEDGE_SIZE_LOG2 # 32 |
| MAX_WEDGE_SQUARE = MAX_WEDGE_SIZE * MAX_WEDGE_SIZE # 1024 |
| MASK_MASTER_SIZE = MAX_WEDGE_SIZE << 1 # 64 |
| MASK_MASTER_STRIDE = MASK_MASTER_SIZE |
| WEDGE_WEIGHT_BITS = 6 |
| INTERINTRA_MODES = 4 |
| MAX_SB_SIZE_LOG2 = 7 |
| MAX_SB_SIZE = 1 << MAX_SB_SIZE_LOG2 # 128 |
| |
| # WedgeDirectionType. |
| WEDGE_HORIZONTAL = 0 |
| WEDGE_VERTICAL = 1 |
| WEDGE_OBLIQUE27 = 2 |
| WEDGE_OBLIQUE63 = 3 |
| WEDGE_OBLIQUE117 = 4 |
| WEDGE_OBLIQUE153 = 5 |
| WEDGE_DIRECTIONS = 6 |
| |
| # BLOCK_SIZE enum order (must match enums.h). |
| BLOCK_NAMES = [ |
| "BLOCK_4X4", "BLOCK_4X8", "BLOCK_8X4", "BLOCK_8X8", |
| "BLOCK_8X16", "BLOCK_16X8", "BLOCK_16X16", "BLOCK_16X32", |
| "BLOCK_32X16", "BLOCK_32X32", "BLOCK_32X64", "BLOCK_64X32", |
| "BLOCK_64X64", "BLOCK_64X128", "BLOCK_128X64", "BLOCK_128X128", |
| "BLOCK_4X16", "BLOCK_16X4", "BLOCK_8X32", "BLOCK_32X8", |
| "BLOCK_16X64", "BLOCK_64X16", |
| ] |
| BLOCK_SIZES_ALL = len(BLOCK_NAMES) |
| |
| |
| def _parse_block_dims(name): |
| # e.g. "BLOCK_8X16" -> (8, 16) |
| body = name.split("_", 1)[1] |
| w, h = body.split("X") |
| return int(w), int(h) |
| |
| |
| BLOCK_WIDTH = [_parse_block_dims(n)[0] for n in BLOCK_NAMES] |
| BLOCK_HEIGHT = [_parse_block_dims(n)[1] for n in BLOCK_NAMES] |
| |
| |
| def _bi(name): |
| return BLOCK_NAMES.index(name) |
| |
| |
| # Inter-intra modes (must match enums.h). |
| II_DC_PRED, II_V_PRED, II_H_PRED, II_SMOOTH_PRED = 0, 1, 2, 3 |
| |
| |
| # ----------------------------------------------------------------------------- |
| # Master mask tables (see wedge_master_oblique_odd / _even / _vertical in |
| # av1/common/reconinter.c). |
| # ----------------------------------------------------------------------------- |
| WEDGE_MASTER_OBLIQUE_ODD = [ |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 6, 18, |
| 37, 53, 60, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
| 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
| ] |
| WEDGE_MASTER_OBLIQUE_EVEN = [ |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 11, 27, |
| 46, 58, 62, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
| 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
| ] |
| WEDGE_MASTER_VERTICAL = [ |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 7, 21, |
| 43, 57, 62, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
| 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
| ] |
| |
| # wedge_signflip_lookup (see av1/common/reconinter.c). |
| WEDGE_SIGNFLIP_LOOKUP = [ |
| [0]*16, [0]*16, [0]*16, |
| [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1], # BLOCK_8X8 |
| [1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1], # BLOCK_8X16 |
| [1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1], # BLOCK_16X8 |
| [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1], # BLOCK_16X16 |
| [1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1], # BLOCK_16X32 |
| [1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1], # BLOCK_32X16 |
| [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1], # BLOCK_32X32 |
| [0]*16, [0]*16, [0]*16, [0]*16, [0]*16, [0]*16, [0]*16, [0]*16, |
| [1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1], # BLOCK_8X32 |
| [1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1], # BLOCK_32X8 |
| [0]*16, [0]*16, |
| ] |
| assert len(WEDGE_SIGNFLIP_LOOKUP) == BLOCK_SIZES_ALL |
| |
| |
| # Wedge codebooks (see wedge_codebook_16_* in av1/common/reconinter.c). |
| # Each entry is |
| # (direction, x_offset, y_offset). |
| WEDGE_CODEBOOK_16_HGTW = [ |
| (WEDGE_OBLIQUE27, 4, 4), (WEDGE_OBLIQUE63, 4, 4), |
| (WEDGE_OBLIQUE117, 4, 4), (WEDGE_OBLIQUE153, 4, 4), |
| (WEDGE_HORIZONTAL, 4, 2), (WEDGE_HORIZONTAL, 4, 4), |
| (WEDGE_HORIZONTAL, 4, 6), (WEDGE_VERTICAL, 4, 4), |
| (WEDGE_OBLIQUE27, 4, 2), (WEDGE_OBLIQUE27, 4, 6), |
| (WEDGE_OBLIQUE153, 4, 2), (WEDGE_OBLIQUE153, 4, 6), |
| (WEDGE_OBLIQUE63, 2, 4), (WEDGE_OBLIQUE63, 6, 4), |
| (WEDGE_OBLIQUE117, 2, 4), (WEDGE_OBLIQUE117, 6, 4), |
| ] |
| WEDGE_CODEBOOK_16_HLTW = [ |
| (WEDGE_OBLIQUE27, 4, 4), (WEDGE_OBLIQUE63, 4, 4), |
| (WEDGE_OBLIQUE117, 4, 4), (WEDGE_OBLIQUE153, 4, 4), |
| (WEDGE_VERTICAL, 2, 4), (WEDGE_VERTICAL, 4, 4), |
| (WEDGE_VERTICAL, 6, 4), (WEDGE_HORIZONTAL, 4, 4), |
| (WEDGE_OBLIQUE27, 4, 2), (WEDGE_OBLIQUE27, 4, 6), |
| (WEDGE_OBLIQUE153, 4, 2), (WEDGE_OBLIQUE153, 4, 6), |
| (WEDGE_OBLIQUE63, 2, 4), (WEDGE_OBLIQUE63, 6, 4), |
| (WEDGE_OBLIQUE117, 2, 4), (WEDGE_OBLIQUE117, 6, 4), |
| ] |
| WEDGE_CODEBOOK_16_HEQW = [ |
| (WEDGE_OBLIQUE27, 4, 4), (WEDGE_OBLIQUE63, 4, 4), |
| (WEDGE_OBLIQUE117, 4, 4), (WEDGE_OBLIQUE153, 4, 4), |
| (WEDGE_HORIZONTAL, 4, 2), (WEDGE_HORIZONTAL, 4, 6), |
| (WEDGE_VERTICAL, 2, 4), (WEDGE_VERTICAL, 6, 4), |
| (WEDGE_OBLIQUE27, 4, 2), (WEDGE_OBLIQUE27, 4, 6), |
| (WEDGE_OBLIQUE153, 4, 2), (WEDGE_OBLIQUE153, 4, 6), |
| (WEDGE_OBLIQUE63, 2, 4), (WEDGE_OBLIQUE63, 6, 4), |
| (WEDGE_OBLIQUE117, 2, 4), (WEDGE_OBLIQUE117, 6, 4), |
| ] |
| |
| # av1_wedge_params_lookup. Stored here as (wtypes, codebook). The masks/ |
| # signflip pointers are reconstructed from BLOCK index. See |
| # av1_wedge_params_lookup in av1/common/reconinter.c. |
| WEDGE_PARAMS_LOOKUP = [ |
| (0, None), |
| (0, None), |
| (0, None), |
| (MAX_WEDGE_TYPES, WEDGE_CODEBOOK_16_HEQW), # BLOCK_8X8 |
| (MAX_WEDGE_TYPES, WEDGE_CODEBOOK_16_HGTW), # BLOCK_8X16 |
| (MAX_WEDGE_TYPES, WEDGE_CODEBOOK_16_HLTW), # BLOCK_16X8 |
| (MAX_WEDGE_TYPES, WEDGE_CODEBOOK_16_HEQW), # BLOCK_16X16 |
| (MAX_WEDGE_TYPES, WEDGE_CODEBOOK_16_HGTW), # BLOCK_16X32 |
| (MAX_WEDGE_TYPES, WEDGE_CODEBOOK_16_HLTW), # BLOCK_32X16 |
| (MAX_WEDGE_TYPES, WEDGE_CODEBOOK_16_HEQW), # BLOCK_32X32 |
| (0, None), (0, None), (0, None), (0, None), |
| (0, None), (0, None), (0, None), (0, None), |
| (MAX_WEDGE_TYPES, WEDGE_CODEBOOK_16_HGTW), # BLOCK_8X32 |
| (MAX_WEDGE_TYPES, WEDGE_CODEBOOK_16_HLTW), # BLOCK_32X8 |
| (0, None), (0, None), |
| ] |
| assert len(WEDGE_PARAMS_LOOKUP) == BLOCK_SIZES_ALL |
| |
| # ii_weights1d (see av1/common/reconinter.c). |
| II_WEIGHTS_1D = [ |
| 60, 58, 56, 54, 52, 50, 48, 47, 45, 44, 42, 41, 39, 38, 37, 35, 34, 33, 32, |
| 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 22, 21, 20, 19, 19, 18, 18, 17, 16, |
| 16, 15, 15, 14, 14, 13, 13, 12, 12, 12, 11, 11, 10, 10, 10, 9, 9, 9, 8, |
| 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, |
| 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, |
| 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| ] |
| assert len(II_WEIGHTS_1D) == MAX_SB_SIZE |
| |
| # ii_size_scales (see av1/common/reconinter.c). |
| II_SIZE_SCALES = [ |
| 32, 16, 16, 16, 8, 8, 8, 4, |
| 4, 4, 2, 2, 2, 1, 1, 1, |
| 8, 8, 4, 4, 2, 2, |
| ] |
| assert len(II_SIZE_SCALES) == BLOCK_SIZES_ALL |
| |
| |
| # ----------------------------------------------------------------------------- |
| # Algorithm: build wedge_mask_obl (init_wedge_master_masks in reconinter.c). |
| # ----------------------------------------------------------------------------- |
| def shift_copy(src, dst, dst_off, shift, width): |
| """Mirrors shift_copy() in reconinter.c.""" |
| if shift >= 0: |
| for i in range(width - shift): |
| dst[dst_off + shift + i] = src[i] |
| for i in range(shift): |
| dst[dst_off + i] = src[0] |
| else: |
| n = -shift |
| for i in range(width - n): |
| dst[dst_off + i] = src[n + i] |
| for i in range(n): |
| dst[dst_off + width - n + i] = src[width - 1] |
| |
| |
| def build_wedge_mask_obl(): |
| # [negative][direction] indexed flat per direction, MASK_MASTER_SIZE^2 bytes. |
| obl = [[[0] * (MASK_MASTER_SIZE * MASK_MASTER_SIZE) |
| for _ in range(WEDGE_DIRECTIONS)] |
| for _ in range(2)] |
| |
| w = MASK_MASTER_SIZE |
| h = MASK_MASTER_SIZE |
| stride = MASK_MASTER_STRIDE |
| shift = h // 4 |
| i = 0 |
| while i < h: |
| shift_copy(WEDGE_MASTER_OBLIQUE_EVEN, |
| obl[0][WEDGE_OBLIQUE63], i * stride, shift, MASK_MASTER_SIZE) |
| shift -= 1 |
| shift_copy(WEDGE_MASTER_OBLIQUE_ODD, |
| obl[0][WEDGE_OBLIQUE63], (i + 1) * stride, shift, |
| MASK_MASTER_SIZE) |
| # Vertical rows are just the vertical master copied each row. |
| for k in range(MASK_MASTER_SIZE): |
| obl[0][WEDGE_VERTICAL][i * stride + k] = WEDGE_MASTER_VERTICAL[k] |
| obl[0][WEDGE_VERTICAL][(i + 1) * stride + k] = ( |
| WEDGE_MASTER_VERTICAL[k]) |
| i += 2 |
| |
| max_val = 1 << WEDGE_WEIGHT_BITS # 64 |
| for i in range(h): |
| for j in range(w): |
| msk = obl[0][WEDGE_OBLIQUE63][i * stride + j] |
| obl[0][WEDGE_OBLIQUE27][j * stride + i] = msk |
| obl[0][WEDGE_OBLIQUE117][i * stride + w - 1 - j] = max_val - msk |
| obl[0][WEDGE_OBLIQUE153][(w - 1 - j) * stride + i] = max_val - msk |
| obl[1][WEDGE_OBLIQUE63][i * stride + j] = max_val - msk |
| obl[1][WEDGE_OBLIQUE27][j * stride + i] = max_val - msk |
| obl[1][WEDGE_OBLIQUE117][i * stride + w - 1 - j] = msk |
| obl[1][WEDGE_OBLIQUE153][(w - 1 - j) * stride + i] = msk |
| mskx = obl[0][WEDGE_VERTICAL][i * stride + j] |
| obl[0][WEDGE_HORIZONTAL][j * stride + i] = mskx |
| obl[1][WEDGE_VERTICAL][i * stride + j] = max_val - mskx |
| obl[1][WEDGE_HORIZONTAL][j * stride + i] = max_val - mskx |
| |
| return obl |
| |
| |
| # ----------------------------------------------------------------------------- |
| # Algorithm: build wedge_mask_buf and wedge_masks offset table |
| # (init_wedge_masks + get_wedge_mask_inplace + aom_convolve_copy). |
| # ----------------------------------------------------------------------------- |
| def get_wedge_mask_inplace_offset(wedge_obl, w_idx, neg, bsize): |
| """Compute the starting (row, col) into wedge_mask_obl[neg^wsignflip][dir] |
| for a given wedge index/sign/block-size; mirrors get_wedge_mask_inplace(). |
| Returns (which_neg, direction, row_off, col_off).""" |
| bw = BLOCK_WIDTH[bsize] |
| bh = BLOCK_HEIGHT[bsize] |
| wtypes, codebook = WEDGE_PARAMS_LOOKUP[bsize] |
| assert wtypes > 0 |
| direction, x_off, y_off = codebook[w_idx] |
| woff = (x_off * bw) >> 3 |
| hoff = (y_off * bh) >> 3 |
| wsignflip = WEDGE_SIGNFLIP_LOOKUP[bsize][w_idx] |
| which = neg ^ wsignflip |
| row_off = MASK_MASTER_SIZE // 2 - hoff |
| col_off = MASK_MASTER_SIZE // 2 - woff |
| return which, direction, row_off, col_off |
| |
| |
| def build_wedge_mask_buf(obl): |
| buf_size = 2 * MAX_WEDGE_TYPES * 4 * MAX_WEDGE_SQUARE |
| buf = [0] * buf_size |
| |
| # Offset table: wedge_masks[bsize][sign][wedge_index] -> uint32 offset. |
| offsets = [[[0] * MAX_WEDGE_TYPES for _ in range(2)] |
| for _ in range(BLOCK_SIZES_ALL)] |
| |
| dst = 0 |
| for bsize in range(BLOCK_SIZES_ALL): |
| wtypes, _ = WEDGE_PARAMS_LOOKUP[bsize] |
| if wtypes == 0: |
| continue |
| bw = BLOCK_WIDTH[bsize] |
| bh = BLOCK_HEIGHT[bsize] |
| for w_idx in range(wtypes): |
| # sign 0 |
| which, direction, row_off, col_off = ( |
| get_wedge_mask_inplace_offset(obl, w_idx, 0, bsize)) |
| src = obl[which][direction] |
| for r in range(bh): |
| for c in range(bw): |
| buf[dst + r * bw + c] = src[ |
| (row_off + r) * MASK_MASTER_STRIDE + (col_off + c)] |
| offsets[bsize][0][w_idx] = dst |
| dst += bw * bh |
| |
| # sign 1 |
| which, direction, row_off, col_off = ( |
| get_wedge_mask_inplace_offset(obl, w_idx, 1, bsize)) |
| src = obl[which][direction] |
| for r in range(bh): |
| for c in range(bw): |
| buf[dst + r * bw + c] = src[ |
| (row_off + r) * MASK_MASTER_STRIDE + (col_off + c)] |
| offsets[bsize][1][w_idx] = dst |
| dst += bw * bh |
| |
| assert dst <= buf_size, (dst, buf_size) |
| return buf, offsets |
| |
| |
| # ----------------------------------------------------------------------------- |
| # Algorithm: build smooth_interintra_mask_buf |
| # (init_smooth_interintra_masks + build_smooth_interintra_mask). |
| # ----------------------------------------------------------------------------- |
| def build_smooth_interintra(mask, mask_off, stride, plane_bsize, mode): |
| bw = BLOCK_WIDTH[plane_bsize] |
| bh = BLOCK_HEIGHT[plane_bsize] |
| size_scale = II_SIZE_SCALES[plane_bsize] |
| if mode == II_V_PRED: |
| for i in range(bh): |
| row = mask_off + i * stride |
| val = II_WEIGHTS_1D[i * size_scale] |
| for j in range(bw): |
| mask[row + j] = val |
| elif mode == II_H_PRED: |
| for i in range(bh): |
| row = mask_off + i * stride |
| for j in range(bw): |
| mask[row + j] = II_WEIGHTS_1D[j * size_scale] |
| elif mode == II_SMOOTH_PRED: |
| for i in range(bh): |
| row = mask_off + i * stride |
| for j in range(bw): |
| mask[row + j] = II_WEIGHTS_1D[min(i, j) * size_scale] |
| else: # II_DC_PRED or default |
| for i in range(bh): |
| row = mask_off + i * stride |
| for j in range(bw): |
| mask[row + j] = 32 |
| |
| |
| def build_smooth_interintra_mask_buf(): |
| # [INTERINTRA_MODES][BLOCK_SIZES_ALL][MAX_WEDGE_SQUARE] |
| buf = [[[0] * MAX_WEDGE_SQUARE for _ in range(BLOCK_SIZES_ALL)] |
| for _ in range(INTERINTRA_MODES)] |
| for m in range(INTERINTRA_MODES): |
| for bs in range(BLOCK_SIZES_ALL): |
| bw = BLOCK_WIDTH[bs] |
| bh = BLOCK_HEIGHT[bs] |
| if bw > MAX_WEDGE_SIZE or bh > MAX_WEDGE_SIZE: |
| continue |
| build_smooth_interintra(buf[m][bs], 0, bw, bs, m) |
| return buf |
| |
| |
| # ----------------------------------------------------------------------------- |
| # C emission helpers. |
| # ----------------------------------------------------------------------------- |
| def emit_bytes_block(values, indent=" ", per_line=16): |
| lines = [] |
| for chunk_start in range(0, len(values), per_line): |
| chunk = values[chunk_start:chunk_start + per_line] |
| parts = ["{:>3d}".format(v) for v in chunk] |
| lines.append(indent + ", ".join(parts) + ",") |
| return "\n".join(lines) |
| |
| |
| def emit_wedge_mask_obl(out, obl): |
| out.append( |
| "DECLARE_ALIGNED(16, static const uint8_t,") |
| out.append( |
| " wedge_mask_obl[2][WEDGE_DIRECTIONS]") |
| out.append( |
| " [MASK_MASTER_SIZE * MASK_MASTER_SIZE]) = {") |
| for neg in range(2): |
| out.append(" {") |
| for direction in range(WEDGE_DIRECTIONS): |
| out.append(" {{ // [{}][dir={}]".format(neg, direction)) |
| out.append(emit_bytes_block(obl[neg][direction], indent=" ")) |
| out.append(" },") |
| out.append(" },") |
| out.append("};") |
| |
| |
| def emit_wedge_mask_buf(out, buf): |
| out.append( |
| "DECLARE_ALIGNED(16, static const uint8_t,") |
| out.append( |
| " wedge_mask_buf[2 * MAX_WEDGE_TYPES * 4 *" |
| " MAX_WEDGE_SQUARE]) = {") |
| out.append(emit_bytes_block(buf, indent=" ")) |
| out.append("};") |
| |
| |
| def emit_smooth_interintra(out, buf): |
| out.append( |
| "DECLARE_ALIGNED(16, static const uint8_t,") |
| out.append( |
| " smooth_interintra_mask_buf[INTERINTRA_MODES]") |
| out.append( |
| " [BLOCK_SIZES_ALL]") |
| out.append( |
| " [MAX_WEDGE_SQUARE]) = {") |
| for m in range(INTERINTRA_MODES): |
| out.append(" {") |
| for bs in range(BLOCK_SIZES_ALL): |
| out.append(" {{ // mode={}, bsize={}".format(m, BLOCK_NAMES[bs])) |
| out.append(emit_bytes_block(buf[m][bs], indent=" ")) |
| out.append(" },") |
| out.append(" },") |
| out.append("};") |
| |
| |
| def emit_wedge_offsets(out, offsets): |
| out.append( |
| "static const wedge_masks_type wedge_masks[BLOCK_SIZES_ALL][2] = {") |
| for bs in range(BLOCK_SIZES_ALL): |
| out.append(" { // " + BLOCK_NAMES[bs]) |
| for sign in range(2): |
| row = offsets[bs][sign] |
| parts = ["{:>6d}u".format(v) for v in row] |
| out.append(" { " + ", ".join(parts) + " },") |
| out.append(" },") |
| out.append("};") |
| |
| |
| HEADER_BANNER = """\ |
| /* |
| * 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. |
| */ |
| |
| // This file is auto-generated by tools/gen_wedge_masks_data.py. DO NOT EDIT. |
| // |
| // It precomputes the libaom AV1 compound-prediction wedge masks and |
| // inter-intra smooth blending masks so they can live in `.rdata` and be |
| // COW-shared across processes, instead of being computed at runtime into |
| // writable `.data` buffers via av1_init_wedge_masks(). |
| // |
| // `wedge_masks` stores byte offsets into `wedge_mask_buf` (not pointers) so |
| // no loader relocations are needed. |
| // |
| // To regenerate after upstream changes to reconinter.c (wedge codebooks, |
| // master tables, BLOCK_SIZE enum, ii_weights1d, etc.) run: |
| // python3 source/libaom/tools/gen_wedge_masks_data.py |
| // --output source/libaom/av1/common/wedge_masks_data.inc |
| """ |
| |
| |
| def write_output(path, obl, buf, smooth, offsets): |
| out = [] |
| out.append(HEADER_BANNER) |
| # Disable clang-format on the generated data tables. The emitters below |
| # produce a deliberately column-aligned, 16-values-per-line layout so the |
| # ~14k lines of mask data are visually scannable (you can eyeball the |
| # wedge patterns and offset progressions). clang-format would otherwise |
| # reflow each table to fit the project column limit, jumbling rows |
| # together, destroying the alignment, and producing a several-thousand- |
| # line diff every time anyone re-ran it. |
| out.append("// The data tables below are emitted by") |
| out.append("// tools/gen_wedge_masks_data.py with a fixed 16-values-per-row") |
| out.append("// layout for visual readability. clang-format would reflow") |
| out.append("// them to fit the project column limit, destroying the") |
| out.append("// alignment and producing a many-thousand-line diff. Keep the") |
| out.append("// formatter off until the closing `// clang-format on` below.") |
| out.append("// clang-format off") |
| out.append("") |
| # `wedge_mask_obl` is intentionally not emitted: it was only used at |
| # runtime as an intermediate to populate `wedge_mask_buf`, which is now |
| # precomputed below. Dropping it saves ~48 KB of .rdata. |
| _ = obl # retained for verification harnesses; unused here. |
| emit_wedge_mask_buf(out, buf) |
| out.append("") |
| emit_smooth_interintra(out, smooth) |
| out.append("") |
| emit_wedge_offsets(out, offsets) |
| out.append("") |
| out.append("// clang-format on") |
| out.append("") |
| text = "\n".join(out) |
| with open(path, "w", encoding="utf-8", newline="\n") as f: |
| f.write(text) |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser(description=__doc__) |
| default_out = os.path.normpath( |
| os.path.join(os.path.dirname(__file__), "..", "av1", "common", |
| "wedge_masks_data.inc")) |
| parser.add_argument("--output", default=default_out, |
| help="Path to wedge_masks_data.inc (default: %(default)s)") |
| args = parser.parse_args() |
| |
| obl = build_wedge_mask_obl() |
| buf, offsets = build_wedge_mask_buf(obl) |
| smooth = build_smooth_interintra_mask_buf() |
| write_output(args.output, obl, buf, smooth, offsets) |
| print("Wrote {}".format(args.output)) |
| |
| |
| if __name__ == "__main__": |
| main() |