Unexpected use of above/left in get_tx_size_context

How was the issue detected?

HDR Nova AV2 Verification

What version / commit were you testing with?

32f9c7ba

What steps will reproduce the problem?

We are trying to draft specification text for get_tx_size_context, but are worried that it may be operating incorrectly.

The code in pred_common.h reads:

  static INLINE int get_tx_size_context(const MACROBLOCKD *xd) {
  const MB_MODE_INFO *mbmi = xd->mi[0];
  const TX_SIZE max_tx_size =
      max_txsize_rect_lookup[mbmi->sb_type[PLANE_TYPE_Y]];
  const int max_tx_wide = tx_size_wide[max_tx_size];
  const int max_tx_high = tx_size_high[max_tx_size];
  const int default_ctx[MAX_NUM_NEIGHBORS] = {
    xd->above_txfm_context[0] >= max_tx_wide,
    xd->left_txfm_context[0] >= max_tx_high
  };

  const int max_tx_threshold[MAX_NUM_NEIGHBORS] = { max_tx_wide, max_tx_high };

  int ctx = 0;
  for (int i = 0; i < MAX_NUM_NEIGHBORS; ++i) {
    const MB_MODE_INFO *const neighbor = xd->neighbors[i];
    if (neighbor != NULL) {
      if (is_inter_block(neighbor, xd->tree_type)) {
        const int block_size = neighbor->sb_type[PLANE_TYPE_Y];
        ctx += (block_size_wide[block_size] >= max_tx_threshold[i]);
      } else {
        ctx += default_ctx[i];
      }
    }
  }

The problems are related to the construction of neighbour candidates in fetch_spatial_neighbors:

  int index = 0;
#if CONFIG_NEW_CONTEXT_MODELING
  if (xd->bottom_left_mbmi) {
    xd->neighbors[index++] = xd->bottom_left_mbmi;
    if (index >= MAX_NUM_NEIGHBORS) return;
  }
  if (xd->above_right_mbmi) {
    xd->neighbors[index++] = xd->above_right_mbmi;
    if (index >= MAX_NUM_NEIGHBORS) return;
  }
#endif  // CONFIG_NEW_CONTEXT_MODELING
  if (xd->left_mbmi) {
    xd->neighbors[index++] = xd->left_mbmi;
    if (index >= MAX_NUM_NEIGHBORS) return;
  }
  if (xd->above_mbmi) {
    xd->neighbors[index++] = xd->above_mbmi;
    if (index >= MAX_NUM_NEIGHBORS) return;
  }

Note that neighbours are added based on availability, so if all are available, neighbors[0] is bottom left and neighbours[1] is above right.

The surprising features in the code are:

  1. block_size_wide is used for both neighbours, but compared to max_tx_high for neighbour 1
  2. the ordering of default_ctx is above/left which is opposite to the neighbours bottomleft/aboveright order
  3. the ordering of max_tx_threshold is wide/high which is opposite to the neighbours bottomleft/aboveright order
  4. If some neighbours are unavailable, the ordering will change, e.g. the neighbours may be left and bottomleft