1 // Copyright 2019 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/prediction_mask.h"
16
17 #include <algorithm>
18 #include <array>
19 #include <cassert>
20 #include <cstddef>
21 #include <cstdint>
22 #include <cstdlib>
23 #include <cstring>
24 #include <memory>
25
26 #include "src/utils/array_2d.h"
27 #include "src/utils/bit_mask_set.h"
28 #include "src/utils/common.h"
29 #include "src/utils/constants.h"
30 #include "src/utils/logging.h"
31 #include "src/utils/memory.h"
32
33 namespace libgav1 {
34 namespace {
35
36 constexpr int kWedgeDirectionTypes = 16;
37
38 enum kWedgeDirection : uint8_t {
39 kWedgeHorizontal,
40 kWedgeVertical,
41 kWedgeOblique27,
42 kWedgeOblique63,
43 kWedgeOblique117,
44 kWedgeOblique153,
45 };
46
47 constexpr uint8_t kWedgeCodebook[3][16][3] = {{{kWedgeOblique27, 4, 4},
48 {kWedgeOblique63, 4, 4},
49 {kWedgeOblique117, 4, 4},
50 {kWedgeOblique153, 4, 4},
51 {kWedgeHorizontal, 4, 2},
52 {kWedgeHorizontal, 4, 4},
53 {kWedgeHorizontal, 4, 6},
54 {kWedgeVertical, 4, 4},
55 {kWedgeOblique27, 4, 2},
56 {kWedgeOblique27, 4, 6},
57 {kWedgeOblique153, 4, 2},
58 {kWedgeOblique153, 4, 6},
59 {kWedgeOblique63, 2, 4},
60 {kWedgeOblique63, 6, 4},
61 {kWedgeOblique117, 2, 4},
62 {kWedgeOblique117, 6, 4}},
63 {{kWedgeOblique27, 4, 4},
64 {kWedgeOblique63, 4, 4},
65 {kWedgeOblique117, 4, 4},
66 {kWedgeOblique153, 4, 4},
67 {kWedgeVertical, 2, 4},
68 {kWedgeVertical, 4, 4},
69 {kWedgeVertical, 6, 4},
70 {kWedgeHorizontal, 4, 4},
71 {kWedgeOblique27, 4, 2},
72 {kWedgeOblique27, 4, 6},
73 {kWedgeOblique153, 4, 2},
74 {kWedgeOblique153, 4, 6},
75 {kWedgeOblique63, 2, 4},
76 {kWedgeOblique63, 6, 4},
77 {kWedgeOblique117, 2, 4},
78 {kWedgeOblique117, 6, 4}},
79 {{kWedgeOblique27, 4, 4},
80 {kWedgeOblique63, 4, 4},
81 {kWedgeOblique117, 4, 4},
82 {kWedgeOblique153, 4, 4},
83 {kWedgeHorizontal, 4, 2},
84 {kWedgeHorizontal, 4, 6},
85 {kWedgeVertical, 2, 4},
86 {kWedgeVertical, 6, 4},
87 {kWedgeOblique27, 4, 2},
88 {kWedgeOblique27, 4, 6},
89 {kWedgeOblique153, 4, 2},
90 {kWedgeOblique153, 4, 6},
91 {kWedgeOblique63, 2, 4},
92 {kWedgeOblique63, 6, 4},
93 {kWedgeOblique117, 2, 4},
94 {kWedgeOblique117, 6, 4}}};
95
96 constexpr BitMaskSet kWedgeFlipSignMasks[9] = {
97 BitMaskSet(0xBBFF), // kBlock8x8
98 BitMaskSet(0xBBEF), // kBlock8x16
99 BitMaskSet(0xBAEF), // kBlock8x32
100 BitMaskSet(0xBBEF), // kBlock16x8
101 BitMaskSet(0xBBFF), // kBlock16x16
102 BitMaskSet(0xBBEF), // kBlock16x32
103 BitMaskSet(0xABEF), // kBlock32x8
104 BitMaskSet(0xBBEF), // kBlock32x16
105 BitMaskSet(0xBBFF) // kBlock32x32
106 };
107
108 // This table (and the one below) contains a few leading zeros and trailing 64s
109 // to avoid some additional memcpys where it is actually used.
110 constexpr uint8_t kWedgeMasterObliqueOdd[kWedgeMaskMasterSize * 3 / 2] = {
111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 6, 18, 37,
114 53, 60, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
115 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
116 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64};
117
118 constexpr uint8_t kWedgeMasterObliqueEven[kWedgeMaskMasterSize * 3 / 2] = {
119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 11, 27,
122 46, 58, 62, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
123 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
124 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64};
125
126 constexpr uint8_t kWedgeMasterVertical[kWedgeMaskMasterSize] = {
127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 7, 21,
129 43, 57, 62, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
130 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64};
131
BlockShape(BlockSize block_size)132 int BlockShape(BlockSize block_size) {
133 const int width = kNum4x4BlocksWide[block_size];
134 const int height = kNum4x4BlocksHigh[block_size];
135 if (height > width) return 0;
136 if (height < width) return 1;
137 return 2;
138 }
139
GetWedgeDirection(BlockSize block_size,int index)140 uint8_t GetWedgeDirection(BlockSize block_size, int index) {
141 return kWedgeCodebook[BlockShape(block_size)][index][0];
142 }
143
GetWedgeOffsetX(BlockSize block_size,int index)144 uint8_t GetWedgeOffsetX(BlockSize block_size, int index) {
145 return kWedgeCodebook[BlockShape(block_size)][index][1];
146 }
147
GetWedgeOffsetY(BlockSize block_size,int index)148 uint8_t GetWedgeOffsetY(BlockSize block_size, int index) {
149 return kWedgeCodebook[BlockShape(block_size)][index][2];
150 }
151
152 } // namespace
153
GenerateWedgeMask(WedgeMaskArray * const wedge_masks)154 bool GenerateWedgeMask(WedgeMaskArray* const wedge_masks) {
155 // Generate master masks.
156 uint8_t master_mask[6][kWedgeMaskMasterSize][kWedgeMaskMasterSize];
157 for (int y = 0; y < kWedgeMaskMasterSize; ++y) {
158 memcpy(master_mask[kWedgeVertical][y], kWedgeMasterVertical,
159 kWedgeMaskMasterSize);
160 }
161
162 for (int y = 0, shift = 0; y < kWedgeMaskMasterSize; y += 2, ++shift) {
163 memcpy(master_mask[kWedgeOblique63][y], kWedgeMasterObliqueEven + shift,
164 kWedgeMaskMasterSize);
165 memcpy(master_mask[kWedgeOblique63][y + 1], kWedgeMasterObliqueOdd + shift,
166 kWedgeMaskMasterSize);
167 }
168
169 for (int y = 0; y < kWedgeMaskMasterSize; ++y) {
170 for (int x = 0; x < kWedgeMaskMasterSize; ++x) {
171 const uint8_t mask_value = master_mask[kWedgeOblique63][y][x];
172 master_mask[kWedgeHorizontal][x][y] = master_mask[kWedgeVertical][y][x];
173 master_mask[kWedgeOblique27][x][y] = mask_value;
174 master_mask[kWedgeOblique117][y][kWedgeMaskMasterSize - 1 - x] =
175 64 - mask_value;
176 master_mask[kWedgeOblique153][(kWedgeMaskMasterSize - 1 - x)][y] =
177 64 - mask_value;
178 }
179 }
180
181 // Generate wedge masks.
182 int block_size_index = 0;
183 for (int size = kBlock8x8; size <= kBlock32x32; ++size) {
184 if (!kIsWedgeCompoundModeAllowed.Contains(size)) continue;
185
186 const int width = kBlockWidthPixels[size];
187 const int height = kBlockHeightPixels[size];
188 assert(width >= 8);
189 assert(width <= 32);
190 assert(height >= 8);
191 assert(height <= 32);
192
193 const auto block_size = static_cast<BlockSize>(size);
194 for (int wedge_index = 0; wedge_index < kWedgeDirectionTypes;
195 ++wedge_index) {
196 const uint8_t direction = GetWedgeDirection(block_size, wedge_index);
197 const uint8_t offset_x =
198 DivideBy2(kWedgeMaskMasterSize) -
199 ((GetWedgeOffsetX(block_size, wedge_index) * width) >> 3);
200 const uint8_t offset_y =
201 DivideBy2(kWedgeMaskMasterSize) -
202 ((GetWedgeOffsetY(block_size, wedge_index) * height) >> 3);
203
204 // Allocate the 2d array.
205 for (int flip_sign = 0; flip_sign < 2; ++flip_sign) {
206 if (!((*wedge_masks)[block_size_index][flip_sign][wedge_index].Reset(
207 height, width, /*zero_initialize=*/false))) {
208 LIBGAV1_DLOG(ERROR, "Failed to allocate memory for wedge masks.");
209 return false;
210 }
211 }
212
213 const auto flip_sign = static_cast<uint8_t>(
214 kWedgeFlipSignMasks[block_size_index].Contains(wedge_index));
215 uint8_t* wedge_masks_row =
216 (*wedge_masks)[block_size_index][flip_sign][wedge_index][0];
217 uint8_t* wedge_masks_row_flip =
218 (*wedge_masks)[block_size_index][1 - flip_sign][wedge_index][0];
219 uint8_t* master_mask_row = &master_mask[direction][offset_y][offset_x];
220 for (int y = 0; y < height; ++y) {
221 memcpy(wedge_masks_row, master_mask_row, width);
222 for (int x = 0; x < width; ++x) {
223 wedge_masks_row_flip[x] = 64 - wedge_masks_row[x];
224 }
225 wedge_masks_row += width;
226 wedge_masks_row_flip += width;
227 master_mask_row += kWedgeMaskMasterSize;
228 }
229 }
230
231 block_size_index++;
232 }
233 return true;
234 }
235
236 } // namespace libgav1
237