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