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