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