lf_mask.c (18626B)
1 /* 2 * Copyright © 2018, VideoLAN and dav1d authors 3 * Copyright © 2018, Two Orioles, LLC 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, this 10 * list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "config.h" 29 30 #include <string.h> 31 32 #include "common/intops.h" 33 34 #include "src/ctx.h" 35 #include "src/levels.h" 36 #include "src/lf_mask.h" 37 #include "src/tables.h" 38 39 static void decomp_tx(uint8_t (*const txa)[2 /* txsz, step */][32 /* y */][32 /* x */], 40 const enum RectTxfmSize from, 41 const int depth, 42 const int y_off, const int x_off, 43 const uint16_t *const tx_masks) 44 { 45 const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[from]; 46 const int is_split = (from == (int) TX_4X4 || depth > 1) ? 0 : 47 (tx_masks[depth] >> (y_off * 4 + x_off)) & 1; 48 49 if (is_split) { 50 const enum RectTxfmSize sub = t_dim->sub; 51 const int htw4 = t_dim->w >> 1, hth4 = t_dim->h >> 1; 52 53 decomp_tx(txa, sub, depth + 1, y_off * 2 + 0, x_off * 2 + 0, tx_masks); 54 if (t_dim->w >= t_dim->h) 55 decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][0][htw4], 56 sub, depth + 1, y_off * 2 + 0, x_off * 2 + 1, tx_masks); 57 if (t_dim->h >= t_dim->w) { 58 decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][hth4][0], 59 sub, depth + 1, y_off * 2 + 1, x_off * 2 + 0, tx_masks); 60 if (t_dim->w >= t_dim->h) 61 decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][hth4][htw4], 62 sub, depth + 1, y_off * 2 + 1, x_off * 2 + 1, tx_masks); 63 } 64 } else { 65 const int lw = imin(2, t_dim->lw), lh = imin(2, t_dim->lh); 66 67 #define set_ctx(rep_macro) \ 68 for (int y = 0; y < t_dim->h; y++) { \ 69 rep_macro(txa[0][0][y], 0, lw); \ 70 rep_macro(txa[1][0][y], 0, lh); \ 71 txa[0][1][y][0] = t_dim->w; \ 72 } 73 case_set_upto16(t_dim->lw); 74 #undef set_ctx 75 dav1d_memset_pow2[t_dim->lw](txa[1][1][0], t_dim->h); 76 } 77 } 78 79 static inline void mask_edges_inter(uint16_t (*const masks)[32][3][2], 80 const int by4, const int bx4, 81 const int w4, const int h4, const int skip, 82 const enum RectTxfmSize max_tx, 83 const uint16_t *const tx_masks, 84 uint8_t *const a, uint8_t *const l) 85 { 86 const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[max_tx]; 87 int y, x; 88 89 ALIGN_STK_16(uint8_t, txa, 2 /* edge */, [2 /* txsz, step */][32 /* y */][32 /* x */]); 90 for (int y_off = 0, y = 0; y < h4; y += t_dim->h, y_off++) 91 for (int x_off = 0, x = 0; x < w4; x += t_dim->w, x_off++) 92 decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][y][x], 93 max_tx, 0, y_off, x_off, tx_masks); 94 95 // left block edge 96 unsigned mask = 1U << by4; 97 for (y = 0; y < h4; y++, mask <<= 1) { 98 const int sidx = mask >= 0x10000; 99 const unsigned smask = mask >> (sidx << 4); 100 masks[0][bx4][imin(txa[0][0][y][0], l[y])][sidx] |= smask; 101 } 102 103 // top block edge 104 for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) { 105 const int sidx = mask >= 0x10000; 106 const unsigned smask = mask >> (sidx << 4); 107 masks[1][by4][imin(txa[1][0][0][x], a[x])][sidx] |= smask; 108 } 109 110 if (!skip) { 111 // inner (tx) left|right edges 112 for (y = 0, mask = 1U << by4; y < h4; y++, mask <<= 1) { 113 const int sidx = mask >= 0x10000U; 114 const unsigned smask = mask >> (sidx << 4); 115 int ltx = txa[0][0][y][0]; 116 int step = txa[0][1][y][0]; 117 for (x = step; x < w4; x += step) { 118 const int rtx = txa[0][0][y][x]; 119 masks[0][bx4 + x][imin(rtx, ltx)][sidx] |= smask; 120 ltx = rtx; 121 step = txa[0][1][y][x]; 122 } 123 } 124 125 // top 126 // inner (tx) --- edges 127 // bottom 128 for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) { 129 const int sidx = mask >= 0x10000U; 130 const unsigned smask = mask >> (sidx << 4); 131 int ttx = txa[1][0][0][x]; 132 int step = txa[1][1][0][x]; 133 for (y = step; y < h4; y += step) { 134 const int btx = txa[1][0][y][x]; 135 masks[1][by4 + y][imin(ttx, btx)][sidx] |= smask; 136 ttx = btx; 137 step = txa[1][1][y][x]; 138 } 139 } 140 } 141 142 for (y = 0; y < h4; y++) 143 l[y] = txa[0][0][y][w4 - 1]; 144 memcpy(a, txa[1][0][h4 - 1], w4); 145 } 146 147 static inline void mask_edges_intra(uint16_t (*const masks)[32][3][2], 148 const int by4, const int bx4, 149 const int w4, const int h4, 150 const enum RectTxfmSize tx, 151 uint8_t *const a, uint8_t *const l) 152 { 153 const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[tx]; 154 const int twl4 = t_dim->lw, thl4 = t_dim->lh; 155 const int twl4c = imin(2, twl4), thl4c = imin(2, thl4); 156 int y, x; 157 158 // left block edge 159 unsigned mask = 1U << by4; 160 for (y = 0; y < h4; y++, mask <<= 1) { 161 const int sidx = mask >= 0x10000; 162 const unsigned smask = mask >> (sidx << 4); 163 masks[0][bx4][imin(twl4c, l[y])][sidx] |= smask; 164 } 165 166 // top block edge 167 for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) { 168 const int sidx = mask >= 0x10000; 169 const unsigned smask = mask >> (sidx << 4); 170 masks[1][by4][imin(thl4c, a[x])][sidx] |= smask; 171 } 172 173 // inner (tx) left|right edges 174 const int hstep = t_dim->w; 175 unsigned t = 1U << by4; 176 unsigned inner = (unsigned) ((((uint64_t) t) << h4) - t); 177 unsigned inner1 = inner & 0xffff, inner2 = inner >> 16; 178 for (x = hstep; x < w4; x += hstep) { 179 if (inner1) masks[0][bx4 + x][twl4c][0] |= inner1; 180 if (inner2) masks[0][bx4 + x][twl4c][1] |= inner2; 181 } 182 183 // top 184 // inner (tx) --- edges 185 // bottom 186 const int vstep = t_dim->h; 187 t = 1U << bx4; 188 inner = (unsigned) ((((uint64_t) t) << w4) - t); 189 inner1 = inner & 0xffff; 190 inner2 = inner >> 16; 191 for (y = vstep; y < h4; y += vstep) { 192 if (inner1) masks[1][by4 + y][thl4c][0] |= inner1; 193 if (inner2) masks[1][by4 + y][thl4c][1] |= inner2; 194 } 195 196 dav1d_memset_likely_pow2(a, thl4c, w4); 197 dav1d_memset_likely_pow2(l, twl4c, h4); 198 } 199 200 static void mask_edges_chroma(uint16_t (*const masks)[32][2][2], 201 const int cby4, const int cbx4, 202 const int cw4, const int ch4, 203 const int skip_inter, 204 const enum RectTxfmSize tx, 205 uint8_t *const a, uint8_t *const l, 206 const int ss_hor, const int ss_ver) 207 { 208 const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[tx]; 209 const int twl4 = t_dim->lw, thl4 = t_dim->lh; 210 const int twl4c = !!twl4, thl4c = !!thl4; 211 int y, x; 212 const int vbits = 4 - ss_ver, hbits = 4 - ss_hor; 213 const int vmask = 16 >> ss_ver, hmask = 16 >> ss_hor; 214 const unsigned vmax = 1 << vmask, hmax = 1 << hmask; 215 216 // left block edge 217 unsigned mask = 1U << cby4; 218 for (y = 0; y < ch4; y++, mask <<= 1) { 219 const int sidx = mask >= vmax; 220 const unsigned smask = mask >> (sidx << vbits); 221 masks[0][cbx4][imin(twl4c, l[y])][sidx] |= smask; 222 } 223 224 // top block edge 225 for (x = 0, mask = 1U << cbx4; x < cw4; x++, mask <<= 1) { 226 const int sidx = mask >= hmax; 227 const unsigned smask = mask >> (sidx << hbits); 228 masks[1][cby4][imin(thl4c, a[x])][sidx] |= smask; 229 } 230 231 if (!skip_inter) { 232 // inner (tx) left|right edges 233 const int hstep = t_dim->w; 234 unsigned t = 1U << cby4; 235 unsigned inner = (unsigned) ((((uint64_t) t) << ch4) - t); 236 unsigned inner1 = inner & ((1 << vmask) - 1), inner2 = inner >> vmask; 237 for (x = hstep; x < cw4; x += hstep) { 238 if (inner1) masks[0][cbx4 + x][twl4c][0] |= inner1; 239 if (inner2) masks[0][cbx4 + x][twl4c][1] |= inner2; 240 } 241 242 // top 243 // inner (tx) --- edges 244 // bottom 245 const int vstep = t_dim->h; 246 t = 1U << cbx4; 247 inner = (unsigned) ((((uint64_t) t) << cw4) - t); 248 inner1 = inner & ((1 << hmask) - 1), inner2 = inner >> hmask; 249 for (y = vstep; y < ch4; y += vstep) { 250 if (inner1) masks[1][cby4 + y][thl4c][0] |= inner1; 251 if (inner2) masks[1][cby4 + y][thl4c][1] |= inner2; 252 } 253 } 254 255 dav1d_memset_likely_pow2(a, thl4c, cw4); 256 dav1d_memset_likely_pow2(l, twl4c, ch4); 257 } 258 259 void dav1d_create_lf_mask_intra(Av1Filter *const lflvl, 260 uint8_t (*const level_cache)[4], 261 const ptrdiff_t b4_stride, 262 const uint8_t (*filter_level)[8][2], 263 const int bx, const int by, 264 const int iw, const int ih, 265 const enum BlockSize bs, 266 const enum RectTxfmSize ytx, 267 const enum RectTxfmSize uvtx, 268 const enum Dav1dPixelLayout layout, 269 uint8_t *const ay, uint8_t *const ly, 270 uint8_t *const auv, uint8_t *const luv) 271 { 272 const uint8_t *const b_dim = dav1d_block_dimensions[bs]; 273 const int bw4 = imin(iw - bx, b_dim[0]); 274 const int bh4 = imin(ih - by, b_dim[1]); 275 const int bx4 = bx & 31; 276 const int by4 = by & 31; 277 assert(bw4 >= 0 && bh4 >= 0); 278 279 if (bw4 && bh4) { 280 uint8_t (*level_cache_ptr)[4] = level_cache + by * b4_stride + bx; 281 for (int y = 0; y < bh4; y++) { 282 for (int x = 0; x < bw4; x++) { 283 level_cache_ptr[x][0] = filter_level[0][0][0]; 284 level_cache_ptr[x][1] = filter_level[1][0][0]; 285 } 286 level_cache_ptr += b4_stride; 287 } 288 289 mask_edges_intra(lflvl->filter_y, by4, bx4, bw4, bh4, ytx, ay, ly); 290 } 291 292 if (!auv) return; 293 294 const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420; 295 const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444; 296 const int cbw4 = imin(((iw + ss_hor) >> ss_hor) - (bx >> ss_hor), 297 (b_dim[0] + ss_hor) >> ss_hor); 298 const int cbh4 = imin(((ih + ss_ver) >> ss_ver) - (by >> ss_ver), 299 (b_dim[1] + ss_ver) >> ss_ver); 300 assert(cbw4 >= 0 && cbh4 >= 0); 301 302 if (!cbw4 || !cbh4) return; 303 304 const int cbx4 = bx4 >> ss_hor; 305 const int cby4 = by4 >> ss_ver; 306 307 uint8_t (*level_cache_ptr)[4] = 308 level_cache + (by >> ss_ver) * b4_stride + (bx >> ss_hor); 309 for (int y = 0; y < cbh4; y++) { 310 for (int x = 0; x < cbw4; x++) { 311 level_cache_ptr[x][2] = filter_level[2][0][0]; 312 level_cache_ptr[x][3] = filter_level[3][0][0]; 313 } 314 level_cache_ptr += b4_stride; 315 } 316 317 mask_edges_chroma(lflvl->filter_uv, cby4, cbx4, cbw4, cbh4, 0, uvtx, 318 auv, luv, ss_hor, ss_ver); 319 } 320 321 void dav1d_create_lf_mask_inter(Av1Filter *const lflvl, 322 uint8_t (*const level_cache)[4], 323 const ptrdiff_t b4_stride, 324 const uint8_t (*filter_level)[8][2], 325 const int bx, const int by, 326 const int iw, const int ih, 327 const int skip, const enum BlockSize bs, 328 const enum RectTxfmSize max_ytx, 329 const uint16_t *const tx_masks, 330 const enum RectTxfmSize uvtx, 331 const enum Dav1dPixelLayout layout, 332 uint8_t *const ay, uint8_t *const ly, 333 uint8_t *const auv, uint8_t *const luv) 334 { 335 const uint8_t *const b_dim = dav1d_block_dimensions[bs]; 336 const int bw4 = imin(iw - bx, b_dim[0]); 337 const int bh4 = imin(ih - by, b_dim[1]); 338 const int bx4 = bx & 31; 339 const int by4 = by & 31; 340 assert(bw4 >= 0 && bh4 >= 0); 341 342 if (bw4 && bh4) { 343 uint8_t (*level_cache_ptr)[4] = level_cache + by * b4_stride + bx; 344 for (int y = 0; y < bh4; y++) { 345 for (int x = 0; x < bw4; x++) { 346 level_cache_ptr[x][0] = filter_level[0][0][0]; 347 level_cache_ptr[x][1] = filter_level[1][0][0]; 348 } 349 level_cache_ptr += b4_stride; 350 } 351 352 mask_edges_inter(lflvl->filter_y, by4, bx4, bw4, bh4, skip, 353 max_ytx, tx_masks, ay, ly); 354 } 355 356 if (!auv) return; 357 358 const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420; 359 const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444; 360 const int cbw4 = imin(((iw + ss_hor) >> ss_hor) - (bx >> ss_hor), 361 (b_dim[0] + ss_hor) >> ss_hor); 362 const int cbh4 = imin(((ih + ss_ver) >> ss_ver) - (by >> ss_ver), 363 (b_dim[1] + ss_ver) >> ss_ver); 364 assert(cbw4 >= 0 && cbh4 >= 0); 365 366 if (!cbw4 || !cbh4) return; 367 368 const int cbx4 = bx4 >> ss_hor; 369 const int cby4 = by4 >> ss_ver; 370 371 uint8_t (*level_cache_ptr)[4] = 372 level_cache + (by >> ss_ver) * b4_stride + (bx >> ss_hor); 373 for (int y = 0; y < cbh4; y++) { 374 for (int x = 0; x < cbw4; x++) { 375 level_cache_ptr[x][2] = filter_level[2][0][0]; 376 level_cache_ptr[x][3] = filter_level[3][0][0]; 377 } 378 level_cache_ptr += b4_stride; 379 } 380 381 mask_edges_chroma(lflvl->filter_uv, cby4, cbx4, cbw4, cbh4, skip, uvtx, 382 auv, luv, ss_hor, ss_ver); 383 } 384 385 void dav1d_calc_eih(Av1FilterLUT *const lim_lut, const int filter_sharpness) { 386 // set E/I/H values from loopfilter level 387 const int sharp = filter_sharpness; 388 for (int level = 0; level < 64; level++) { 389 int limit = level; 390 391 if (sharp > 0) { 392 limit >>= (sharp + 3) >> 2; 393 limit = imin(limit, 9 - sharp); 394 } 395 limit = imax(limit, 1); 396 397 lim_lut->i[level] = limit; 398 lim_lut->e[level] = 2 * (level + 2) + limit; 399 } 400 lim_lut->sharp[0] = (sharp + 3) >> 2; 401 lim_lut->sharp[1] = sharp ? 9 - sharp : 0xff; 402 } 403 404 static void calc_lf_value(uint8_t (*const lflvl_values)[2], 405 const int base_lvl, const int lf_delta, 406 const int seg_delta, 407 const Dav1dLoopfilterModeRefDeltas *const mr_delta) 408 { 409 const int base = iclip(iclip(base_lvl + lf_delta, 0, 63) + seg_delta, 0, 63); 410 411 if (!mr_delta) { 412 memset(lflvl_values, base, sizeof(*lflvl_values) * 8); 413 } else { 414 const int sh = base >= 32; 415 lflvl_values[0][0] = lflvl_values[0][1] = 416 iclip(base + (mr_delta->ref_delta[0] * (1 << sh)), 0, 63); 417 for (int r = 1; r < 8; r++) { 418 for (int m = 0; m < 2; m++) { 419 const int delta = 420 mr_delta->mode_delta[m] + mr_delta->ref_delta[r]; 421 lflvl_values[r][m] = iclip(base + (delta * (1 << sh)), 0, 63); 422 } 423 } 424 } 425 } 426 427 static inline void calc_lf_value_chroma(uint8_t (*const lflvl_values)[2], 428 const int base_lvl, const int lf_delta, 429 const int seg_delta, 430 const Dav1dLoopfilterModeRefDeltas *const mr_delta) 431 { 432 if (!base_lvl) 433 memset(lflvl_values, 0, sizeof(*lflvl_values) * 8); 434 else 435 calc_lf_value(lflvl_values, base_lvl, lf_delta, seg_delta, mr_delta); 436 } 437 438 void dav1d_calc_lf_values(uint8_t (*const lflvl_values)[4][8][2], 439 const Dav1dFrameHeader *const hdr, 440 const int8_t lf_delta[4]) 441 { 442 const int n_seg = hdr->segmentation.enabled ? 8 : 1; 443 444 if (!hdr->loopfilter.level_y[0] && !hdr->loopfilter.level_y[1]) { 445 memset(lflvl_values, 0, sizeof(*lflvl_values) * n_seg); 446 return; 447 } 448 449 const Dav1dLoopfilterModeRefDeltas *const mr_deltas = 450 hdr->loopfilter.mode_ref_delta_enabled ? 451 &hdr->loopfilter.mode_ref_deltas : NULL; 452 for (int s = 0; s < n_seg; s++) { 453 const Dav1dSegmentationData *const segd = 454 hdr->segmentation.enabled ? &hdr->segmentation.seg_data.d[s] : NULL; 455 456 calc_lf_value(lflvl_values[s][0], hdr->loopfilter.level_y[0], 457 lf_delta[0], segd ? segd->delta_lf_y_v : 0, mr_deltas); 458 calc_lf_value(lflvl_values[s][1], hdr->loopfilter.level_y[1], 459 lf_delta[hdr->delta.lf.multi ? 1 : 0], 460 segd ? segd->delta_lf_y_h : 0, mr_deltas); 461 calc_lf_value_chroma(lflvl_values[s][2], hdr->loopfilter.level_u, 462 lf_delta[hdr->delta.lf.multi ? 2 : 0], 463 segd ? segd->delta_lf_u : 0, mr_deltas); 464 calc_lf_value_chroma(lflvl_values[s][3], hdr->loopfilter.level_v, 465 lf_delta[hdr->delta.lf.multi ? 3 : 0], 466 segd ? segd->delta_lf_v : 0, mr_deltas); 467 } 468 }