• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkYUVAPixmaps.h"
9 
10 #include "include/core/SkAlphaType.h"
11 #include "include/private/base/SkDebug.h"
12 #include "src/base/SkRectMemcpy.h"
13 #include "src/core/SkImageInfoPriv.h"
14 #include "src/core/SkYUVAInfoLocation.h"
15 
16 #include <algorithm>
17 #include <cstdint>
18 #include <utility>
19 
enableDataType(DataType type,int numChannels)20 void SkYUVAPixmapInfo::SupportedDataTypes::enableDataType(DataType type, int numChannels) {
21     if (numChannels < 1 || numChannels > 4) {
22         return;
23     }
24     fDataTypeSupport[static_cast<size_t>(type) + (numChannels - 1)*kDataTypeCnt] = true;
25 }
26 
27 //////////////////////////////////////////////////////////////////////////////
28 
NumChannelsAndDataType(SkColorType ct)29 std::tuple<int, SkYUVAPixmapInfo::DataType> SkYUVAPixmapInfo::NumChannelsAndDataType(
30         SkColorType ct) {
31     // We could allow BGR[A] color types, but then we'd have to decide whether B should be the 0th
32     // or 2nd channel. Our docs currently say channel order is always R=0, G=1, B=2[, A=3].
33     switch (ct) {
34         case kAlpha_8_SkColorType:
35         case kGray_8_SkColorType:    return {1, DataType::kUnorm8 };
36         case kA16_unorm_SkColorType: return {1, DataType::kUnorm16};
37         case kA16_float_SkColorType: return {1, DataType::kFloat16};
38 
39         case kR8G8_unorm_SkColorType:   return {2, DataType::kUnorm8  };
40         case kR16G16_unorm_SkColorType: return {2, DataType::kUnorm16 };
41         case kR16G16_float_SkColorType: return {2, DataType::kFloat16 };
42 
43         case kRGB_888x_SkColorType:    return {3, DataType::kUnorm8          };
44         case kRGB_101010x_SkColorType: return {3, DataType::kUnorm10_Unorm2  };
45 
46         case kRGBA_8888_SkColorType:          return {4, DataType::kUnorm8  };
47         case kR16G16B16A16_unorm_SkColorType: return {4, DataType::kUnorm16 };
48         case kRGBA_F16_SkColorType:           return {4, DataType::kFloat16 };
49         case kRGBA_F16Norm_SkColorType:       return {4, DataType::kFloat16 };
50         case kRGBA_1010102_SkColorType:       return {4, DataType::kUnorm10_Unorm2 };
51 
52         default: return {0, DataType::kUnorm8 };
53     }
54 }
55 
SkYUVAPixmapInfo(const SkYUVAInfo & yuvaInfo,const SkColorType colorTypes[kMaxPlanes],const size_t rowBytes[kMaxPlanes])56 SkYUVAPixmapInfo::SkYUVAPixmapInfo(const SkYUVAInfo& yuvaInfo,
57                                    const SkColorType colorTypes[kMaxPlanes],
58                                    const size_t rowBytes[kMaxPlanes])
59         : fYUVAInfo(yuvaInfo) {
60     if (!yuvaInfo.isValid()) {
61         *this = {};
62         SkASSERT(!this->isValid());
63         return;
64     }
65     SkISize planeDimensions[4];
66     int n = yuvaInfo.planeDimensions(planeDimensions);
67     size_t tempRowBytes[kMaxPlanes];
68     if (!rowBytes) {
69         for (int i = 0; i < n; ++i) {
70             tempRowBytes[i] = SkColorTypeBytesPerPixel(colorTypes[i]) * planeDimensions[i].width();
71         }
72         rowBytes = tempRowBytes;
73     }
74     bool ok = true;
75     for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
76         fRowBytes[i] = rowBytes[i];
77         // Use kUnpremul so that we never multiply alpha when copying data in.
78         fPlaneInfos[i] = SkImageInfo::Make(planeDimensions[i],
79                                            colorTypes[i],
80                                            kUnpremul_SkAlphaType);
81         int numRequiredChannels = yuvaInfo.numChannelsInPlane(i);
82         SkASSERT(numRequiredChannels > 0);
83         auto [numColorTypeChannels, colorTypeDataType] = NumChannelsAndDataType(colorTypes[i]);
84         ok &= i == 0 || colorTypeDataType == fDataType;
85         ok &= numColorTypeChannels >= numRequiredChannels;
86         ok &= fPlaneInfos[i].validRowBytes(fRowBytes[i]);
87         fDataType = colorTypeDataType;
88     }
89     if (!ok) {
90         *this = {};
91         SkASSERT(!this->isValid());
92     } else {
93         SkASSERT(this->isValid());
94     }
95 }
96 
SkYUVAPixmapInfo(const SkYUVAInfo & yuvaInfo,DataType dataType,const size_t rowBytes[kMaxPlanes])97 SkYUVAPixmapInfo::SkYUVAPixmapInfo(const SkYUVAInfo& yuvaInfo,
98                                    DataType dataType,
99                                    const size_t rowBytes[kMaxPlanes]) {
100     SkColorType colorTypes[kMaxPlanes] = {};
101     int numPlanes = yuvaInfo.numPlanes();
102     for (int i = 0; i < numPlanes; ++i) {
103         int numChannels = yuvaInfo.numChannelsInPlane(i);
104         colorTypes[i] = DefaultColorTypeForDataType(dataType, numChannels);
105     }
106     *this = SkYUVAPixmapInfo(yuvaInfo, colorTypes, rowBytes);
107 }
108 
operator ==(const SkYUVAPixmapInfo & that) const109 bool SkYUVAPixmapInfo::operator==(const SkYUVAPixmapInfo& that) const {
110     bool result = fYUVAInfo   == that.fYUVAInfo   &&
111                   fPlaneInfos == that.fPlaneInfos &&
112                   fRowBytes   == that.fRowBytes;
113     SkASSERT(!result || fDataType == that.fDataType);
114     return result;
115 }
116 
computeTotalBytes(size_t planeSizes[kMaxPlanes]) const117 size_t SkYUVAPixmapInfo::computeTotalBytes(size_t planeSizes[kMaxPlanes]) const {
118     if (!this->isValid()) {
119         if (planeSizes) {
120             std::fill_n(planeSizes, kMaxPlanes, 0);
121         }
122         return 0;
123     }
124     return fYUVAInfo.computeTotalBytes(fRowBytes.data(), planeSizes);
125 }
126 
initPixmapsFromSingleAllocation(void * memory,SkPixmap pixmaps[kMaxPlanes]) const127 bool SkYUVAPixmapInfo::initPixmapsFromSingleAllocation(void* memory,
128                                                        SkPixmap pixmaps[kMaxPlanes]) const {
129     if (!this->isValid()) {
130         return false;
131     }
132     SkASSERT(pixmaps);
133     char* addr = static_cast<char*>(memory);
134     int n = this->numPlanes();
135     for (int i = 0; i < n; ++i) {
136         SkASSERT(fPlaneInfos[i].validRowBytes(fRowBytes[i]));
137         pixmaps[i].reset(fPlaneInfos[i], addr, fRowBytes[i]);
138         size_t planeSize = pixmaps[i].rowBytes()*pixmaps[i].height();
139         SkASSERT(planeSize);
140         addr += planeSize;
141     }
142     for (int i = n; i < kMaxPlanes; ++i) {
143         pixmaps[i] = {};
144     }
145     return true;
146 }
147 
isSupported(const SupportedDataTypes & supportedDataTypes) const148 bool SkYUVAPixmapInfo::isSupported(const SupportedDataTypes& supportedDataTypes) const {
149     if (!this->isValid()) {
150         return false;
151     }
152     return supportedDataTypes.supported(fYUVAInfo.planeConfig(), fDataType);
153 }
154 
155 //////////////////////////////////////////////////////////////////////////////
156 
RecommendedRGBAColorType(DataType dataType)157 SkColorType SkYUVAPixmaps::RecommendedRGBAColorType(DataType dataType) {
158     switch (dataType) {
159         case DataType::kUnorm8:         return kRGBA_8888_SkColorType;
160         // F16 has better GPU support than 16 bit unorm. Often "16" bit unorm values are actually
161         // lower precision.
162         case DataType::kUnorm16:        return kRGBA_F16_SkColorType;
163         case DataType::kFloat16:        return kRGBA_F16_SkColorType;
164         case DataType::kUnorm10_Unorm2: return kRGBA_1010102_SkColorType;
165     }
166     SkUNREACHABLE;
167 }
168 
Allocate(const SkYUVAPixmapInfo & yuvaPixmapInfo)169 SkYUVAPixmaps SkYUVAPixmaps::Allocate(const SkYUVAPixmapInfo& yuvaPixmapInfo) {
170     if (!yuvaPixmapInfo.isValid()) {
171         return {};
172     }
173     return SkYUVAPixmaps(yuvaPixmapInfo,
174                          SkData::MakeUninitialized(yuvaPixmapInfo.computeTotalBytes()));
175 }
176 
FromData(const SkYUVAPixmapInfo & yuvaPixmapInfo,sk_sp<SkData> data)177 SkYUVAPixmaps SkYUVAPixmaps::FromData(const SkYUVAPixmapInfo& yuvaPixmapInfo, sk_sp<SkData> data) {
178     if (!yuvaPixmapInfo.isValid()) {
179         return {};
180     }
181     if (yuvaPixmapInfo.computeTotalBytes() > data->size()) {
182         return {};
183     }
184     return SkYUVAPixmaps(yuvaPixmapInfo, std::move(data));
185 }
186 
MakeCopy(const SkYUVAPixmaps & src)187 SkYUVAPixmaps SkYUVAPixmaps::MakeCopy(const SkYUVAPixmaps& src) {
188     if (!src.isValid()) {
189         return {};
190     }
191     SkYUVAPixmaps result = Allocate(src.pixmapsInfo());
192     int n = result.numPlanes();
193     for (int i = 0; i < n; ++i) {
194         // We use SkRectMemCpy rather than readPixels to ensure that we don't do any alpha type
195         // conversion.
196         const SkPixmap& s = src.plane(i);
197         const SkPixmap& d = result.plane(i);
198         SkRectMemcpy(d.writable_addr(),
199                      d.rowBytes(),
200                      s.addr(),
201                      s.rowBytes(),
202                      s.info().minRowBytes(),
203                      s.height());
204     }
205     return result;
206 }
207 
FromExternalMemory(const SkYUVAPixmapInfo & yuvaPixmapInfo,void * memory)208 SkYUVAPixmaps SkYUVAPixmaps::FromExternalMemory(const SkYUVAPixmapInfo& yuvaPixmapInfo,
209                                                 void* memory) {
210     if (!yuvaPixmapInfo.isValid()) {
211         return {};
212     }
213     SkPixmap pixmaps[kMaxPlanes];
214     yuvaPixmapInfo.initPixmapsFromSingleAllocation(memory, pixmaps);
215     return SkYUVAPixmaps(yuvaPixmapInfo.yuvaInfo(), yuvaPixmapInfo.dataType(), pixmaps);
216 }
217 
FromExternalPixmaps(const SkYUVAInfo & yuvaInfo,const SkPixmap pixmaps[kMaxPlanes])218 SkYUVAPixmaps SkYUVAPixmaps::FromExternalPixmaps(const SkYUVAInfo& yuvaInfo,
219                                                  const SkPixmap pixmaps[kMaxPlanes]) {
220     SkColorType colorTypes[kMaxPlanes] = {};
221     size_t rowBytes[kMaxPlanes] = {};
222     int numPlanes = yuvaInfo.numPlanes();
223     for (int i = 0; i < numPlanes; ++i) {
224         colorTypes[i] = pixmaps[i].colorType();
225         rowBytes[i] = pixmaps[i].rowBytes();
226     }
227     SkYUVAPixmapInfo yuvaPixmapInfo(yuvaInfo, colorTypes, rowBytes);
228     if (!yuvaPixmapInfo.isValid()) {
229         return {};
230     }
231     return SkYUVAPixmaps(yuvaInfo, yuvaPixmapInfo.dataType(), pixmaps);
232 }
233 
SkYUVAPixmaps(const SkYUVAPixmapInfo & yuvaPixmapInfo,sk_sp<SkData> data)234 SkYUVAPixmaps::SkYUVAPixmaps(const SkYUVAPixmapInfo& yuvaPixmapInfo, sk_sp<SkData> data)
235         : fData(std::move(data))
236         , fYUVAInfo(yuvaPixmapInfo.yuvaInfo())
237         , fDataType(yuvaPixmapInfo.dataType()) {
238     SkASSERT(yuvaPixmapInfo.isValid());
239     SkASSERT(yuvaPixmapInfo.computeTotalBytes() <= fData->size());
240     SkAssertResult(yuvaPixmapInfo.initPixmapsFromSingleAllocation(fData->writable_data(),
241                                                                   fPlanes.data()));
242 }
243 
SkYUVAPixmaps(const SkYUVAInfo & yuvaInfo,DataType dataType,const SkPixmap pixmaps[kMaxPlanes])244 SkYUVAPixmaps::SkYUVAPixmaps(const SkYUVAInfo& yuvaInfo,
245                              DataType dataType,
246                              const SkPixmap pixmaps[kMaxPlanes])
247         : fYUVAInfo(yuvaInfo), fDataType(dataType) {
248     std::copy_n(pixmaps, yuvaInfo.numPlanes(), fPlanes.data());
249 }
250 
pixmapsInfo() const251 SkYUVAPixmapInfo SkYUVAPixmaps::pixmapsInfo() const {
252     if (!this->isValid()) {
253         return {};
254     }
255     SkColorType colorTypes[kMaxPlanes] = {};
256     size_t rowBytes[kMaxPlanes] = {};
257     int numPlanes = this->numPlanes();
258     for (int i = 0; i < numPlanes; ++i) {
259         colorTypes[i] = fPlanes[i].colorType();
260         rowBytes[i] = fPlanes[i].rowBytes();
261     }
262     return {fYUVAInfo, colorTypes, rowBytes};
263 }
264 
toYUVALocations() const265 SkYUVAInfo::YUVALocations SkYUVAPixmaps::toYUVALocations() const {
266     uint32_t channelFlags[] = {SkColorTypeChannelFlags(fPlanes[0].colorType()),
267                                SkColorTypeChannelFlags(fPlanes[1].colorType()),
268                                SkColorTypeChannelFlags(fPlanes[2].colorType()),
269                                SkColorTypeChannelFlags(fPlanes[3].colorType())};
270     auto result = fYUVAInfo.toYUVALocations(channelFlags);
271     SkDEBUGCODE(int numPlanes;)
272     SkASSERT(SkYUVAInfo::YUVALocation::AreValidLocations(result, &numPlanes));
273     SkASSERT(numPlanes == this->numPlanes());
274     return result;
275 }
276