blob: afafe08279c19f06a28bee7e797c78138ad6fae3 [file] [log] [blame]
robertphillipsf7142e72016-04-18 07:20:05 -07001/*
2 * Copyright 2016 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 "GrAlphaThresholdFragmentProcessor.h"
9
10#if SK_SUPPORT_GPU
11
12#include "GrInvariantOutput.h"
bungeman06ca8ec2016-06-09 08:01:03 -070013#include "SkRefCnt.h"
robertphillipsf7142e72016-04-18 07:20:05 -070014
Brian Osman6fb592e2016-10-03 13:15:12 -040015#include "glsl/GrGLSLColorSpaceXformHelper.h"
robertphillipsf7142e72016-04-18 07:20:05 -070016#include "glsl/GrGLSLFragmentProcessor.h"
17#include "glsl/GrGLSLFragmentShaderBuilder.h"
18#include "glsl/GrGLSLUniformHandler.h"
Brian Salomon94efbf52016-11-29 13:43:05 -050019#include "../private/GrGLSL.h"
robertphillipsf7142e72016-04-18 07:20:05 -070020
Brian Osman6fb592e2016-10-03 13:15:12 -040021sk_sp<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::Make(
22 GrTexture* texture,
23 sk_sp<GrColorSpaceXform> colorSpaceXform,
24 GrTexture* maskTexture,
25 float innerThreshold,
26 float outerThreshold,
27 const SkIRect& bounds) {
robertphillipsf7142e72016-04-18 07:20:05 -070028 return sk_sp<GrFragmentProcessor>(new GrAlphaThresholdFragmentProcessor(
Brian Osman6fb592e2016-10-03 13:15:12 -040029 texture, std::move(colorSpaceXform),
30 maskTexture,
31 innerThreshold, outerThreshold,
32 bounds));
robertphillipsf7142e72016-04-18 07:20:05 -070033}
34
35static SkMatrix make_div_and_translate_matrix(GrTexture* texture, int x, int y) {
36 SkMatrix matrix = GrCoordTransform::MakeDivByTextureWHMatrix(texture);
37 matrix.preTranslate(SkIntToScalar(x), SkIntToScalar(y));
38 return matrix;
39}
40
Brian Osman6fb592e2016-10-03 13:15:12 -040041GrAlphaThresholdFragmentProcessor::GrAlphaThresholdFragmentProcessor(
42 GrTexture* texture,
43 sk_sp<GrColorSpaceXform> colorSpaceXform,
44 GrTexture* maskTexture,
45 float innerThreshold,
46 float outerThreshold,
47 const SkIRect& bounds)
robertphillipsf7142e72016-04-18 07:20:05 -070048 : fInnerThreshold(innerThreshold)
49 , fOuterThreshold(outerThreshold)
Brian Salomon2ebd0c82016-10-03 17:15:28 -040050 , fImageCoordTransform(GrCoordTransform::MakeDivByTextureWHMatrix(texture), texture,
Brian Salomon514baff2016-11-17 15:17:07 -050051 GrSamplerParams::kNone_FilterMode)
Brian Salomon0bbecb22016-11-17 11:38:22 -050052 , fImageTextureSampler(texture)
Brian Osman6fb592e2016-10-03 13:15:12 -040053 , fColorSpaceXform(std::move(colorSpaceXform))
Brian Salomon2ebd0c82016-10-03 17:15:28 -040054 , fMaskCoordTransform(make_div_and_translate_matrix(maskTexture, -bounds.x(), -bounds.y()),
robertphillipsf7142e72016-04-18 07:20:05 -070055 maskTexture,
Brian Salomon514baff2016-11-17 15:17:07 -050056 GrSamplerParams::kNone_FilterMode)
Brian Salomon0bbecb22016-11-17 11:38:22 -050057 , fMaskTextureSampler(maskTexture) {
robertphillipsf7142e72016-04-18 07:20:05 -070058 this->initClassID<GrAlphaThresholdFragmentProcessor>();
59 this->addCoordTransform(&fImageCoordTransform);
Brian Salomon0bbecb22016-11-17 11:38:22 -050060 this->addTextureSampler(&fImageTextureSampler);
robertphillipsf7142e72016-04-18 07:20:05 -070061 this->addCoordTransform(&fMaskCoordTransform);
Brian Salomon0bbecb22016-11-17 11:38:22 -050062 this->addTextureSampler(&fMaskTextureSampler);
robertphillipsf7142e72016-04-18 07:20:05 -070063}
64
65bool GrAlphaThresholdFragmentProcessor::onIsEqual(const GrFragmentProcessor& sBase) const {
66 const GrAlphaThresholdFragmentProcessor& s = sBase.cast<GrAlphaThresholdFragmentProcessor>();
67 return (this->fInnerThreshold == s.fInnerThreshold &&
68 this->fOuterThreshold == s.fOuterThreshold);
69}
70
71void GrAlphaThresholdFragmentProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const {
Brian Salomondb4183d2016-11-17 12:48:40 -050072 GrPixelConfig config = this->textureSampler(0).texture()->config();
Brian Salomon0bbecb22016-11-17 11:38:22 -050073 if (GrPixelConfigIsAlphaOnly(config)) {
robertphillipsf7142e72016-04-18 07:20:05 -070074 inout->mulByUnknownSingleComponent();
Brian Salomon0bbecb22016-11-17 11:38:22 -050075 } else if (GrPixelConfigIsOpaque(config) && fOuterThreshold >= 1.f) {
robertphillipsf7142e72016-04-18 07:20:05 -070076 inout->mulByUnknownOpaqueFourComponents();
77 } else {
78 inout->mulByUnknownFourComponents();
79 }
80}
81
82///////////////////////////////////////////////////////////////////////////////
83
84class GrGLAlphaThresholdFragmentProcessor : public GrGLSLFragmentProcessor {
85public:
86 void emitCode(EmitArgs&) override;
87
Brian Salomon94efbf52016-11-29 13:43:05 -050088 static inline void GenKey(const GrProcessor& effect, const GrShaderCaps&,
Brian Osman6fb592e2016-10-03 13:15:12 -040089 GrProcessorKeyBuilder* b) {
90 const GrAlphaThresholdFragmentProcessor& atfp =
91 effect.cast<GrAlphaThresholdFragmentProcessor>();
92 b->add32(GrColorSpaceXform::XformKey(atfp.colorSpaceXform()));
93 }
94
robertphillipsf7142e72016-04-18 07:20:05 -070095protected:
96 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
97
98private:
99 GrGLSLProgramDataManager::UniformHandle fInnerThresholdVar;
100 GrGLSLProgramDataManager::UniformHandle fOuterThresholdVar;
Brian Osman6fb592e2016-10-03 13:15:12 -0400101 GrGLSLProgramDataManager::UniformHandle fColorSpaceXformVar;
robertphillipsf7142e72016-04-18 07:20:05 -0700102 typedef GrGLSLFragmentProcessor INHERITED;
103};
104
105void GrGLAlphaThresholdFragmentProcessor::emitCode(EmitArgs& args) {
106 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
107 fInnerThresholdVar = uniformHandler->addUniform(kFragment_GrShaderFlag,
108 kFloat_GrSLType, kDefault_GrSLPrecision,
109 "inner_threshold");
110 fOuterThresholdVar = uniformHandler->addUniform(kFragment_GrShaderFlag,
111 kFloat_GrSLType, kDefault_GrSLPrecision,
112 "outer_threshold");
113
Brian Osman6fb592e2016-10-03 13:15:12 -0400114 const GrAlphaThresholdFragmentProcessor& atfp =
115 args.fFp.cast<GrAlphaThresholdFragmentProcessor>();
116 GrGLSLColorSpaceXformHelper colorSpaceHelper(uniformHandler, atfp.colorSpaceXform(),
117 &fColorSpaceXformVar);
118
robertphillipsf7142e72016-04-18 07:20:05 -0700119 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700120 SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
121 SkString maskCoords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[1]);
robertphillipsf7142e72016-04-18 07:20:05 -0700122
123 fragBuilder->codeAppendf("vec2 coord = %s;", coords2D.c_str());
124 fragBuilder->codeAppendf("vec2 mask_coord = %s;", maskCoords2D.c_str());
125 fragBuilder->codeAppend("vec4 input_color = ");
Brian Osman6fb592e2016-10-03 13:15:12 -0400126 fragBuilder->appendTextureLookup(args.fTexSamplers[0], "coord", kVec2f_GrSLType,
127 &colorSpaceHelper);
robertphillipsf7142e72016-04-18 07:20:05 -0700128 fragBuilder->codeAppend(";");
129 fragBuilder->codeAppend("vec4 mask_color = ");
130 fragBuilder->appendTextureLookup(args.fTexSamplers[1], "mask_coord");
131 fragBuilder->codeAppend(";");
132
133 fragBuilder->codeAppendf("float inner_thresh = %s;",
134 uniformHandler->getUniformCStr(fInnerThresholdVar));
135 fragBuilder->codeAppendf("float outer_thresh = %s;",
136 uniformHandler->getUniformCStr(fOuterThresholdVar));
137 fragBuilder->codeAppend("float mask = mask_color.a;");
138
139 fragBuilder->codeAppend("vec4 color = input_color;");
140 fragBuilder->codeAppend("if (mask < 0.5) {"
141 "if (color.a > outer_thresh) {"
142 "float scale = outer_thresh / color.a;"
143 "color.rgb *= scale;"
144 "color.a = outer_thresh;"
145 "}"
146 "} else if (color.a < inner_thresh) {"
147 "float scale = inner_thresh / max(0.001, color.a);"
148 "color.rgb *= scale;"
149 "color.a = inner_thresh;"
150 "}");
151
152 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor,
153 (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr4("color")).c_str());
154}
155
156void GrGLAlphaThresholdFragmentProcessor::onSetData(const GrGLSLProgramDataManager& pdman,
157 const GrProcessor& proc) {
158 const GrAlphaThresholdFragmentProcessor& atfp = proc.cast<GrAlphaThresholdFragmentProcessor>();
159 pdman.set1f(fInnerThresholdVar, atfp.innerThreshold());
160 pdman.set1f(fOuterThresholdVar, atfp.outerThreshold());
Brian Osman6fb592e2016-10-03 13:15:12 -0400161 if (SkToBool(atfp.colorSpaceXform())) {
162 pdman.setSkMatrix44(fColorSpaceXformVar, atfp.colorSpaceXform()->srcToDst());
163 }
robertphillipsf7142e72016-04-18 07:20:05 -0700164}
165
166/////////////////////////////////////////////////////////////////////
167
168GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrAlphaThresholdFragmentProcessor);
169
bungeman06ca8ec2016-06-09 08:01:03 -0700170sk_sp<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::TestCreate(GrProcessorTestData* d) {
robertphillipsf7142e72016-04-18 07:20:05 -0700171 GrTexture* bmpTex = d->fTextures[GrProcessorUnitTest::kSkiaPMTextureIdx];
172 GrTexture* maskTex = d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx];
173 float innerThresh = d->fRandom->nextUScalar1();
174 float outerThresh = d->fRandom->nextUScalar1();
175 const int kMaxWidth = 1000;
176 const int kMaxHeight = 1000;
177 uint32_t width = d->fRandom->nextULessThan(kMaxWidth);
178 uint32_t height = d->fRandom->nextULessThan(kMaxHeight);
179 uint32_t x = d->fRandom->nextULessThan(kMaxWidth - width);
180 uint32_t y = d->fRandom->nextULessThan(kMaxHeight - height);
181 SkIRect bounds = SkIRect::MakeXYWH(x, y, width, height);
Brian Osmane2f732f2016-10-03 14:23:50 -0400182 auto colorSpaceXform = GrTest::TestColorXform(d->fRandom);
183 return GrAlphaThresholdFragmentProcessor::Make(bmpTex, colorSpaceXform, maskTex,
robertphillipsf7142e72016-04-18 07:20:05 -0700184 innerThresh, outerThresh,
bungeman06ca8ec2016-06-09 08:01:03 -0700185 bounds);
robertphillipsf7142e72016-04-18 07:20:05 -0700186}
187
188///////////////////////////////////////////////////////////////////////////////
189
Brian Salomon94efbf52016-11-29 13:43:05 -0500190void GrAlphaThresholdFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
robertphillipsf7142e72016-04-18 07:20:05 -0700191 GrProcessorKeyBuilder* b) const {
192 GrGLAlphaThresholdFragmentProcessor::GenKey(*this, caps, b);
193}
194
195GrGLSLFragmentProcessor* GrAlphaThresholdFragmentProcessor::onCreateGLSLInstance() const {
196 return new GrGLAlphaThresholdFragmentProcessor;
197}
198
199#endif