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