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