1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/gfx/buffer_format_util.h"
6
7 #include "base/logging.h"
8 #include "base/numerics/safe_math.h"
9 #include "base/stl_util.h"
10
11 namespace gfx {
12 namespace {
13
14 const BufferFormat kBufferFormats[] = {BufferFormat::R_8,
15 BufferFormat::R_16,
16 BufferFormat::RG_88,
17 BufferFormat::BGR_565,
18 BufferFormat::RGBA_4444,
19 BufferFormat::RGBX_8888,
20 BufferFormat::RGBA_8888,
21 BufferFormat::BGRX_8888,
22 BufferFormat::BGRA_1010102,
23 BufferFormat::RGBA_1010102,
24 BufferFormat::BGRA_8888,
25 BufferFormat::RGBA_F16,
26 BufferFormat::YUV_420_BIPLANAR,
27 BufferFormat::YVU_420,
28 BufferFormat::P010};
29
30 static_assert(base::size(kBufferFormats) ==
31 (static_cast<int>(BufferFormat::LAST) + 1),
32 "BufferFormat::LAST must be last value of kBufferFormats");
33
34 } // namespace
35
GetBufferFormatsForTesting()36 std::vector<BufferFormat> GetBufferFormatsForTesting() {
37 return std::vector<BufferFormat>(kBufferFormats,
38 kBufferFormats + base::size(kBufferFormats));
39 }
40
AlphaBitsForBufferFormat(BufferFormat format)41 size_t AlphaBitsForBufferFormat(BufferFormat format) {
42 switch (format) {
43 case BufferFormat::RGBA_4444:
44 return 4;
45 case BufferFormat::RGBA_8888:
46 return 8;
47 case BufferFormat::BGRA_1010102:
48 case BufferFormat::RGBA_1010102:
49 return 2;
50 case BufferFormat::BGRA_8888:
51 return 8;
52 case BufferFormat::RGBA_F16:
53 return 16;
54 case BufferFormat::R_8:
55 case BufferFormat::R_16:
56 case BufferFormat::RG_88:
57 case BufferFormat::BGR_565:
58 case BufferFormat::RGBX_8888:
59 case BufferFormat::BGRX_8888:
60 case BufferFormat::YVU_420:
61 case BufferFormat::YUV_420_BIPLANAR:
62 case BufferFormat::P010:
63 return 0;
64 }
65 NOTREACHED();
66 return 0;
67 }
68
NumberOfPlanesForLinearBufferFormat(BufferFormat format)69 size_t NumberOfPlanesForLinearBufferFormat(BufferFormat format) {
70 switch (format) {
71 case BufferFormat::R_8:
72 case BufferFormat::R_16:
73 case BufferFormat::RG_88:
74 case BufferFormat::BGR_565:
75 case BufferFormat::RGBA_4444:
76 case BufferFormat::RGBX_8888:
77 case BufferFormat::RGBA_8888:
78 case BufferFormat::BGRX_8888:
79 case BufferFormat::BGRA_1010102:
80 case BufferFormat::RGBA_1010102:
81 case BufferFormat::BGRA_8888:
82 case BufferFormat::RGBA_F16:
83 return 1;
84 case BufferFormat::YUV_420_BIPLANAR:
85 case BufferFormat::P010:
86 return 2;
87 case BufferFormat::YVU_420:
88 return 3;
89 }
90 NOTREACHED();
91 return 0;
92 }
93
SubsamplingFactorForBufferFormat(BufferFormat format,size_t plane)94 size_t SubsamplingFactorForBufferFormat(BufferFormat format, size_t plane) {
95 switch (format) {
96 case BufferFormat::R_8:
97 case BufferFormat::R_16:
98 case BufferFormat::RG_88:
99 case BufferFormat::BGR_565:
100 case BufferFormat::RGBA_4444:
101 case BufferFormat::RGBX_8888:
102 case BufferFormat::RGBA_8888:
103 case BufferFormat::BGRX_8888:
104 case BufferFormat::BGRA_1010102:
105 case BufferFormat::RGBA_1010102:
106 case BufferFormat::BGRA_8888:
107 case BufferFormat::RGBA_F16:
108 return 1;
109 case BufferFormat::YVU_420: {
110 static size_t factor[] = {1, 2, 2};
111 DCHECK_LT(static_cast<size_t>(plane), base::size(factor));
112 return factor[plane];
113 }
114 case BufferFormat::YUV_420_BIPLANAR:
115 case BufferFormat::P010: {
116 static size_t factor[] = {1, 2};
117 DCHECK_LT(static_cast<size_t>(plane), base::size(factor));
118 return factor[plane];
119 }
120 }
121 NOTREACHED();
122 return 0;
123 }
124
RowSizeForBufferFormat(size_t width,BufferFormat format,size_t plane)125 size_t RowSizeForBufferFormat(size_t width, BufferFormat format, size_t plane) {
126 size_t row_size = 0;
127 bool valid = RowSizeForBufferFormatChecked(width, format, plane, &row_size);
128 DCHECK(valid);
129 return row_size;
130 }
131
RowSizeForBufferFormatChecked(size_t width,BufferFormat format,size_t plane,size_t * size_in_bytes)132 bool RowSizeForBufferFormatChecked(size_t width,
133 BufferFormat format,
134 size_t plane,
135 size_t* size_in_bytes) {
136 base::CheckedNumeric<size_t> checked_size = width;
137 switch (format) {
138 case BufferFormat::R_8:
139 checked_size += 3;
140 if (!checked_size.IsValid())
141 return false;
142 *size_in_bytes = (checked_size & ~0x3).ValueOrDie();
143 return true;
144 case BufferFormat::R_16:
145 case BufferFormat::RG_88:
146 case BufferFormat::BGR_565:
147 case BufferFormat::RGBA_4444:
148 checked_size *= 2;
149 checked_size += 3;
150 if (!checked_size.IsValid())
151 return false;
152 *size_in_bytes = (checked_size & ~0x3).ValueOrDie();
153 return true;
154 case BufferFormat::BGRX_8888:
155 case BufferFormat::BGRA_1010102:
156 case BufferFormat::RGBA_1010102:
157 case BufferFormat::RGBX_8888:
158 case BufferFormat::RGBA_8888:
159 case BufferFormat::BGRA_8888:
160 checked_size *= 4;
161 if (!checked_size.IsValid())
162 return false;
163 *size_in_bytes = checked_size.ValueOrDie();
164 return true;
165 case BufferFormat::RGBA_F16:
166 checked_size *= 8;
167 if (!checked_size.IsValid())
168 return false;
169 *size_in_bytes = checked_size.ValueOrDie();
170 return true;
171 case BufferFormat::YVU_420:
172 DCHECK_EQ(0u, width % 2);
173 *size_in_bytes = width / SubsamplingFactorForBufferFormat(format, plane);
174 return true;
175 case BufferFormat::YUV_420_BIPLANAR:
176 DCHECK_EQ(width % 2, 0u);
177 *size_in_bytes = width;
178 return true;
179 case BufferFormat::P010:
180 DCHECK_EQ(width % 2, 0u);
181 *size_in_bytes = 2 * width;
182 return true;
183 }
184 NOTREACHED();
185 return false;
186 }
187
BufferSizeForBufferFormat(const Size & size,BufferFormat format)188 size_t BufferSizeForBufferFormat(const Size& size, BufferFormat format) {
189 size_t buffer_size = 0;
190 bool valid = BufferSizeForBufferFormatChecked(size, format, &buffer_size);
191 DCHECK(valid);
192 return buffer_size;
193 }
194
BufferSizeForBufferFormatChecked(const Size & size,BufferFormat format,size_t * size_in_bytes)195 bool BufferSizeForBufferFormatChecked(const Size& size,
196 BufferFormat format,
197 size_t* size_in_bytes) {
198 base::CheckedNumeric<size_t> checked_size = 0;
199 size_t num_planes = NumberOfPlanesForLinearBufferFormat(format);
200 for (size_t i = 0; i < num_planes; ++i) {
201 size_t row_size = 0;
202 if (!RowSizeForBufferFormatChecked(size.width(), format, i, &row_size))
203 return false;
204 base::CheckedNumeric<size_t> checked_plane_size = row_size;
205 checked_plane_size *= size.height() /
206 SubsamplingFactorForBufferFormat(format, i);
207 if (!checked_plane_size.IsValid())
208 return false;
209 checked_size += checked_plane_size.ValueOrDie();
210 if (!checked_size.IsValid())
211 return false;
212 }
213 *size_in_bytes = checked_size.ValueOrDie();
214 return true;
215 }
216
BufferOffsetForBufferFormat(const Size & size,BufferFormat format,size_t plane)217 size_t BufferOffsetForBufferFormat(const Size& size,
218 BufferFormat format,
219 size_t plane) {
220 DCHECK_LT(plane, gfx::NumberOfPlanesForLinearBufferFormat(format));
221 switch (format) {
222 case BufferFormat::R_8:
223 case BufferFormat::R_16:
224 case BufferFormat::RG_88:
225 case BufferFormat::BGR_565:
226 case BufferFormat::RGBA_4444:
227 case BufferFormat::RGBX_8888:
228 case BufferFormat::RGBA_8888:
229 case BufferFormat::BGRX_8888:
230 case BufferFormat::BGRA_1010102:
231 case BufferFormat::RGBA_1010102:
232 case BufferFormat::BGRA_8888:
233 case BufferFormat::RGBA_F16:
234 return 0;
235 case BufferFormat::YVU_420: {
236 static size_t offset_in_2x2_sub_sampling_sizes[] = {0, 4, 5};
237 DCHECK_LT(plane, base::size(offset_in_2x2_sub_sampling_sizes));
238 return offset_in_2x2_sub_sampling_sizes[plane] * (size.width() / 2) *
239 (size.height() / 2);
240 }
241 case gfx::BufferFormat::YUV_420_BIPLANAR: {
242 static size_t offset_in_2x2_sub_sampling_sizes[] = {0, 4};
243 DCHECK_LT(plane, base::size(offset_in_2x2_sub_sampling_sizes));
244 return offset_in_2x2_sub_sampling_sizes[plane] * (size.width() / 2) *
245 (size.height() / 2);
246 }
247 case BufferFormat::P010: {
248 static size_t offset_in_2x2_sub_sampling_sizes[] = {0, 4};
249 DCHECK_LT(plane, base::size(offset_in_2x2_sub_sampling_sizes));
250 return 2 * offset_in_2x2_sub_sampling_sizes[plane] *
251 (size.width() / 2 + size.height() / 2);
252 }
253 }
254 NOTREACHED();
255 return 0;
256 }
257
BufferFormatToString(BufferFormat format)258 const char* BufferFormatToString(BufferFormat format) {
259 switch (format) {
260 case BufferFormat::R_8:
261 return "R_8";
262 case BufferFormat::R_16:
263 return "R_16";
264 case BufferFormat::RG_88:
265 return "RG_88";
266 case BufferFormat::BGR_565:
267 return "BGR_565";
268 case BufferFormat::RGBA_4444:
269 return "RGBA_4444";
270 case BufferFormat::RGBX_8888:
271 return "RGBX_8888";
272 case BufferFormat::RGBA_8888:
273 return "RGBA_8888";
274 case BufferFormat::BGRX_8888:
275 return "BGRX_8888";
276 case BufferFormat::BGRA_1010102:
277 return "BGRA_1010102";
278 case BufferFormat::RGBA_1010102:
279 return "RGBA_1010102";
280 case BufferFormat::BGRA_8888:
281 return "BGRA_8888";
282 case BufferFormat::RGBA_F16:
283 return "RGBA_F16";
284 case BufferFormat::YVU_420:
285 return "YVU_420";
286 case BufferFormat::YUV_420_BIPLANAR:
287 return "YUV_420_BIPLANAR";
288 case BufferFormat::P010:
289 return "P010";
290 }
291 NOTREACHED()
292 << "Invalid BufferFormat: "
293 << static_cast<typename std::underlying_type<BufferFormat>::type>(format);
294 return "Invalid Format";
295 }
296
297 } // namespace gfx
298