Coverage Report

Created: 2021-08-22 09:07

/src/skia/include/core/SkYUVAPixmaps.h
Line
Count
Source (jump to first uncovered line)
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/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
0
        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
0
    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
0
    SkYUVAPixmapInfo& operator=(const SkYUVAPixmapInfo&) = default;
113
114
    bool operator==(const SkYUVAPixmapInfo&) const;
115
0
    bool operator!=(const SkYUVAPixmapInfo& that) const { return !(*this == that); }
116
117
0
    const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; }
118
119
0
    SkYUVColorSpace yuvColorSpace() const { return fYUVAInfo.yuvColorSpace(); }
120
121
    /** The number of SkPixmap planes, 0 if this SkYUVAPixmapInfo is invalid. */
122
0
    int numPlanes() const { return fYUVAInfo.numPlanes(); }
123
124
    /** The per-YUV[A] channel data type. */
125
0
    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
     */
131
0
    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() */
134
0
    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
     */
154
0
    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
0
    SkYUVAPixmaps() = default;
210
0
    ~SkYUVAPixmaps() = default;
211
212
0
    SkYUVAPixmaps(SkYUVAPixmaps&& that) = default;
213
0
    SkYUVAPixmaps& operator=(SkYUVAPixmaps&& that) = default;
214
0
    SkYUVAPixmaps(const SkYUVAPixmaps&) = default;
215
0
    SkYUVAPixmaps& operator=(const SkYUVAPixmaps& that) = default;
216
217
    /** Does have initialized pixmaps compatible with its SkYUVAInfo. */
218
0
    bool isValid() const { return !fYUVAInfo.dimensions().isEmpty(); }
219
220
0
    const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; }
221
222
0
    DataType dataType() const { return fDataType; }
223
224
    SkYUVAPixmapInfo pixmapsInfo() const;
225
226
    /** Number of pixmap planes or 0 if this SkYUVAPixmaps is invalid. */
227
0
    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
     */
233
0
    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
     */
239
0
    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? */
248
0
    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
262
0
constexpr SkYUVAPixmapInfo::SupportedDataTypes SkYUVAPixmapInfo::SupportedDataTypes::All() {
263
0
    using ULL = unsigned long long; // bitset cons. takes this.
264
0
    ULL bits = 0;
265
0
    for (ULL c = 1; c <= 4; ++c) {
266
0
        for (ULL dt = 0; dt <= ULL(kDataTypeCnt); ++dt) {
267
0
            if (DefaultColorTypeForDataType(static_cast<DataType>(dt),
268
0
                                            static_cast<int>(c)) != kUnknown_SkColorType) {
269
0
                bits |= ULL(1) << (dt + static_cast<ULL>(kDataTypeCnt)*(c - 1));
270
0
            }
271
0
        }
272
0
    }
273
0
    SupportedDataTypes combinations;
274
0
    combinations.fDataTypeSupport = bits;
275
0
    return combinations;
276
0
}
277
278
constexpr bool SkYUVAPixmapInfo::SupportedDataTypes::supported(PlaneConfig config,
279
0
                                                               DataType type) const {
280
0
    int n = SkYUVAInfo::NumPlanes(config);
281
0
    for (int i = 0; i < n; ++i) {
282
0
        auto c = static_cast<size_t>(SkYUVAInfo::NumChannelsInPlane(config, i));
283
0
        SkASSERT(c >= 1 && c <= 4);
284
0
        if (!fDataTypeSupport[static_cast<size_t>(type) +
285
0
                              (c - 1)*static_cast<size_t>(kDataTypeCnt)]) {
286
0
            return false;
287
0
        }
288
0
    }
289
0
    return true;
290
0
}
Unexecuted instantiation: SkYUVAPixmapInfo::SupportedDataTypes::supported(SkYUVAInfo::PlaneConfig, SkYUVAPixmapInfo::DataType) const
Unexecuted instantiation: SkYUVAPixmapInfo::SupportedDataTypes::supported(SkYUVAInfo::PlaneConfig, SkYUVAPixmapInfo::DataType) const
291
292
constexpr SkColorType SkYUVAPixmapInfo::DefaultColorTypeForDataType(DataType dataType,
293
0
                                                                    int numChannels) {
294
0
    switch (numChannels) {
295
0
        case 1:
296
0
            switch (dataType) {
297
0
                case DataType::kUnorm8:         return kGray_8_SkColorType;
298
0
                case DataType::kUnorm16:        return kA16_unorm_SkColorType;
299
0
                case DataType::kFloat16:        return kA16_float_SkColorType;
300
0
                case DataType::kUnorm10_Unorm2: return kUnknown_SkColorType;
301
0
            }
302
0
            break;
303
0
        case 2:
304
0
            switch (dataType) {
305
0
                case DataType::kUnorm8:         return kR8G8_unorm_SkColorType;
306
0
                case DataType::kUnorm16:        return kR16G16_unorm_SkColorType;
307
0
                case DataType::kFloat16:        return kR16G16_float_SkColorType;
308
0
                case DataType::kUnorm10_Unorm2: return kUnknown_SkColorType;
309
0
            }
310
0
            break;
311
0
        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
0
            switch (dataType) {
318
0
                case DataType::kUnorm8:         return kRGBA_8888_SkColorType;
319
0
                case DataType::kUnorm16:        return kR16G16B16A16_unorm_SkColorType;
320
0
                case DataType::kFloat16:        return kRGBA_F16_SkColorType;
321
0
                case DataType::kUnorm10_Unorm2: return kRGBA_1010102_SkColorType;
322
0
            }
323
0
            break;
324
0
        case 4:
325
0
            switch (dataType) {
326
0
                case DataType::kUnorm8:         return kRGBA_8888_SkColorType;
327
0
                case DataType::kUnorm16:        return kR16G16B16A16_unorm_SkColorType;
328
0
                case DataType::kFloat16:        return kRGBA_F16_SkColorType;
329
0
                case DataType::kUnorm10_Unorm2: return kRGBA_1010102_SkColorType;
330
0
            }
331
0
            break;
332
0
    }
333
0
    return kUnknown_SkColorType;
334
0
}
335
336
#endif