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
Make(const sk_sp<GrTextureProxy> proxies[],const SkYUVAIndex yuvaIndices[4],SkYUVColorSpace yuvColorSpace,GrSamplerState::Filter filterMode)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
dumpInfo() const70 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:
GrGLSLYUVtoRGBEffect()91 GrGLSLYUVtoRGBEffect() {}
emitCode(EmitArgs & args)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:
onSetData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & _proc)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 };
onCreateGLSLInstance() const150 GrGLSLFragmentProcessor* GrYUVtoRGBEffect::onCreateGLSLInstance() const {
151 return new GrGLSLYUVtoRGBEffect();
152 }
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const153 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 }
onIsEqual(const GrFragmentProcessor & other) const172 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 }
GrYUVtoRGBEffect(const GrYUVtoRGBEffect & src)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 }
clone() const211 std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::clone() const {
212 return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect(*this));
213 }
onTextureSampler(int index) const214 const GrFragmentProcessor::TextureSampler& GrYUVtoRGBEffect::onTextureSampler(int index) const {
215 SkASSERT(index < this->numTextureSamplers());
216 return fSamplers[index];
217 }
218