xref: /aosp_15_r20/external/skia/src/core/SkYUVAPixmaps.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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