blob: 61d24566c64838026d41d87c4063ba67f49f2f77 [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
Ethan Nicholas7461a4a2017-12-21 14:18:01 -05008#include "GrYUVtoRGBEffect.h"
Ethan Nicholas7461a4a2017-12-21 14:18:01 -05009
10static const float kJPEGConversionMatrix[16] = {
Robert Phillips94ade752018-10-09 12:32:31 -040011 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};
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050016
17static const float kRec601ConversionMatrix[16] = {
Robert Phillips94ade752018-10-09 12:32:31 -040018 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};
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050023
24static const float kRec709ConversionMatrix[16] = {
Robert Phillips94ade752018-10-09 12:32:31 -040025 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};
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050030
Robert Phillips94ade752018-10-09 12:32:31 -040031std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(const sk_sp<GrTextureProxy> proxies[],
32 const SkYUVAIndex yuvaIndices[4],
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040033 SkYUVColorSpace yuvColorSpace,
34 GrSamplerState::Filter filterMode) {
Robert Phillips94ade752018-10-09 12:32:31 -040035 int numPlanes;
Jim Van Verthf00b1622018-10-10 13:03:23 -040036 SkAssertResult(SkYUVAIndex::AreValidIndices(yuvaIndices, &numPlanes));
Robert Phillips94ade752018-10-09 12:32:31 -040037
38 const SkISize YSize = proxies[yuvaIndices[SkYUVAIndex::kY_Index].fIndex]->isize();
39
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040040 GrSamplerState::Filter minimizeFilterMode = GrSamplerState::Filter::kMipMap == filterMode ?
41 GrSamplerState::Filter::kMipMap :
42 GrSamplerState::Filter::kBilerp;
43
Robert Phillips94ade752018-10-09 12:32:31 -040044 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()));
Jim Van Verth30e0d7f2018-11-02 13:36:42 -040050 filterModes[i] = (size == YSize) ? filterMode : minimizeFilterMode;
Robert Phillips94ade752018-10-09 12:32:31 -040051 }
52
Mike Klein4429a4f2018-10-04 09:06:00 -040053 SkMatrix44 mat;
Robert Phillips94ade752018-10-09 12:32:31 -040054 switch (yuvColorSpace) {
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050055 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(
Robert Phillips94ade752018-10-09 12:32:31 -040066 proxies, scales, filterModes, numPlanes, yuvaIndices, mat));
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050067}
Robert Phillipsba5c4392018-07-25 12:37:14 -040068
69SkString GrYUVtoRGBEffect::dumpInfo() const {
70 SkString str;
Robert Phillips94ade752018-10-09 12:32:31 -040071 for (int i = 0; i < this->numTextureSamplers(); ++i) {
72 str.appendf("%d: %d %d ", i,
73 this->textureSampler(i).proxy()->uniqueID().asUInt(),
74 this->textureSampler(i).proxy()->underlyingUniqueID().asUInt());
75 }
76 str.appendf("\n");
Robert Phillipsba5c4392018-07-25 12:37:14 -040077
78 return str;
79}
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050080#include "glsl/GrGLSLFragmentProcessor.h"
81#include "glsl/GrGLSLFragmentShaderBuilder.h"
82#include "glsl/GrGLSLProgramBuilder.h"
83#include "GrTexture.h"
84#include "SkSLCPP.h"
85#include "SkSLUtil.h"
86class GrGLSLYUVtoRGBEffect : public GrGLSLFragmentProcessor {
87public:
88 GrGLSLYUVtoRGBEffect() {}
89 void emitCode(EmitArgs& args) override {
90 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
91 const GrYUVtoRGBEffect& _outer = args.fFp.cast<GrYUVtoRGBEffect>();
92 (void)_outer;
Robert Phillips94ade752018-10-09 12:32:31 -040093
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050094 auto colorSpaceMatrix = _outer.colorSpaceMatrix();
95 (void)colorSpaceMatrix;
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050096 fColorSpaceMatrixVar =
97 args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4x4_GrSLType,
98 kDefault_GrSLPrecision, "colorSpaceMatrix");
Robert Phillips94ade752018-10-09 12:32:31 -040099
100 int numSamplers = args.fTexSamplers.count();
101
102 SkString coords[4];
103 for (int i = 0; i < numSamplers; ++i) {
104 coords[i] = fragBuilder->ensureCoords2D(args.fTransformedCoords[i]);
105 }
106
107 for (int i = 0; i < numSamplers; ++i) {
108 fragBuilder->codeAppendf(
109 "half4 tmp%d = texture(%s, %s).%s;",
110 i,
111 fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[i]).c_str(),
112 coords[i].c_str(),
113 fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[i]).c_str());
114 }
115
116 static const char kChannelToChar[4] = { 'x', 'y', 'z', 'w' };
117
Ethan Nicholas7461a4a2017-12-21 14:18:01 -0500118 fragBuilder->codeAppendf(
Robert Phillips94ade752018-10-09 12:32:31 -0400119 "half4 yuvOne = half4(tmp%d.%c, tmp%d.%c, tmp%d.%c, 1.0) * %s;",
120 _outer.yuvaIndex(0).fIndex, kChannelToChar[(int)_outer.yuvaIndex(0).fChannel],
121 _outer.yuvaIndex(1).fIndex, kChannelToChar[(int)_outer.yuvaIndex(1).fChannel],
122 _outer.yuvaIndex(2).fIndex, kChannelToChar[(int)_outer.yuvaIndex(2).fChannel],
Ethan Nicholas7461a4a2017-12-21 14:18:01 -0500123 args.fUniformHandler->getUniformCStr(fColorSpaceMatrixVar));
Robert Phillips94ade752018-10-09 12:32:31 -0400124
125
126 if (_outer.yuvaIndex(3).fIndex >= 0) {
127 fragBuilder->codeAppendf(
128 "float a = tmp%d.%c;", _outer.yuvaIndex(3).fIndex,
129 kChannelToChar[(int)_outer.yuvaIndex(3).fChannel]);
Jim Van Verth53275362018-11-09 15:42:35 -0500130 // premultiply alpha
131 fragBuilder->codeAppend("yuvOne *= a;");
Robert Phillips94ade752018-10-09 12:32:31 -0400132 } else {
133 fragBuilder->codeAppendf("float a = 1.0;");
134 }
135
136 fragBuilder->codeAppendf("%s = half4(yuvOne.xyz, a);", args.fOutputColor);
Ethan Nicholas7461a4a2017-12-21 14:18:01 -0500137 }
138
139private:
140 void onSetData(const GrGLSLProgramDataManager& pdman,
141 const GrFragmentProcessor& _proc) override {
142 const GrYUVtoRGBEffect& _outer = _proc.cast<GrYUVtoRGBEffect>();
Michael Ludwiga4275592018-08-31 10:52:47 -0400143 { pdman.setSkMatrix44(fColorSpaceMatrixVar, (_outer.colorSpaceMatrix())); }
Ethan Nicholas7461a4a2017-12-21 14:18:01 -0500144 }
145 UniformHandle fColorSpaceMatrixVar;
146};
147GrGLSLFragmentProcessor* GrYUVtoRGBEffect::onCreateGLSLInstance() const {
148 return new GrGLSLYUVtoRGBEffect();
149}
150void GrYUVtoRGBEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
151 GrProcessorKeyBuilder* b) const {
Robert Phillips94ade752018-10-09 12:32:31 -0400152 b->add32(this->numTextureSamplers());
153
154 uint32_t packed = 0;
155 for (int i = 0; i < 4; ++i) {
156 if (this->yuvaIndex(i).fIndex < 0) {
157 continue;
158 }
159
160 uint8_t index = this->yuvaIndex(i).fIndex;
161 uint8_t chann = (uint8_t) this->yuvaIndex(i).fChannel;
Robert Phillips6ba8c832018-10-10 11:43:01 -0400162
Robert Phillips94ade752018-10-09 12:32:31 -0400163 SkASSERT(index < 4 && chann < 4);
164
165 packed |= (index | (chann << 2)) << (i * 4);
166 }
167 b->add32(packed);
Ethan Nicholas7461a4a2017-12-21 14:18:01 -0500168}
169bool GrYUVtoRGBEffect::onIsEqual(const GrFragmentProcessor& other) const {
170 const GrYUVtoRGBEffect& that = other.cast<GrYUVtoRGBEffect>();
Robert Phillips6ba8c832018-10-10 11:43:01 -0400171
172 for (int i = 0; i < 4; ++i) {
173 if (fYUVAIndices[i] != that.fYUVAIndices[i]) {
174 return false;
175 }
176 }
Robert Phillips94ade752018-10-09 12:32:31 -0400177
178 for (int i = 0; i < this->numTextureSamplers(); ++i) {
179 // 'fSamplers' is checked by the base class
180 if (fSamplerTransforms[i] != that.fSamplerTransforms[i]) {
181 return false;
182 }
183 }
184
185 if (fColorSpaceMatrix != that.fColorSpaceMatrix) {
186 return false;
187 }
188
Ethan Nicholas7461a4a2017-12-21 14:18:01 -0500189 return true;
190}
191GrYUVtoRGBEffect::GrYUVtoRGBEffect(const GrYUVtoRGBEffect& src)
192 : INHERITED(kGrYUVtoRGBEffect_ClassID, src.optimizationFlags())
Robert Phillips94ade752018-10-09 12:32:31 -0400193 , fColorSpaceMatrix(src.fColorSpaceMatrix) {
194 int numPlanes = src.numTextureSamplers();
195 for (int i = 0; i < numPlanes; ++i) {
196 fSamplers[i].reset(sk_ref_sp(src.fSamplers[i].proxy()), src.fSamplers[i].samplerState());
197 fSamplerTransforms[i] = src.fSamplerTransforms[i];
198 fSamplerCoordTransforms[i] = src.fSamplerCoordTransforms[i];
199 }
200
201 this->setTextureSamplerCnt(numPlanes);
202 for (int i = 0; i < numPlanes; ++i) {
203 this->addCoordTransform(&fSamplerCoordTransforms[i]);
204 }
205
206 memcpy(fYUVAIndices, src.fYUVAIndices, sizeof(fYUVAIndices));
Ethan Nicholas7461a4a2017-12-21 14:18:01 -0500207}
208std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::clone() const {
209 return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect(*this));
210}
Brian Salomonf7dcd762018-07-30 14:48:15 -0400211const GrFragmentProcessor::TextureSampler& GrYUVtoRGBEffect::onTextureSampler(int index) const {
Robert Phillips94ade752018-10-09 12:32:31 -0400212 SkASSERT(index < this->numTextureSamplers());
213 return fSamplers[index];
Brian Salomonf7dcd762018-07-30 14:48:15 -0400214}