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