blob: a82aec707607f493afad690f32f83f003ca43544 [file] [log] [blame]
Ethan Nicholas7461a4a2017-12-21 14:18:01 -05001/*
Ethan Nicholas130fb3f2018-02-01 12:14:34 -05002 * Copyright 2018 Google Inc.
Ethan Nicholas7461a4a2017-12-21 14:18:01 -05003 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/effects/GrYUVtoRGBEffect.h"
Ethan Nicholas7461a4a2017-12-21 14:18:01 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/gpu/GrTexture.h"
11#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
12#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
13#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
14#include "src/sksl/SkSLCPP.h"
15#include "src/sksl/SkSLUtil.h"
Michael Ludwiga6a84002019-04-12 15:03:02 -040016
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050017static const float kJPEGConversionMatrix[16] = {
Robert Phillips94ade752018-10-09 12:32:31 -040018 1.0f, 0.0f, 1.402f, -0.703749f,
19 1.0f, -0.344136f, -0.714136f, 0.531211f,
20 1.0f, 1.772f, 0.0f, -0.889475f,
21 0.0f, 0.0f, 0.0f, 1.0
22};
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050023
24static const float kRec601ConversionMatrix[16] = {
Robert Phillips94ade752018-10-09 12:32:31 -040025 1.164f, 0.0f, 1.596f, -0.87075f,
26 1.164f, -0.391f, -0.813f, 0.52925f,
27 1.164f, 2.018f, 0.0f, -1.08175f,
28 0.0f, 0.0f, 0.0f, 1.0
29};
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050030
31static const float kRec709ConversionMatrix[16] = {
Robert Phillips94ade752018-10-09 12:32:31 -040032 1.164f, 0.0f, 1.793f, -0.96925f,
33 1.164f, -0.213f, -0.533f, 0.30025f,
34 1.164f, 2.112f, 0.0f, -1.12875f,
35 0.0f, 0.0f, 0.0f, 1.0f
36};
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050037
Robert Phillips94ade752018-10-09 12:32:31 -040038std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(const sk_sp<GrTextureProxy> proxies[],
39 const SkYUVAIndex yuvaIndices[4],
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040040 SkYUVColorSpace yuvColorSpace,
Michael Ludwiga6a84002019-04-12 15:03:02 -040041 GrSamplerState::Filter filterMode,
42 const SkMatrix& localMatrix,
43 const SkRect* domain) {
Robert Phillips94ade752018-10-09 12:32:31 -040044 int numPlanes;
Jim Van Verthf00b1622018-10-10 13:03:23 -040045 SkAssertResult(SkYUVAIndex::AreValidIndices(yuvaIndices, &numPlanes));
Robert Phillips94ade752018-10-09 12:32:31 -040046
47 const SkISize YSize = proxies[yuvaIndices[SkYUVAIndex::kY_Index].fIndex]->isize();
48
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040049 GrSamplerState::Filter minimizeFilterMode = GrSamplerState::Filter::kMipMap == filterMode ?
50 GrSamplerState::Filter::kMipMap :
51 GrSamplerState::Filter::kBilerp;
52
Robert Phillips94ade752018-10-09 12:32:31 -040053 GrSamplerState::Filter filterModes[4];
54 SkSize scales[4];
55 for (int i = 0; i < numPlanes; ++i) {
56 SkISize size = proxies[i]->isize();
57 scales[i] = SkSize::Make(SkIntToScalar(size.width()) / SkIntToScalar(YSize.width()),
58 SkIntToScalar(size.height()) / SkIntToScalar(YSize.height()));
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040059 filterModes[i] = (size == YSize) ? filterMode : minimizeFilterMode;
Robert Phillips94ade752018-10-09 12:32:31 -040060 }
61
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050062 return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect(
Michael Ludwiga6a84002019-04-12 15:03:02 -040063 proxies, scales, filterModes, numPlanes, yuvaIndices, yuvColorSpace, localMatrix,
64 domain));
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050065}
Robert Phillipsba5c4392018-07-25 12:37:14 -040066
Brian Osman9a390ac2018-11-12 09:47:48 -050067#ifdef SK_DEBUG
Robert Phillipsba5c4392018-07-25 12:37:14 -040068SkString GrYUVtoRGBEffect::dumpInfo() const {
69 SkString str;
Robert Phillips94ade752018-10-09 12:32:31 -040070 for (int i = 0; i < this->numTextureSamplers(); ++i) {
71 str.appendf("%d: %d %d ", i,
72 this->textureSampler(i).proxy()->uniqueID().asUInt(),
73 this->textureSampler(i).proxy()->underlyingUniqueID().asUInt());
74 }
75 str.appendf("\n");
Robert Phillipsba5c4392018-07-25 12:37:14 -040076
77 return str;
78}
Brian Osman9a390ac2018-11-12 09:47:48 -050079#endif
80
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050081GrGLSLFragmentProcessor* GrYUVtoRGBEffect::onCreateGLSLInstance() const {
Michael Ludwiga6a84002019-04-12 15:03:02 -040082 class GrGLSLYUVtoRGBEffect : public GrGLSLFragmentProcessor {
83 public:
84 GrGLSLYUVtoRGBEffect() {}
85
86 void emitCode(EmitArgs& args) override {
87 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
88 const GrYUVtoRGBEffect& _outer = args.fFp.cast<GrYUVtoRGBEffect>();
89 (void)_outer;
90
91 if (kIdentity_SkYUVColorSpace != _outer.yuvColorSpace()) {
92 fColorSpaceMatrixVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
93 kHalf4x4_GrSLType,
94 "colorSpaceMatrix");
95 }
96
97 int numSamplers = args.fTexSamplers.count();
98
99 SkString coords[4];
100 for (int i = 0; i < numSamplers; ++i) {
Ethan Nicholasd4efe682019-08-29 16:10:13 -0400101 coords[i] = fragBuilder->ensureCoords2D(args.fTransformedCoords[i].fVaryingPoint);
Michael Ludwiga6a84002019-04-12 15:03:02 -0400102 }
103
104 for (int i = 0; i < numSamplers; ++i) {
105 SkString sampleVar;
106 sampleVar.printf("tmp%d", i);
107 fragBuilder->codeAppendf("half4 %s;", sampleVar.c_str());
108 fGLDomains[i].sampleTexture(fragBuilder, args.fUniformHandler, args.fShaderCaps,
109 _outer.fDomains[i], sampleVar.c_str(), coords[i], args.fTexSamplers[i]);
110 }
111
112 static const char kChannelToChar[4] = { 'x', 'y', 'z', 'w' };
113
114 fragBuilder->codeAppendf(
115 "half4 yuvOne = half4(tmp%d.%c, tmp%d.%c, tmp%d.%c, 1.0);",
116 _outer.yuvaIndex(0).fIndex, kChannelToChar[(int)_outer.yuvaIndex(0).fChannel],
117 _outer.yuvaIndex(1).fIndex, kChannelToChar[(int)_outer.yuvaIndex(1).fChannel],
118 _outer.yuvaIndex(2).fIndex, kChannelToChar[(int)_outer.yuvaIndex(2).fChannel]);
119
120 if (kIdentity_SkYUVColorSpace != _outer.yuvColorSpace()) {
121 SkASSERT(fColorSpaceMatrixVar.isValid());
122 fragBuilder->codeAppendf(
123 "yuvOne *= %s;", args.fUniformHandler->getUniformCStr(fColorSpaceMatrixVar));
124 }
125
126 if (_outer.yuvaIndex(3).fIndex >= 0) {
127 fragBuilder->codeAppendf(
128 "half a = tmp%d.%c;", _outer.yuvaIndex(3).fIndex,
129 kChannelToChar[(int)_outer.yuvaIndex(3).fChannel]);
130 // premultiply alpha
131 fragBuilder->codeAppend("yuvOne *= a;");
132 } else {
133 fragBuilder->codeAppend("half a = 1.0;");
134 }
135
136 fragBuilder->codeAppendf("%s = half4(yuvOne.xyz, a);", args.fOutputColor);
137 }
138
139 private:
140 void onSetData(const GrGLSLProgramDataManager& pdman,
141 const GrFragmentProcessor& _proc) override {
142 const GrYUVtoRGBEffect& _outer = _proc.cast<GrYUVtoRGBEffect>();
143
144 switch (_outer.yuvColorSpace()) {
145 case kJPEG_SkYUVColorSpace:
146 SkASSERT(fColorSpaceMatrixVar.isValid());
147 pdman.setMatrix4f(fColorSpaceMatrixVar, kJPEGConversionMatrix);
148 break;
149 case kRec601_SkYUVColorSpace:
150 SkASSERT(fColorSpaceMatrixVar.isValid());
151 pdman.setMatrix4f(fColorSpaceMatrixVar, kRec601ConversionMatrix);
152 break;
153 case kRec709_SkYUVColorSpace:
154 SkASSERT(fColorSpaceMatrixVar.isValid());
155 pdman.setMatrix4f(fColorSpaceMatrixVar, kRec709ConversionMatrix);
156 break;
157 case kIdentity_SkYUVColorSpace:
158 break;
159 }
160
161 int numSamplers = _outer.numTextureSamplers();
162 for (int i = 0; i < numSamplers; ++i) {
163 fGLDomains[i].setData(pdman, _outer.fDomains[i],
164 _outer.textureSampler(i).proxy(), _outer.textureSampler(i).samplerState());
165 }
166 }
167
168 UniformHandle fColorSpaceMatrixVar;
169 GrTextureDomain::GLDomain fGLDomains[4];
170 };
171
172 return new GrGLSLYUVtoRGBEffect;
Ethan Nicholas7461a4a2017-12-21 14:18:01 -0500173}
174void GrYUVtoRGBEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
175 GrProcessorKeyBuilder* b) const {
Michael Ludwiga6a84002019-04-12 15:03:02 -0400176 using Domain = GrTextureDomain::GLDomain;
177
Robert Phillips94ade752018-10-09 12:32:31 -0400178 b->add32(this->numTextureSamplers());
179
180 uint32_t packed = 0;
Michael Ludwiga6a84002019-04-12 15:03:02 -0400181 uint32_t domain = 0;
Robert Phillips94ade752018-10-09 12:32:31 -0400182 for (int i = 0; i < 4; ++i) {
183 if (this->yuvaIndex(i).fIndex < 0) {
184 continue;
185 }
186
187 uint8_t index = this->yuvaIndex(i).fIndex;
188 uint8_t chann = (uint8_t) this->yuvaIndex(i).fChannel;
Robert Phillips6ba8c832018-10-10 11:43:01 -0400189
Robert Phillips94ade752018-10-09 12:32:31 -0400190 SkASSERT(index < 4 && chann < 4);
191
192 packed |= (index | (chann << 2)) << (i * 4);
Michael Ludwiga6a84002019-04-12 15:03:02 -0400193
194 domain |= Domain::DomainKey(fDomains[i]) << (i * Domain::kDomainKeyBits);
Robert Phillips94ade752018-10-09 12:32:31 -0400195 }
Robert Phillipsb651aac2019-03-15 12:18:49 -0400196 if (kIdentity_SkYUVColorSpace == this->yuvColorSpace()) {
197 packed |= 0x1 << 16;
198 }
199
Robert Phillips94ade752018-10-09 12:32:31 -0400200 b->add32(packed);
Michael Ludwiga6a84002019-04-12 15:03:02 -0400201 b->add32(domain);
Ethan Nicholas7461a4a2017-12-21 14:18:01 -0500202}
203bool GrYUVtoRGBEffect::onIsEqual(const GrFragmentProcessor& other) const {
204 const GrYUVtoRGBEffect& that = other.cast<GrYUVtoRGBEffect>();
Robert Phillips6ba8c832018-10-10 11:43:01 -0400205
206 for (int i = 0; i < 4; ++i) {
207 if (fYUVAIndices[i] != that.fYUVAIndices[i]) {
208 return false;
209 }
210 }
Robert Phillips94ade752018-10-09 12:32:31 -0400211
212 for (int i = 0; i < this->numTextureSamplers(); ++i) {
213 // 'fSamplers' is checked by the base class
214 if (fSamplerTransforms[i] != that.fSamplerTransforms[i]) {
215 return false;
216 }
Michael Ludwiga6a84002019-04-12 15:03:02 -0400217 if (!(fDomains[i] == that.fDomains[i])) {
218 return false;
219 }
Robert Phillips94ade752018-10-09 12:32:31 -0400220 }
221
Robert Phillipsb651aac2019-03-15 12:18:49 -0400222 if (fYUVColorSpace != that.fYUVColorSpace) {
Robert Phillips94ade752018-10-09 12:32:31 -0400223 return false;
224 }
225
Ethan Nicholas7461a4a2017-12-21 14:18:01 -0500226 return true;
227}
228GrYUVtoRGBEffect::GrYUVtoRGBEffect(const GrYUVtoRGBEffect& src)
229 : INHERITED(kGrYUVtoRGBEffect_ClassID, src.optimizationFlags())
Michael Ludwiga6a84002019-04-12 15:03:02 -0400230 , fDomains{src.fDomains[0], src.fDomains[1], src.fDomains[2], src.fDomains[3]}
Robert Phillipsb651aac2019-03-15 12:18:49 -0400231 , fYUVColorSpace(src.fYUVColorSpace) {
Robert Phillips94ade752018-10-09 12:32:31 -0400232 int numPlanes = src.numTextureSamplers();
233 for (int i = 0; i < numPlanes; ++i) {
234 fSamplers[i].reset(sk_ref_sp(src.fSamplers[i].proxy()), src.fSamplers[i].samplerState());
235 fSamplerTransforms[i] = src.fSamplerTransforms[i];
236 fSamplerCoordTransforms[i] = src.fSamplerCoordTransforms[i];
237 }
238
239 this->setTextureSamplerCnt(numPlanes);
240 for (int i = 0; i < numPlanes; ++i) {
241 this->addCoordTransform(&fSamplerCoordTransforms[i]);
242 }
243
244 memcpy(fYUVAIndices, src.fYUVAIndices, sizeof(fYUVAIndices));
Ethan Nicholas7461a4a2017-12-21 14:18:01 -0500245}
246std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::clone() const {
247 return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect(*this));
248}
Brian Salomonf7dcd762018-07-30 14:48:15 -0400249const GrFragmentProcessor::TextureSampler& GrYUVtoRGBEffect::onTextureSampler(int index) const {
Robert Phillips94ade752018-10-09 12:32:31 -0400250 SkASSERT(index < this->numTextureSamplers());
251 return fSamplers[index];
Brian Salomonf7dcd762018-07-30 14:48:15 -0400252}