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/gpu/GrYUVABackendTextures.h"
9
10#include "src/core/SkYUVAInfoLocation.h"
11
12static int num_channels(const GrBackendFormat& format) {
13    switch (format.channelMask()) {
14        case kRed_SkColorChannelFlag        : return 1;
15        case kAlpha_SkColorChannelFlag      : return 1;
16        case kGray_SkColorChannelFlag       : return 1;
17        case kGrayAlpha_SkColorChannelFlags : return 2;
18        case kRG_SkColorChannelFlags        : return 2;
19        case kRGB_SkColorChannelFlags       : return 3;
20        case kRGBA_SkColorChannelFlags      : return 4;
21        default                             : return 0;
22    }
23}
24
25GrYUVABackendTextureInfo::GrYUVABackendTextureInfo(const SkYUVAInfo& yuvaInfo,
26                                                   const GrBackendFormat formats[kMaxPlanes],
27                                                   GrMipmapped mipmapped,
28                                                   GrSurfaceOrigin origin)
29        : fYUVAInfo(yuvaInfo), fMipmapped(mipmapped), fTextureOrigin(origin) {
30    if (!yuvaInfo.isValid()) {
31        *this = {};
32        SkASSERT(!this->isValid());
33        return;
34    }
35    int n = yuvaInfo.numPlanes();
36    for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
37        if (!formats[i].isValid() || formats[i].backend() != formats[0].backend()) {
38            *this = {};
39            SkASSERT(!this->isValid());
40            return;
41        }
42        int numRequiredChannels = yuvaInfo.numChannelsInPlane(i);
43        SkASSERT(numRequiredChannels > 0);
44        int numActualChannels = num_channels(formats[i]);
45        if (numActualChannels < numRequiredChannels) {
46            *this = {};
47            SkASSERT(!this->isValid());
48        }
49        fPlaneFormats[i] = formats[i];
50    }
51    SkASSERT(this->isValid());
52}
53
54bool GrYUVABackendTextureInfo::operator==(const GrYUVABackendTextureInfo& that) const {
55    if (fYUVAInfo != that.fYUVAInfo ||
56        fMipmapped != that.fMipmapped ||
57        fTextureOrigin != that.fTextureOrigin) {
58        return false;
59    }
60    int n = fYUVAInfo.numPlanes();
61    return std::equal(fPlaneFormats, fPlaneFormats + n, that.fPlaneFormats);
62}
63
64SkYUVAInfo::YUVALocations GrYUVABackendTextureInfo::toYUVALocations() const {
65    uint32_t channelFlags[] = {fPlaneFormats[0].channelMask(),
66                               fPlaneFormats[1].channelMask(),
67                               fPlaneFormats[2].channelMask(),
68                               fPlaneFormats[3].channelMask()};
69    auto result = fYUVAInfo.toYUVALocations(channelFlags);
70    SkDEBUGCODE(int numPlanes;)
71    SkASSERT(SkYUVAInfo::YUVALocation::AreValidLocations(result, &numPlanes));
72    SkASSERT(numPlanes == this->numPlanes());
73    return result;
74}
75
76//////////////////////////////////////////////////////////////////////////////
77
78GrYUVABackendTextures::GrYUVABackendTextures(
79        const SkYUVAInfo& yuvaInfo,
80        const GrBackendTexture textures[SkYUVAInfo::kMaxPlanes],
81        GrSurfaceOrigin textureOrigin)
82        : fYUVAInfo(yuvaInfo), fTextureOrigin(textureOrigin) {
83    if (!fYUVAInfo.isValid()) {
84        return;
85    }
86    SkISize planeDimensions[SkYUVAInfo::kMaxPlanes];
87    int numPlanes = yuvaInfo.planeDimensions(planeDimensions);
88    for (int i = 0; i < numPlanes; ++i) {
89        int numRequiredChannels = fYUVAInfo.numChannelsInPlane(i);
90        if (!textures[i].isValid() ||
91            textures[i].dimensions() != planeDimensions[i] ||
92            textures[i].backend() != textures[0].backend() ||
93            num_channels(textures[i].getBackendFormat()) < numRequiredChannels) {
94            *this = {};
95            return;
96        }
97        fTextures[i] = textures[i];
98    }
99}
100
101SkYUVAInfo::YUVALocations GrYUVABackendTextures::toYUVALocations() const {
102    uint32_t channelFlags[] = {fTextures[0].getBackendFormat().channelMask(),
103                               fTextures[1].getBackendFormat().channelMask(),
104                               fTextures[2].getBackendFormat().channelMask(),
105                               fTextures[3].getBackendFormat().channelMask()};
106    auto result = fYUVAInfo.toYUVALocations(channelFlags);
107    SkDEBUGCODE(int numPlanes;)
108    SkASSERT(SkYUVAInfo::YUVALocation::AreValidLocations(result, &numPlanes));
109    SkASSERT(numPlanes == this->numPlanes());
110    return result;
111}
112