Coverage Report

Created: 2024-05-20 07:14

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