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 case kRGB_F16F16F16x_SkColorType: return {3, DataType::kFloat16 };
46
47 case kRGBA_8888_SkColorType: return {4, DataType::kUnorm8 };
48 case kR16G16B16A16_unorm_SkColorType: return {4, DataType::kUnorm16 };
49 case kRGBA_F16_SkColorType: return {4, DataType::kFloat16 };
50 case kRGBA_F16Norm_SkColorType: return {4, DataType::kFloat16 };
51 case kRGBA_1010102_SkColorType: return {4, DataType::kUnorm10_Unorm2 };
52
53 default: return {0, DataType::kUnorm8 };
54 }
55 }
56
SkYUVAPixmapInfo(const SkYUVAInfo & yuvaInfo,const SkColorType colorTypes[kMaxPlanes],const size_t rowBytes[kMaxPlanes])57 SkYUVAPixmapInfo::SkYUVAPixmapInfo(const SkYUVAInfo& yuvaInfo,
58 const SkColorType colorTypes[kMaxPlanes],
59 const size_t rowBytes[kMaxPlanes])
60 : fYUVAInfo(yuvaInfo) {
61 if (!yuvaInfo.isValid()) {
62 *this = {};
63 SkASSERT(!this->isValid());
64 return;
65 }
66 SkISize planeDimensions[4];
67 int n = yuvaInfo.planeDimensions(planeDimensions);
68 size_t tempRowBytes[kMaxPlanes];
69 if (!rowBytes) {
70 for (int i = 0; i < n; ++i) {
71 tempRowBytes[i] = SkColorTypeBytesPerPixel(colorTypes[i]) * planeDimensions[i].width();
72 }
73 rowBytes = tempRowBytes;
74 }
75 bool ok = true;
76 for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
77 fRowBytes[i] = rowBytes[i];
78 // Use kUnpremul so that we never multiply alpha when copying data in.
79 fPlaneInfos[i] = SkImageInfo::Make(planeDimensions[i],
80 colorTypes[i],
81 kUnpremul_SkAlphaType);
82 int numRequiredChannels = yuvaInfo.numChannelsInPlane(i);
83 SkASSERT(numRequiredChannels > 0);
84 auto [numColorTypeChannels, colorTypeDataType] = NumChannelsAndDataType(colorTypes[i]);
85 ok &= i == 0 || colorTypeDataType == fDataType;
86 ok &= numColorTypeChannels >= numRequiredChannels;
87 ok &= fPlaneInfos[i].validRowBytes(fRowBytes[i]);
88 fDataType = colorTypeDataType;
89 }
90 if (!ok) {
91 *this = {};
92 SkASSERT(!this->isValid());
93 } else {
94 SkASSERT(this->isValid());
95 }
96 }
97
SkYUVAPixmapInfo(const SkYUVAInfo & yuvaInfo,DataType dataType,const size_t rowBytes[kMaxPlanes])98 SkYUVAPixmapInfo::SkYUVAPixmapInfo(const SkYUVAInfo& yuvaInfo,
99 DataType dataType,
100 const size_t rowBytes[kMaxPlanes]) {
101 SkColorType colorTypes[kMaxPlanes] = {};
102 int numPlanes = yuvaInfo.numPlanes();
103 for (int i = 0; i < numPlanes; ++i) {
104 int numChannels = yuvaInfo.numChannelsInPlane(i);
105 colorTypes[i] = DefaultColorTypeForDataType(dataType, numChannels);
106 }
107 *this = SkYUVAPixmapInfo(yuvaInfo, colorTypes, rowBytes);
108 }
109
operator ==(const SkYUVAPixmapInfo & that) const110 bool SkYUVAPixmapInfo::operator==(const SkYUVAPixmapInfo& that) const {
111 bool result = fYUVAInfo == that.fYUVAInfo &&
112 fPlaneInfos == that.fPlaneInfos &&
113 fRowBytes == that.fRowBytes;
114 SkASSERT(!result || fDataType == that.fDataType);
115 return result;
116 }
117
computeTotalBytes(size_t planeSizes[kMaxPlanes]) const118 size_t SkYUVAPixmapInfo::computeTotalBytes(size_t planeSizes[kMaxPlanes]) const {
119 if (!this->isValid()) {
120 if (planeSizes) {
121 std::fill_n(planeSizes, kMaxPlanes, 0);
122 }
123 return 0;
124 }
125 return fYUVAInfo.computeTotalBytes(fRowBytes.data(), planeSizes);
126 }
127
initPixmapsFromSingleAllocation(void * memory,SkPixmap pixmaps[kMaxPlanes]) const128 bool SkYUVAPixmapInfo::initPixmapsFromSingleAllocation(void* memory,
129 SkPixmap pixmaps[kMaxPlanes]) const {
130 if (!this->isValid()) {
131 return false;
132 }
133 SkASSERT(pixmaps);
134 char* addr = static_cast<char*>(memory);
135 int n = this->numPlanes();
136 for (int i = 0; i < n; ++i) {
137 SkASSERT(fPlaneInfos[i].validRowBytes(fRowBytes[i]));
138 pixmaps[i].reset(fPlaneInfos[i], addr, fRowBytes[i]);
139 size_t planeSize = pixmaps[i].rowBytes()*pixmaps[i].height();
140 SkASSERT(planeSize);
141 addr += planeSize;
142 }
143 for (int i = n; i < kMaxPlanes; ++i) {
144 pixmaps[i] = {};
145 }
146 return true;
147 }
148
isSupported(const SupportedDataTypes & supportedDataTypes) const149 bool SkYUVAPixmapInfo::isSupported(const SupportedDataTypes& supportedDataTypes) const {
150 if (!this->isValid()) {
151 return false;
152 }
153 return supportedDataTypes.supported(fYUVAInfo.planeConfig(), fDataType);
154 }
155
156 //////////////////////////////////////////////////////////////////////////////
157
RecommendedRGBAColorType(DataType dataType)158 SkColorType SkYUVAPixmaps::RecommendedRGBAColorType(DataType dataType) {
159 switch (dataType) {
160 case DataType::kUnorm8: return kRGBA_8888_SkColorType;
161 // F16 has better GPU support than 16 bit unorm. Often "16" bit unorm values are actually
162 // lower precision.
163 case DataType::kUnorm16: return kRGBA_F16_SkColorType;
164 case DataType::kFloat16: return kRGBA_F16_SkColorType;
165 case DataType::kUnorm10_Unorm2: return kRGBA_1010102_SkColorType;
166 }
167 SkUNREACHABLE;
168 }
169
Allocate(const SkYUVAPixmapInfo & yuvaPixmapInfo)170 SkYUVAPixmaps SkYUVAPixmaps::Allocate(const SkYUVAPixmapInfo& yuvaPixmapInfo) {
171 if (!yuvaPixmapInfo.isValid()) {
172 return {};
173 }
174 return SkYUVAPixmaps(yuvaPixmapInfo,
175 SkData::MakeUninitialized(yuvaPixmapInfo.computeTotalBytes()));
176 }
177
FromData(const SkYUVAPixmapInfo & yuvaPixmapInfo,sk_sp<SkData> data)178 SkYUVAPixmaps SkYUVAPixmaps::FromData(const SkYUVAPixmapInfo& yuvaPixmapInfo, sk_sp<SkData> data) {
179 if (!yuvaPixmapInfo.isValid()) {
180 return {};
181 }
182 if (yuvaPixmapInfo.computeTotalBytes() > data->size()) {
183 return {};
184 }
185 return SkYUVAPixmaps(yuvaPixmapInfo, std::move(data));
186 }
187
MakeCopy(const SkYUVAPixmaps & src)188 SkYUVAPixmaps SkYUVAPixmaps::MakeCopy(const SkYUVAPixmaps& src) {
189 if (!src.isValid()) {
190 return {};
191 }
192 SkYUVAPixmaps result = Allocate(src.pixmapsInfo());
193 int n = result.numPlanes();
194 for (int i = 0; i < n; ++i) {
195 // We use SkRectMemCpy rather than readPixels to ensure that we don't do any alpha type
196 // conversion.
197 const SkPixmap& s = src.plane(i);
198 const SkPixmap& d = result.plane(i);
199 SkRectMemcpy(d.writable_addr(),
200 d.rowBytes(),
201 s.addr(),
202 s.rowBytes(),
203 s.info().minRowBytes(),
204 s.height());
205 }
206 return result;
207 }
208
FromExternalMemory(const SkYUVAPixmapInfo & yuvaPixmapInfo,void * memory)209 SkYUVAPixmaps SkYUVAPixmaps::FromExternalMemory(const SkYUVAPixmapInfo& yuvaPixmapInfo,
210 void* memory) {
211 if (!yuvaPixmapInfo.isValid()) {
212 return {};
213 }
214 SkPixmap pixmaps[kMaxPlanes];
215 yuvaPixmapInfo.initPixmapsFromSingleAllocation(memory, pixmaps);
216 return SkYUVAPixmaps(yuvaPixmapInfo.yuvaInfo(), yuvaPixmapInfo.dataType(), pixmaps);
217 }
218
FromExternalPixmaps(const SkYUVAInfo & yuvaInfo,const SkPixmap pixmaps[kMaxPlanes])219 SkYUVAPixmaps SkYUVAPixmaps::FromExternalPixmaps(const SkYUVAInfo& yuvaInfo,
220 const SkPixmap pixmaps[kMaxPlanes]) {
221 SkColorType colorTypes[kMaxPlanes] = {};
222 size_t rowBytes[kMaxPlanes] = {};
223 int numPlanes = yuvaInfo.numPlanes();
224 for (int i = 0; i < numPlanes; ++i) {
225 colorTypes[i] = pixmaps[i].colorType();
226 rowBytes[i] = pixmaps[i].rowBytes();
227 }
228 SkYUVAPixmapInfo yuvaPixmapInfo(yuvaInfo, colorTypes, rowBytes);
229 if (!yuvaPixmapInfo.isValid()) {
230 return {};
231 }
232 return SkYUVAPixmaps(yuvaInfo, yuvaPixmapInfo.dataType(), pixmaps);
233 }
234
SkYUVAPixmaps(const SkYUVAPixmapInfo & yuvaPixmapInfo,sk_sp<SkData> data)235 SkYUVAPixmaps::SkYUVAPixmaps(const SkYUVAPixmapInfo& yuvaPixmapInfo, sk_sp<SkData> data)
236 : fData(std::move(data))
237 , fYUVAInfo(yuvaPixmapInfo.yuvaInfo())
238 , fDataType(yuvaPixmapInfo.dataType()) {
239 SkASSERT(yuvaPixmapInfo.isValid());
240 SkASSERT(yuvaPixmapInfo.computeTotalBytes() <= fData->size());
241 SkAssertResult(yuvaPixmapInfo.initPixmapsFromSingleAllocation(fData->writable_data(),
242 fPlanes.data()));
243 }
244
SkYUVAPixmaps(const SkYUVAInfo & yuvaInfo,DataType dataType,const SkPixmap pixmaps[kMaxPlanes])245 SkYUVAPixmaps::SkYUVAPixmaps(const SkYUVAInfo& yuvaInfo,
246 DataType dataType,
247 const SkPixmap pixmaps[kMaxPlanes])
248 : fYUVAInfo(yuvaInfo), fDataType(dataType) {
249 std::copy_n(pixmaps, yuvaInfo.numPlanes(), fPlanes.data());
250 }
251
pixmapsInfo() const252 SkYUVAPixmapInfo SkYUVAPixmaps::pixmapsInfo() const {
253 if (!this->isValid()) {
254 return {};
255 }
256 SkColorType colorTypes[kMaxPlanes] = {};
257 size_t rowBytes[kMaxPlanes] = {};
258 int numPlanes = this->numPlanes();
259 for (int i = 0; i < numPlanes; ++i) {
260 colorTypes[i] = fPlanes[i].colorType();
261 rowBytes[i] = fPlanes[i].rowBytes();
262 }
263 return {fYUVAInfo, colorTypes, rowBytes};
264 }
265
toYUVALocations() const266 SkYUVAInfo::YUVALocations SkYUVAPixmaps::toYUVALocations() const {
267 uint32_t channelFlags[] = {SkColorTypeChannelFlags(fPlanes[0].colorType()),
268 SkColorTypeChannelFlags(fPlanes[1].colorType()),
269 SkColorTypeChannelFlags(fPlanes[2].colorType()),
270 SkColorTypeChannelFlags(fPlanes[3].colorType())};
271 auto result = fYUVAInfo.toYUVALocations(channelFlags);
272 SkDEBUGCODE(int numPlanes;)
273 SkASSERT(SkYUVAInfo::YUVALocation::AreValidLocations(result, &numPlanes));
274 SkASSERT(numPlanes == this->numPlanes());
275 return result;
276 }
277