xref: /aosp_15_r20/external/skia/include/core/SkYUVAPixmaps.h (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 #ifndef SkYUVAPixmaps_DEFINED
9 #define SkYUVAPixmaps_DEFINED
10 
11 #include "include/core/SkColorType.h"
12 #include "include/core/SkData.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkPixmap.h"
15 #include "include/core/SkRefCnt.h"
16 #include "include/core/SkSize.h"
17 #include "include/core/SkTypes.h"
18 #include "include/core/SkYUVAInfo.h"
19 #include "include/private/base/SkTo.h"
20 
21 #include <array>
22 #include <bitset>
23 #include <cstddef>
24 #include <tuple>
25 
26 /**
27  * SkYUVAInfo combined with per-plane SkColorTypes and row bytes. Fully specifies the SkPixmaps
28  * for a YUVA image without the actual pixel memory and data.
29  */
30 class SK_API SkYUVAPixmapInfo {
31 public:
32     static constexpr auto kMaxPlanes = SkYUVAInfo::kMaxPlanes;
33 
34     using PlaneConfig  = SkYUVAInfo::PlaneConfig;
35     using Subsampling  = SkYUVAInfo::Subsampling;
36 
37     /**
38      * Data type for Y, U, V, and possibly A channels independent of how values are packed into
39      * planes.
40      **/
41     enum class DataType {
42         kUnorm8,          ///< 8 bit unsigned normalized
43         kUnorm16,         ///< 16 bit unsigned normalized
44         kFloat16,         ///< 16 bit (half) floating point
45         kUnorm10_Unorm2,  ///< 10 bit unorm for Y, U, and V. 2 bit unorm for alpha (if present).
46 
47         kLast = kUnorm10_Unorm2
48     };
49     static constexpr int kDataTypeCnt = static_cast<int>(DataType::kLast) + 1;
50 
51     class SK_API SupportedDataTypes {
52     public:
53         /** Defaults to nothing supported. */
54         constexpr SupportedDataTypes() = default;
55 
56         /** All legal combinations of PlaneConfig and DataType are supported. */
57         static constexpr SupportedDataTypes All();
58 
59         /**
60          * Checks whether there is a supported combination of color types for planes structured
61          * as indicated by PlaneConfig with channel data types as indicated by DataType.
62          */
63         constexpr bool supported(PlaneConfig, DataType) const;
64 
65         /**
66          * Update to add support for pixmaps with numChannel channels where each channel is
67          * represented as DataType.
68          */
69         void enableDataType(DataType, int numChannels);
70 
71     private:
72         // The bit for DataType dt with n channels is at index kDataTypeCnt*(n-1) + dt.
73         std::bitset<kDataTypeCnt*4> fDataTypeSupport = {};
74     };
75 
76     /**
77      * Gets the default SkColorType to use with numChannels channels, each represented as DataType.
78      * Returns kUnknown_SkColorType if no such color type.
79      */
80     static constexpr SkColorType DefaultColorTypeForDataType(DataType dataType, int numChannels);
81 
82     /**
83      * If the SkColorType is supported for YUVA pixmaps this will return the number of YUVA channels
84      * that can be stored in a plane of this color type and what the DataType is of those channels.
85      * If the SkColorType is not supported as a YUVA plane the number of channels is reported as 0
86      * and the DataType returned should be ignored.
87      */
88     static std::tuple<int, DataType> NumChannelsAndDataType(SkColorType);
89 
90     /** Default SkYUVAPixmapInfo is invalid. */
91     SkYUVAPixmapInfo() = default;
92 
93     /**
94      * Initializes the SkYUVAPixmapInfo from a SkYUVAInfo with per-plane color types and row bytes.
95      * This will be invalid if the colorTypes aren't compatible with the SkYUVAInfo or if a
96      * rowBytes entry is not valid for the plane dimensions and color type. Color type and
97      * row byte values beyond the number of planes in SkYUVAInfo are ignored. All SkColorTypes
98      * must have the same DataType or this will be invalid.
99      *
100      * If rowBytes is nullptr then bpp*width is assumed for each plane.
101      */
102     SkYUVAPixmapInfo(const SkYUVAInfo&,
103                      const SkColorType[kMaxPlanes],
104                      const size_t rowBytes[kMaxPlanes]);
105     /**
106      * Like above but uses DefaultColorTypeForDataType to determine each plane's SkColorType. If
107      * rowBytes is nullptr then bpp*width is assumed for each plane.
108      */
109     SkYUVAPixmapInfo(const SkYUVAInfo&, DataType, const size_t rowBytes[kMaxPlanes]);
110 
111     SkYUVAPixmapInfo(const SkYUVAPixmapInfo&) = default;
112 
113     SkYUVAPixmapInfo& operator=(const SkYUVAPixmapInfo&) = default;
114 
115     bool operator==(const SkYUVAPixmapInfo&) const;
116     bool operator!=(const SkYUVAPixmapInfo& that) const { return !(*this == that); }
117 
yuvaInfo()118     const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; }
119 
yuvColorSpace()120     SkYUVColorSpace yuvColorSpace() const { return fYUVAInfo.yuvColorSpace(); }
121 
122     /** The number of SkPixmap planes, 0 if this SkYUVAPixmapInfo is invalid. */
numPlanes()123     int numPlanes() const { return fYUVAInfo.numPlanes(); }
124 
125     /** The per-YUV[A] channel data type. */
dataType()126     DataType dataType() const { return fDataType; }
127 
128     /**
129      * Row bytes for the ith plane. Returns zero if i >= numPlanes() or this SkYUVAPixmapInfo is
130      * invalid.
131      */
rowBytes(int i)132     size_t rowBytes(int i) const { return fRowBytes[static_cast<size_t>(i)]; }
133 
134     /** Image info for the ith plane, or default SkImageInfo if i >= numPlanes() */
planeInfo(int i)135     const SkImageInfo& planeInfo(int i) const { return fPlaneInfos[static_cast<size_t>(i)]; }
136 
137     /**
138      * Determine size to allocate for all planes. Optionally retrieves the per-plane sizes in
139      * planeSizes if not null. If total size overflows will return SIZE_MAX and set all planeSizes
140      * to SIZE_MAX. Returns 0 and fills planesSizes with 0 if this SkYUVAPixmapInfo is not valid.
141      */
142     size_t computeTotalBytes(size_t planeSizes[kMaxPlanes] = nullptr) const;
143 
144     /**
145      * Takes an allocation that is assumed to be at least computeTotalBytes() in size and configures
146      * the first numPlanes() entries in pixmaps array to point into that memory. The remaining
147      * entries of pixmaps are default initialized. Fails if this SkYUVAPixmapInfo not valid.
148      */
149     bool initPixmapsFromSingleAllocation(void* memory, SkPixmap pixmaps[kMaxPlanes]) const;
150 
151     /**
152      * Returns true if this has been configured with a non-empty dimensioned SkYUVAInfo with
153      * compatible color types and row bytes.
154      */
isValid()155     bool isValid() const { return fYUVAInfo.isValid(); }
156 
157     /** Is this valid and does it use color types allowed by the passed SupportedDataTypes? */
158     bool isSupported(const SupportedDataTypes&) const;
159 
160 private:
161     SkYUVAInfo fYUVAInfo;
162     std::array<SkImageInfo, kMaxPlanes> fPlaneInfos = {};
163     std::array<size_t, kMaxPlanes> fRowBytes = {};
164     DataType fDataType = DataType::kUnorm8;
165     static_assert(kUnknown_SkColorType == 0, "default init isn't kUnknown");
166 };
167 
168 /**
169  * Helper to store SkPixmap planes as described by a SkYUVAPixmapInfo. Can be responsible for
170  * allocating/freeing memory for pixmaps or use external memory.
171  */
172 class SK_API SkYUVAPixmaps {
173 public:
174     using DataType = SkYUVAPixmapInfo::DataType;
175     static constexpr auto kMaxPlanes = SkYUVAPixmapInfo::kMaxPlanes;
176 
177     static SkColorType RecommendedRGBAColorType(DataType);
178 
179     /** Allocate space for pixmaps' pixels in the SkYUVAPixmaps. */
180     static SkYUVAPixmaps Allocate(const SkYUVAPixmapInfo& yuvaPixmapInfo);
181 
182     /**
183      * Use storage in SkData as backing store for pixmaps' pixels. SkData is retained by the
184      * SkYUVAPixmaps.
185      */
186     static SkYUVAPixmaps FromData(const SkYUVAPixmapInfo&, sk_sp<SkData>);
187 
188     /**
189      * Makes a deep copy of the src SkYUVAPixmaps. The returned SkYUVAPixmaps owns its planes'
190      * backing stores.
191      */
192     static SkYUVAPixmaps MakeCopy(const SkYUVAPixmaps& src);
193 
194     /**
195      * Use passed in memory as backing store for pixmaps' pixels. Caller must ensure memory remains
196      * allocated while pixmaps are in use. There must be at least
197      * SkYUVAPixmapInfo::computeTotalBytes() allocated starting at memory.
198      */
199     static SkYUVAPixmaps FromExternalMemory(const SkYUVAPixmapInfo&, void* memory);
200 
201     /**
202      * Wraps existing SkPixmaps. The SkYUVAPixmaps will have no ownership of the SkPixmaps' pixel
203      * memory so the caller must ensure it remains valid. Will return an invalid SkYUVAPixmaps if
204      * the SkYUVAInfo isn't compatible with the SkPixmap array (number of planes, plane dimensions,
205      * sufficient color channels in planes, ...).
206      */
207     static SkYUVAPixmaps FromExternalPixmaps(const SkYUVAInfo&, const SkPixmap[kMaxPlanes]);
208 
209     /** Default SkYUVAPixmaps is invalid. */
210     SkYUVAPixmaps() = default;
211     ~SkYUVAPixmaps() = default;
212 
213     SkYUVAPixmaps(SkYUVAPixmaps&& that) = default;
214     SkYUVAPixmaps& operator=(SkYUVAPixmaps&& that) = default;
215     SkYUVAPixmaps(const SkYUVAPixmaps&) = default;
216     SkYUVAPixmaps& operator=(const SkYUVAPixmaps& that) = default;
217 
218     /** Does have initialized pixmaps compatible with its SkYUVAInfo. */
isValid()219     bool isValid() const { return !fYUVAInfo.dimensions().isEmpty(); }
220 
yuvaInfo()221     const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; }
222 
dataType()223     DataType dataType() const { return fDataType; }
224 
225     SkYUVAPixmapInfo pixmapsInfo() const;
226 
227     /** Number of pixmap planes or 0 if this SkYUVAPixmaps is invalid. */
numPlanes()228     int numPlanes() const { return this->isValid() ? fYUVAInfo.numPlanes() : 0; }
229 
230     /**
231      * Access the SkPixmap planes. They are default initialized if this is not a valid
232      * SkYUVAPixmaps.
233      */
planes()234     const std::array<SkPixmap, kMaxPlanes>& planes() const { return fPlanes; }
235 
236     /**
237      * Get the ith SkPixmap plane. SkPixmap will be default initialized if i >= numPlanes or this
238      * SkYUVAPixmaps is invalid.
239      */
plane(int i)240     const SkPixmap& plane(int i) const { return fPlanes[SkToSizeT(i)]; }
241 
242     /**
243      * Computes a YUVALocations representation of the planar layout. The result is guaranteed to be
244      * valid if this->isValid().
245      */
246     SkYUVAInfo::YUVALocations toYUVALocations() const;
247 
248     /** Does this SkPixmaps own the backing store of the planes? */
ownsStorage()249     bool ownsStorage() const { return SkToBool(fData); }
250 
251 private:
252     SkYUVAPixmaps(const SkYUVAPixmapInfo&, sk_sp<SkData>);
253     SkYUVAPixmaps(const SkYUVAInfo&, DataType, const SkPixmap[kMaxPlanes]);
254 
255     std::array<SkPixmap, kMaxPlanes> fPlanes = {};
256     sk_sp<SkData> fData;
257     SkYUVAInfo fYUVAInfo;
258     DataType fDataType;
259 };
260 
261 //////////////////////////////////////////////////////////////////////////////
262 
All()263 constexpr SkYUVAPixmapInfo::SupportedDataTypes SkYUVAPixmapInfo::SupportedDataTypes::All() {
264     using ULL = unsigned long long; // bitset cons. takes this.
265     ULL bits = 0;
266     for (ULL c = 1; c <= 4; ++c) {
267         for (ULL dt = 0; dt <= ULL(kDataTypeCnt); ++dt) {
268             if (DefaultColorTypeForDataType(static_cast<DataType>(dt),
269                                             static_cast<int>(c)) != kUnknown_SkColorType) {
270                 bits |= ULL(1) << (dt + static_cast<ULL>(kDataTypeCnt)*(c - 1));
271             }
272         }
273     }
274     SupportedDataTypes combinations;
275     combinations.fDataTypeSupport = bits;
276     return combinations;
277 }
278 
supported(PlaneConfig config,DataType type)279 constexpr bool SkYUVAPixmapInfo::SupportedDataTypes::supported(PlaneConfig config,
280                                                                DataType type) const {
281     int n = SkYUVAInfo::NumPlanes(config);
282     for (int i = 0; i < n; ++i) {
283         auto c = static_cast<size_t>(SkYUVAInfo::NumChannelsInPlane(config, i));
284         SkASSERT(c >= 1 && c <= 4);
285         if (!fDataTypeSupport[static_cast<size_t>(type) +
286                               (c - 1)*static_cast<size_t>(kDataTypeCnt)]) {
287             return false;
288         }
289     }
290     return true;
291 }
292 
DefaultColorTypeForDataType(DataType dataType,int numChannels)293 constexpr SkColorType SkYUVAPixmapInfo::DefaultColorTypeForDataType(DataType dataType,
294                                                                     int numChannels) {
295     switch (numChannels) {
296         case 1:
297             switch (dataType) {
298                 case DataType::kUnorm8:         return kGray_8_SkColorType;
299                 case DataType::kUnorm16:        return kA16_unorm_SkColorType;
300                 case DataType::kFloat16:        return kA16_float_SkColorType;
301                 case DataType::kUnorm10_Unorm2: return kUnknown_SkColorType;
302             }
303             break;
304         case 2:
305             switch (dataType) {
306                 case DataType::kUnorm8:         return kR8G8_unorm_SkColorType;
307                 case DataType::kUnorm16:        return kR16G16_unorm_SkColorType;
308                 case DataType::kFloat16:        return kR16G16_float_SkColorType;
309                 case DataType::kUnorm10_Unorm2: return kUnknown_SkColorType;
310             }
311             break;
312         case 3:
313             // None of these are tightly packed. The intended use case is for interleaved YUVA
314             // planes where we're forcing opaqueness by ignoring the alpha values.
315             // There are "x" rather than "A" variants for Unorm8 and Unorm10_Unorm2 but we don't
316             // choose them because 1) there is no inherent advantage and 2) there is better support
317             // in the GPU backend for the "A" versions.
318             switch (dataType) {
319                 case DataType::kUnorm8:         return kRGBA_8888_SkColorType;
320                 case DataType::kUnorm16:        return kR16G16B16A16_unorm_SkColorType;
321                 case DataType::kFloat16:        return kRGBA_F16_SkColorType;
322                 case DataType::kUnorm10_Unorm2: return kRGBA_1010102_SkColorType;
323             }
324             break;
325         case 4:
326             switch (dataType) {
327                 case DataType::kUnorm8:         return kRGBA_8888_SkColorType;
328                 case DataType::kUnorm16:        return kR16G16B16A16_unorm_SkColorType;
329                 case DataType::kFloat16:        return kRGBA_F16_SkColorType;
330                 case DataType::kUnorm10_Unorm2: return kRGBA_1010102_SkColorType;
331             }
332             break;
333     }
334     return kUnknown_SkColorType;
335 }
336 
337 #endif
338