/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "GrFragmentProcessor.h" #include "GrCoordTransform.h" #include "GrInvariantOutput.h" #include "GrProcOptInfo.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" #include "effects/GrConstColorProcessor.h" #include "effects/GrXfermodeFragmentProcessor.h" GrFragmentProcessor::~GrFragmentProcessor() { // If we got here then our ref count must have reached zero, so we will have converted refs // to pending executions for all children. for (int i = 0; i < fChildProcessors.count(); ++i) { fChildProcessors[i]->completedExecution(); } } bool GrFragmentProcessor::isEqual(const GrFragmentProcessor& that, bool ignoreCoordTransforms) const { if (this->classID() != that.classID() || !this->hasSameSamplers(that)) { return false; } if (ignoreCoordTransforms) { if (this->numTransforms() != that.numTransforms()) { return false; } } else if (!this->hasSameTransforms(that)) { return false; } if (!this->onIsEqual(that)) { return false; } if (this->numChildProcessors() != that.numChildProcessors()) { return false; } for (int i = 0; i < this->numChildProcessors(); ++i) { if (!this->childProcessor(i).isEqual(that.childProcessor(i), ignoreCoordTransforms)) { return false; } } return true; } GrGLSLFragmentProcessor* GrFragmentProcessor::createGLSLInstance() const { GrGLSLFragmentProcessor* glFragProc = this->onCreateGLSLInstance(); glFragProc->fChildProcessors.push_back_n(fChildProcessors.count()); for (int i = 0; i < fChildProcessors.count(); ++i) { glFragProc->fChildProcessors[i] = fChildProcessors[i]->createGLSLInstance(); } return glFragProc; } void GrFragmentProcessor::addTextureAccess(const GrTextureAccess* textureAccess) { // Can't add texture accesses after registering any children since their texture accesses have // already been bubbled up into our fTextureAccesses array SkASSERT(fChildProcessors.empty()); INHERITED::addTextureAccess(textureAccess); fNumTexturesExclChildren++; } void GrFragmentProcessor::addBufferAccess(const GrBufferAccess* bufferAccess) { // Can't add buffer accesses after registering any children since their buffer accesses have // already been bubbled up into our fBufferAccesses array SkASSERT(fChildProcessors.empty()); INHERITED::addBufferAccess(bufferAccess); fNumBuffersExclChildren++; } void GrFragmentProcessor::addCoordTransform(const GrCoordTransform* transform) { // Can't add transforms after registering any children since their transforms have already been // bubbled up into our fCoordTransforms array SkASSERT(fChildProcessors.empty()); fCoordTransforms.push_back(transform); fUsesLocalCoords = fUsesLocalCoords || transform->sourceCoords() == kLocal_GrCoordSet; SkDEBUGCODE(transform->setInProcessor();) fNumTransformsExclChildren++; } int GrFragmentProcessor::registerChildProcessor(sk_sp child) { // Append the child's transforms to our transforms array and the child's textures array to our // textures array if (!child->fCoordTransforms.empty()) { fCoordTransforms.push_back_n(child->fCoordTransforms.count(), child->fCoordTransforms.begin()); } if (!child->fTextureAccesses.empty()) { fTextureAccesses.push_back_n(child->fTextureAccesses.count(), child->fTextureAccesses.begin()); } this->combineRequiredFeatures(*child); if (child->usesLocalCoords()) { fUsesLocalCoords = true; } int index = fChildProcessors.count(); fChildProcessors.push_back(child.release()); return index; } void GrFragmentProcessor::notifyRefCntIsZero() const { // See comment above GrProgramElement for a detailed explanation of why we do this. for (int i = 0; i < fChildProcessors.count(); ++i) { fChildProcessors[i]->addPendingExecution(); fChildProcessors[i]->unref(); } } bool GrFragmentProcessor::hasSameTransforms(const GrFragmentProcessor& that) const { if (this->numTransforms() != that.numTransforms()) { return false; } int count = this->numTransforms(); for (int i = 0; i < count; ++i) { if (this->coordTransform(i) != that.coordTransform(i)) { return false; } } return true; } sk_sp GrFragmentProcessor::MulOutputByInputAlpha( sk_sp fp) { if (!fp) { return nullptr; } return GrXfermodeFragmentProcessor::MakeFromDstProcessor(std::move(fp), SkXfermode::kDstIn_Mode); } sk_sp GrFragmentProcessor::PremulInput(sk_sp fp) { class PremulInputFragmentProcessor : public GrFragmentProcessor { public: PremulInputFragmentProcessor() { this->initClassID(); } const char* name() const override { return "PremultiplyInput"; } private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { class GLFP : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, args.fInputColor); fragBuilder->codeAppendf("%s.rgb *= %s.a;", args.fOutputColor, args.fInputColor); } }; return new GLFP; } void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override {} bool onIsEqual(const GrFragmentProcessor&) const override { return true; } void onComputeInvariantOutput(GrInvariantOutput* inout) const override { inout->premulFourChannelColor(); } }; if (!fp) { return nullptr; } sk_sp fpPipeline[] = { sk_make_sp(), fp}; return GrFragmentProcessor::RunInSeries(fpPipeline, 2); } sk_sp GrFragmentProcessor::MulOutputByInputUnpremulColor( sk_sp fp) { class PremulFragmentProcessor : public GrFragmentProcessor { public: PremulFragmentProcessor(sk_sp processor) { this->initClassID(); this->registerChildProcessor(processor); } const char* name() const override { return "Premultiply"; } private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { class GLFP : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; this->emitChild(0, nullptr, args); fragBuilder->codeAppendf("%s.rgb *= %s.rgb;", args.fOutputColor, args.fInputColor); fragBuilder->codeAppendf("%s *= %s.a;", args.fOutputColor, args.fInputColor); } }; return new GLFP; } void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override {} bool onIsEqual(const GrFragmentProcessor&) const override { return true; } void onComputeInvariantOutput(GrInvariantOutput* inout) const override { // TODO: Add a helper to GrInvariantOutput that handles multiplying by color with flags? if (!(inout->validFlags() & kA_GrColorComponentFlag)) { inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); return; } GrInvariantOutput childOutput(GrColor_WHITE, kRGBA_GrColorComponentFlags, false); this->childProcessor(0).computeInvariantOutput(&childOutput); if (0 == GrColorUnpackA(inout->color()) || 0 == GrColorUnpackA(childOutput.color())) { inout->mulByKnownFourComponents(0x0); return; } GrColorComponentFlags commonFlags = childOutput.validFlags() & inout->validFlags(); GrColor c0 = GrPremulColor(inout->color()); GrColor c1 = childOutput.color(); GrColor color = 0x0; if (commonFlags & kR_GrColorComponentFlag) { color |= SkMulDiv255Round(GrColorUnpackR(c0), GrColorUnpackR(c1)) << GrColor_SHIFT_R; } if (commonFlags & kG_GrColorComponentFlag) { color |= SkMulDiv255Round(GrColorUnpackG(c0), GrColorUnpackG(c1)) << GrColor_SHIFT_G; } if (commonFlags & kB_GrColorComponentFlag) { color |= SkMulDiv255Round(GrColorUnpackB(c0), GrColorUnpackB(c1)) << GrColor_SHIFT_B; } inout->setToOther(commonFlags, color, GrInvariantOutput::kWill_ReadInput); } }; if (!fp) { return nullptr; } return sk_sp(new PremulFragmentProcessor(std::move(fp))); } ////////////////////////////////////////////////////////////////////////////// sk_sp GrFragmentProcessor::OverrideInput(sk_sp fp, GrColor color) { class ReplaceInputFragmentProcessor : public GrFragmentProcessor { public: ReplaceInputFragmentProcessor(sk_sp child, GrColor color) : fColor(color) { this->initClassID(); this->registerChildProcessor(std::move(child)); } const char* name() const override { return "Replace Color"; } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { class GLFP : public GrGLSLFragmentProcessor { public: GLFP() : fHaveSetColor(false) {} void emitCode(EmitArgs& args) override { const char* colorName; fColorUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec4f_GrSLType, kDefault_GrSLPrecision, "Color", &colorName); this->emitChild(0, colorName, args); } private: void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& fp) override { GrColor color = fp.cast().fColor; if (!fHaveSetColor || color != fPreviousColor) { static const float scale = 1.f / 255.f; float floatColor[4] = { GrColorUnpackR(color) * scale, GrColorUnpackG(color) * scale, GrColorUnpackB(color) * scale, GrColorUnpackA(color) * scale, }; pdman.set4fv(fColorUni, 1, floatColor); fPreviousColor = color; fHaveSetColor = true; } } GrGLSLProgramDataManager::UniformHandle fColorUni; bool fHaveSetColor; GrColor fPreviousColor; }; return new GLFP; } private: void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {} bool onIsEqual(const GrFragmentProcessor& that) const override { return fColor == that.cast().fColor; } void onComputeInvariantOutput(GrInvariantOutput* inout) const override { inout->setToOther(kRGBA_GrColorComponentFlags, fColor, GrInvariantOutput::kWillNot_ReadInput); this->childProcessor(0).computeInvariantOutput(inout); } GrColor fColor; }; GrInvariantOutput childOut(0x0, kNone_GrColorComponentFlags, false); fp->computeInvariantOutput(&childOut); if (childOut.willUseInputColor()) { return sk_sp(new ReplaceInputFragmentProcessor(std::move(fp), color)); } else { return fp; } } sk_sp GrFragmentProcessor::RunInSeries(sk_sp* series, int cnt) { class SeriesFragmentProcessor : public GrFragmentProcessor { public: SeriesFragmentProcessor(sk_sp* children, int cnt){ SkASSERT(cnt > 1); this->initClassID(); for (int i = 0; i < cnt; ++i) { this->registerChildProcessor(std::move(children[i])); } } const char* name() const override { return "Series"; } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { class GLFP : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs& args) override { // First guy's input might be nil. SkString temp("out0"); this->emitChild(0, args.fInputColor, &temp, args); SkString input = temp; for (int i = 1; i < this->numChildProcessors() - 1; ++i) { temp.printf("out%d", i); this->emitChild(i, input.c_str(), &temp, args); input = temp; } // Last guy writes to our output variable. this->emitChild(this->numChildProcessors() - 1, input.c_str(), args); } }; return new GLFP; } private: void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override {} bool onIsEqual(const GrFragmentProcessor&) const override { return true; } void onComputeInvariantOutput(GrInvariantOutput* inout) const override { GrProcOptInfo info; info.calcWithInitialValues(fChildProcessors.begin(), fChildProcessors.count(), inout->color(), inout->validFlags(), false, false); for (int i = 0; i < this->numChildProcessors(); ++i) { this->childProcessor(i).computeInvariantOutput(inout); } } }; if (!cnt) { return nullptr; } // Run the through the series, do the invariant output processing, and look for eliminations. GrProcOptInfo info; info.calcWithInitialValues(sk_sp_address_as_pointer_address(series), cnt, 0x0, kNone_GrColorComponentFlags, false, false); if (kRGBA_GrColorComponentFlags == info.validFlags()) { return GrConstColorProcessor::Make(info.color(), GrConstColorProcessor::kIgnore_InputMode); } SkTArray> replacementSeries; int firstIdx = info.firstEffectiveProcessorIndex(); cnt -= firstIdx; if (firstIdx > 0 && info.inputColorIsUsed()) { sk_sp colorFP(GrConstColorProcessor::Make( info.inputColorToFirstEffectiveProccesor(), GrConstColorProcessor::kIgnore_InputMode)); cnt += 1; replacementSeries.reserve(cnt); replacementSeries.emplace_back(std::move(colorFP)); for (int i = 0; i < cnt - 1; ++i) { replacementSeries.emplace_back(std::move(series[firstIdx + i])); } series = replacementSeries.begin(); } else { series += firstIdx; cnt -= firstIdx; } if (1 == cnt) { return series[0]; } return sk_sp(new SeriesFragmentProcessor(series, cnt)); }