Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2018 Google Inc.
      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 "GrYUVtoRGBEffect.h"
      9 
     10 static const float kJPEGConversionMatrix[16] = {
     11     1.0f,  0.0f,       1.402f,    -0.703749f,
     12     1.0f, -0.344136f, -0.714136f,  0.531211f,
     13     1.0f,  1.772f,     0.0f,      -0.889475f,
     14     0.0f,  0.0f,       0.0f,       1.0
     15 };
     16 
     17 static const float kRec601ConversionMatrix[16] = {
     18     1.164f,  0.0f,    1.596f, -0.87075f,
     19     1.164f, -0.391f, -0.813f,  0.52925f,
     20     1.164f,  2.018f,  0.0f,   -1.08175f,
     21     0.0f,    0.0f,    0.0f,    1.0
     22 };
     23 
     24 static const float kRec709ConversionMatrix[16] = {
     25     1.164f,  0.0f,    1.793f, -0.96925f,
     26     1.164f, -0.213f, -0.533f,  0.30025f,
     27     1.164f,  2.112f,  0.0f,   -1.12875f,
     28     0.0f,    0.0f,    0.0f,    1.0f
     29 };
     30 
     31 std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(const sk_sp<GrTextureProxy> proxies[],
     32                                                             const SkYUVAIndex yuvaIndices[4],
     33                                                             SkYUVColorSpace yuvColorSpace,
     34                                                             GrSamplerState::Filter filterMode) {
     35     int numPlanes;
     36     SkAssertResult(SkYUVAIndex::AreValidIndices(yuvaIndices, &numPlanes));
     37 
     38     const SkISize YSize = proxies[yuvaIndices[SkYUVAIndex::kY_Index].fIndex]->isize();
     39 
     40     GrSamplerState::Filter minimizeFilterMode = GrSamplerState::Filter::kMipMap == filterMode ?
     41                                                 GrSamplerState::Filter::kMipMap :
     42                                                 GrSamplerState::Filter::kBilerp;
     43 
     44     GrSamplerState::Filter filterModes[4];
     45     SkSize scales[4];
     46     for (int i = 0; i < numPlanes; ++i) {
     47         SkISize size = proxies[i]->isize();
     48         scales[i] = SkSize::Make(SkIntToScalar(size.width()) / SkIntToScalar(YSize.width()),
     49                                  SkIntToScalar(size.height()) / SkIntToScalar(YSize.height()));
     50         filterModes[i] = (size == YSize) ? filterMode : minimizeFilterMode;
     51     }
     52 
     53     SkMatrix44 mat;
     54     switch (yuvColorSpace) {
     55         case kJPEG_SkYUVColorSpace:
     56             mat.setColMajorf(kJPEGConversionMatrix);
     57             break;
     58         case kRec601_SkYUVColorSpace:
     59             mat.setColMajorf(kRec601ConversionMatrix);
     60             break;
     61         case kRec709_SkYUVColorSpace:
     62             mat.setColMajorf(kRec709ConversionMatrix);
     63             break;
     64     }
     65     return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect(
     66             proxies, scales, filterModes, numPlanes, yuvaIndices, mat));
     67 }
     68 
     69 #ifdef SK_DEBUG
     70 SkString GrYUVtoRGBEffect::dumpInfo() const {
     71     SkString str;
     72     for (int i = 0; i < this->numTextureSamplers(); ++i) {
     73         str.appendf("%d: %d %d ", i,
     74                     this->textureSampler(i).proxy()->uniqueID().asUInt(),
     75                     this->textureSampler(i).proxy()->underlyingUniqueID().asUInt());
     76     }
     77     str.appendf("\n");
     78 
     79     return str;
     80 }
     81 #endif
     82 
     83 #include "glsl/GrGLSLFragmentProcessor.h"
     84 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     85 #include "glsl/GrGLSLProgramBuilder.h"
     86 #include "GrTexture.h"
     87 #include "SkSLCPP.h"
     88 #include "SkSLUtil.h"
     89 class GrGLSLYUVtoRGBEffect : public GrGLSLFragmentProcessor {
     90 public:
     91     GrGLSLYUVtoRGBEffect() {}
     92     void emitCode(EmitArgs& args) override {
     93         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
     94         const GrYUVtoRGBEffect& _outer = args.fFp.cast<GrYUVtoRGBEffect>();
     95         (void)_outer;
     96 
     97         auto colorSpaceMatrix = _outer.colorSpaceMatrix();
     98         (void)colorSpaceMatrix;
     99         fColorSpaceMatrixVar =
    100                 args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4x4_GrSLType,
    101                                                  kDefault_GrSLPrecision, "colorSpaceMatrix");
    102 
    103         int numSamplers = args.fTexSamplers.count();
    104 
    105         SkString coords[4];
    106         for (int i = 0; i < numSamplers; ++i) {
    107             coords[i] = fragBuilder->ensureCoords2D(args.fTransformedCoords[i]);
    108         }
    109 
    110         for (int i = 0; i < numSamplers; ++i) {
    111             fragBuilder->codeAppendf(
    112                 "half4 tmp%d = texture(%s, %s).%s;",
    113                     i,
    114                     fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[i]).c_str(),
    115                     coords[i].c_str(),
    116                     fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[i]).c_str());
    117         }
    118 
    119         static const char kChannelToChar[4] = { 'x', 'y', 'z', 'w' };
    120 
    121         fragBuilder->codeAppendf(
    122             "half4 yuvOne = half4(tmp%d.%c, tmp%d.%c, tmp%d.%c, 1.0) * %s;",
    123                 _outer.yuvaIndex(0).fIndex, kChannelToChar[(int)_outer.yuvaIndex(0).fChannel],
    124                 _outer.yuvaIndex(1).fIndex, kChannelToChar[(int)_outer.yuvaIndex(1).fChannel],
    125                 _outer.yuvaIndex(2).fIndex, kChannelToChar[(int)_outer.yuvaIndex(2).fChannel],
    126                 args.fUniformHandler->getUniformCStr(fColorSpaceMatrixVar));
    127 
    128 
    129         if (_outer.yuvaIndex(3).fIndex >= 0) {
    130             fragBuilder->codeAppendf(
    131                 "float a = tmp%d.%c;", _outer.yuvaIndex(3).fIndex,
    132                                        kChannelToChar[(int)_outer.yuvaIndex(3).fChannel]);
    133             // premultiply alpha
    134             fragBuilder->codeAppend("yuvOne *= a;");
    135         } else {
    136             fragBuilder->codeAppendf("float a = 1.0;");
    137         }
    138 
    139         fragBuilder->codeAppendf("%s = half4(yuvOne.xyz, a);", args.fOutputColor);
    140     }
    141 
    142 private:
    143     void onSetData(const GrGLSLProgramDataManager& pdman,
    144                    const GrFragmentProcessor& _proc) override {
    145         const GrYUVtoRGBEffect& _outer = _proc.cast<GrYUVtoRGBEffect>();
    146         { pdman.setSkMatrix44(fColorSpaceMatrixVar, (_outer.colorSpaceMatrix())); }
    147     }
    148     UniformHandle fColorSpaceMatrixVar;
    149 };
    150 GrGLSLFragmentProcessor* GrYUVtoRGBEffect::onCreateGLSLInstance() const {
    151     return new GrGLSLYUVtoRGBEffect();
    152 }
    153 void GrYUVtoRGBEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
    154                                              GrProcessorKeyBuilder* b) const {
    155     b->add32(this->numTextureSamplers());
    156 
    157     uint32_t packed = 0;
    158     for (int i = 0; i < 4; ++i) {
    159         if (this->yuvaIndex(i).fIndex < 0) {
    160             continue;
    161         }
    162 
    163         uint8_t index = this->yuvaIndex(i).fIndex;
    164         uint8_t chann = (uint8_t) this->yuvaIndex(i).fChannel;
    165 
    166         SkASSERT(index < 4 && chann < 4);
    167 
    168         packed |= (index | (chann << 2)) << (i * 4);
    169     }
    170     b->add32(packed);
    171 }
    172 bool GrYUVtoRGBEffect::onIsEqual(const GrFragmentProcessor& other) const {
    173     const GrYUVtoRGBEffect& that = other.cast<GrYUVtoRGBEffect>();
    174 
    175     for (int i = 0; i < 4; ++i) {
    176         if (fYUVAIndices[i] != that.fYUVAIndices[i]) {
    177             return false;
    178         }
    179     }
    180 
    181     for (int i = 0; i < this->numTextureSamplers(); ++i) {
    182         // 'fSamplers' is checked by the base class
    183         if (fSamplerTransforms[i] != that.fSamplerTransforms[i]) {
    184             return false;
    185         }
    186     }
    187 
    188     if (fColorSpaceMatrix != that.fColorSpaceMatrix) {
    189         return false;
    190     }
    191 
    192     return true;
    193 }
    194 GrYUVtoRGBEffect::GrYUVtoRGBEffect(const GrYUVtoRGBEffect& src)
    195         : INHERITED(kGrYUVtoRGBEffect_ClassID, src.optimizationFlags())
    196         , fColorSpaceMatrix(src.fColorSpaceMatrix) {
    197     int numPlanes = src.numTextureSamplers();
    198     for (int i = 0; i < numPlanes; ++i) {
    199         fSamplers[i].reset(sk_ref_sp(src.fSamplers[i].proxy()), src.fSamplers[i].samplerState());
    200         fSamplerTransforms[i] = src.fSamplerTransforms[i];
    201         fSamplerCoordTransforms[i] = src.fSamplerCoordTransforms[i];
    202     }
    203 
    204     this->setTextureSamplerCnt(numPlanes);
    205     for (int i = 0; i < numPlanes; ++i) {
    206         this->addCoordTransform(&fSamplerCoordTransforms[i]);
    207     }
    208 
    209     memcpy(fYUVAIndices, src.fYUVAIndices, sizeof(fYUVAIndices));
    210 }
    211 std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::clone() const {
    212     return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect(*this));
    213 }
    214 const GrFragmentProcessor::TextureSampler& GrYUVtoRGBEffect::onTextureSampler(int index) const {
    215     SkASSERT(index < this->numTextureSamplers());
    216     return fSamplers[index];
    217 }
    218