Use child effects for LUTs in perline noise effects

Bug: skia:10139

Change-Id: Ie7e4cf0cd583c8cb6eafd7ab30b729ee755f5042
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297060
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2020-06-17 11:46:21 -04:00 committed by Skia Commit-Bot
parent 99b047087d
commit 83c2d35155

View File

@ -21,6 +21,7 @@
#include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrCoordTransform.h"
#include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/SkGr.h" #include "src/gpu/SkGr.h"
#include "src/gpu/effects/GrTextureEffect.h"
#include "src/gpu/effects/generated/GrConstColorProcessor.h" #include "src/gpu/effects/generated/GrConstColorProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h" #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
@ -717,13 +718,26 @@ private:
class GrPerlinNoise2Effect : public GrFragmentProcessor { class GrPerlinNoise2Effect : public GrFragmentProcessor {
public: public:
static std::unique_ptr<GrFragmentProcessor> Make( static std::unique_ptr<GrFragmentProcessor> Make(
SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles, SkPerlinNoiseShaderImpl::Type type,
int numOctaves,
bool stitchTiles,
std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData, std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
GrSurfaceProxyView permutationsView, GrSurfaceProxyView noiseView, GrSurfaceProxyView permutationsView,
const SkMatrix& matrix) { GrSurfaceProxyView noiseView,
return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect( const SkMatrix& matrix,
type, numOctaves, stitchTiles, std::move(paintingData), const GrCaps& caps) {
std::move(permutationsView), std::move(noiseView), matrix)); static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
GrSamplerState::WrapMode::kClamp,
GrSamplerState::Filter::kNearest};
auto permutationsFP =
GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
SkMatrix::I(), kRepeatXSampler, caps);
auto noiseFP = GrTextureEffect::Make(std::move(noiseView), kPremul_SkAlphaType,
SkMatrix::I(), kRepeatXSampler, caps);
return std::unique_ptr<GrFragmentProcessor>(
new GrPerlinNoise2Effect(type, numOctaves, stitchTiles, std::move(paintingData),
std::move(permutationsFP), std::move(noiseFP), matrix));
} }
const char* name() const override { return "PerlinNoise"; } const char* name() const override { return "PerlinNoise"; }
@ -759,23 +773,22 @@ private:
fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit; fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
} }
static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat, GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type,
GrSamplerState::WrapMode::kClamp, int numOctaves,
GrSamplerState::Filter::kNearest}; bool stitchTiles,
GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData, std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
GrSurfaceProxyView permutationsView, std::unique_ptr<GrFragmentProcessor> permutationsFP,
GrSurfaceProxyView noiseView, std::unique_ptr<GrFragmentProcessor> noiseFP,
const SkMatrix& matrix) const SkMatrix& matrix)
: INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags) : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
, fType(type) , fType(type)
, fNumOctaves(numOctaves) , fNumOctaves(numOctaves)
, fStitchTiles(stitchTiles) , fStitchTiles(stitchTiles)
, fPermutationsSampler(std::move(permutationsView), kRepeatXSampler)
, fNoiseSampler(std::move(noiseView), kRepeatXSampler)
, fPaintingData(std::move(paintingData)) { , fPaintingData(std::move(paintingData)) {
this->setTextureSamplerCnt(2); permutationsFP->setSampledWithExplicitCoords();
this->registerChildProcessor(std::move(permutationsFP));
noiseFP->setSampledWithExplicitCoords();
this->registerChildProcessor(std::move(noiseFP));
fCoordTransform = GrCoordTransform(matrix); fCoordTransform = GrCoordTransform(matrix);
this->addCoordTransform(&fCoordTransform); this->addCoordTransform(&fCoordTransform);
} }
@ -786,16 +799,11 @@ private:
, fCoordTransform(that.fCoordTransform) , fCoordTransform(that.fCoordTransform)
, fNumOctaves(that.fNumOctaves) , fNumOctaves(that.fNumOctaves)
, fStitchTiles(that.fStitchTiles) , fStitchTiles(that.fStitchTiles)
, fPermutationsSampler(that.fPermutationsSampler)
, fNoiseSampler(that.fNoiseSampler)
, fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) { , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
this->setTextureSamplerCnt(2); this->cloneAndRegisterAllChildProcessors(that);
this->addCoordTransform(&fCoordTransform); this->addCoordTransform(&fCoordTransform);
} }
const TextureSampler& onTextureSampler(int i) const override {
return IthTextureSampler(i, fPermutationsSampler, fNoiseSampler);
}
GR_DECLARE_FRAGMENT_PROCESSOR_TEST GR_DECLARE_FRAGMENT_PROCESSOR_TEST
@ -803,8 +811,7 @@ private:
GrCoordTransform fCoordTransform; GrCoordTransform fCoordTransform;
int fNumOctaves; int fNumOctaves;
bool fStitchTiles; bool fStitchTiles;
TextureSampler fPermutationsSampler;
TextureSampler fNoiseSampler;
std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData; std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
typedef GrFragmentProcessor INHERITED; typedef GrFragmentProcessor INHERITED;
@ -882,15 +889,9 @@ void GrGLPerlinNoise::emitCode(EmitArgs& args) {
if (floorVal.w >= stitchData.y) { floorVal.w -= stitchData.y; };)"); if (floorVal.w >= stitchData.y) { floorVal.w -= stitchData.y; };)");
} }
// Get texture coordinates and normalize SkString sampleX = this->invokeChild(0, args, "half2(floorVal.x, 0.5)");
noiseCode.append(R"(floorVal /= 256; SkString sampleY = this->invokeChild(0, args, "half2(floorVal.z, 0.5)");
half2 latticeIdx; noiseCode.appendf("half2 latticeIdx = half2(%s.r, %s.r);", sampleX.c_str(), sampleY.c_str());
latticeIdx.x = )");
fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], "half2(floorVal.x, 0.5)");
noiseCode.append(R"(.r;
latticeIdx.y = )");
fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], "half2(floorVal.z, 0.5)");
noiseCode.append(".r;");
#if defined(SK_BUILD_FOR_ANDROID) #if defined(SK_BUILD_FOR_ANDROID)
// Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3). // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
@ -904,7 +905,7 @@ void GrGLPerlinNoise::emitCode(EmitArgs& args) {
#endif #endif
// Get (x,y) coordinates with the permutated x // Get (x,y) coordinates with the permutated x
noiseCode.append("half4 bcoords = latticeIdx.xyxy + floorVal.yyww;"); noiseCode.append("half4 bcoords = 256*latticeIdx.xyxy + floorVal.yyww;");
noiseCode.append("half2 uv;"); noiseCode.append("half2 uv;");
@ -915,20 +916,19 @@ void GrGLPerlinNoise::emitCode(EmitArgs& args) {
SkString dotLattice = SkString dotLattice =
SkStringPrintf("dot((lattice.ga + lattice.rb*%s)*2 - half2(1), fractVal)", inc8bit); SkStringPrintf("dot((lattice.ga + lattice.rb*%s)*2 - half2(1), fractVal)", inc8bit);
SkString sampleA = this->invokeChild(1, args, "half2(bcoords.x, chanCoord)");
SkString sampleB = this->invokeChild(1, args, "half2(bcoords.y, chanCoord)");
SkString sampleC = this->invokeChild(1, args, "half2(bcoords.w, chanCoord)");
SkString sampleD = this->invokeChild(1, args, "half2(bcoords.z, chanCoord)");
// Compute u, at offset (0,0) // Compute u, at offset (0,0)
noiseCode.append("half4 lattice = "); noiseCode.appendf("half4 lattice = %s;", sampleA.c_str());
fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
"half2(bcoords.x, chanCoord)");
noiseCode.appendf(R"(;
uv.x = %s;)", dotLattice.c_str());
// Compute v, at offset (-1,0) // Compute v, at offset (-1,0)
noiseCode.append("fractVal.x -= 1.0;"); noiseCode.append("fractVal.x -= 1.0;");
noiseCode.append("lattice = "); noiseCode.appendf("lattice = %s;", sampleB.c_str());
fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
"half2(bcoords.y, chanCoord)");
noiseCode.appendf(R"(;
uv.y = %s;)", dotLattice.c_str());
// Compute 'a' as a linear interpolation of 'u' and 'v' // Compute 'a' as a linear interpolation of 'u' and 'v'
noiseCode.append("half2 ab;"); noiseCode.append("half2 ab;");
@ -936,19 +936,13 @@ void GrGLPerlinNoise::emitCode(EmitArgs& args) {
// Compute v, at offset (-1,-1) // Compute v, at offset (-1,-1)
noiseCode.append("fractVal.y -= 1.0;"); noiseCode.append("fractVal.y -= 1.0;");
noiseCode.append("lattice = "); noiseCode.appendf("lattice = %s;", sampleC.c_str());
fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
"half2(bcoords.w, chanCoord)");
noiseCode.appendf(R"(;
uv.y = %s;)", dotLattice.c_str());
// Compute u, at offset (0,-1) // Compute u, at offset (0,-1)
noiseCode.append("fractVal.x += 1.0;"); noiseCode.append("fractVal.x += 1.0;");
noiseCode.append("lattice = "); noiseCode.appendf("lattice = %s;", sampleD.c_str());
fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
"half2(bcoords.z, chanCoord)");
noiseCode.appendf(R"(;
uv.x = %s;)", dotLattice.c_str());
// Compute 'b' as a linear interpolation of 'u' and 'v' // Compute 'b' as a linear interpolation of 'u' and 'v'
noiseCode.append("ab.y = mix(uv.x, uv.y, noiseSmooth.x);"); noiseCode.append("ab.y = mix(uv.x, uv.y, noiseSmooth.x);");
@ -987,11 +981,11 @@ void GrGLPerlinNoise::emitCode(EmitArgs& args) {
fragBuilder->codeAppend("abs("); fragBuilder->codeAppend("abs(");
} }
// There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8 // There are 4 lines, put y coords at center of each.
static constexpr const char* chanCoordR = "0.125"; static constexpr const char* chanCoordR = "0.5";
static constexpr const char* chanCoordG = "0.375"; static constexpr const char* chanCoordG = "1.5";
static constexpr const char* chanCoordB = "0.625"; static constexpr const char* chanCoordB = "2.5";
static constexpr const char* chanCoordA = "0.875"; static constexpr const char* chanCoordA = "3.5";
if (pne.stitchTiles()) { if (pne.stitchTiles()) {
fragBuilder->codeAppendf(R"( fragBuilder->codeAppendf(R"(
half4(%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData)," half4(%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData),"
@ -1104,13 +1098,24 @@ private:
class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor { class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
public: public:
static std::unique_ptr<GrFragmentProcessor> Make( static std::unique_ptr<GrFragmentProcessor> Make(
int octaves, SkScalar z, int octaves,
SkScalar z,
std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData, std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
GrSurfaceProxyView permutationsView, GrSurfaceProxyView gradientView, GrSurfaceProxyView permutationsView,
const SkMatrix& matrix) { GrSurfaceProxyView gradientView,
const SkMatrix& matrix,
const GrCaps& caps) {
static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
GrSamplerState::WrapMode::kClamp,
GrSamplerState::Filter::kNearest};
auto permutationsFP =
GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
SkMatrix::I(), kRepeatXSampler, caps);
auto gradientFP = GrTextureEffect::Make(std::move(gradientView), kPremul_SkAlphaType,
SkMatrix::I(), kRepeatXSampler, caps);
return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect( return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
octaves, z, std::move(paintingData), std::move(permutationsView), octaves, z, std::move(paintingData), std::move(permutationsFP),
std::move(gradientView), matrix)); std::move(gradientFP), matrix));
} }
const char* name() const override { return "ImprovedPerlinNoise"; } const char* name() const override { return "ImprovedPerlinNoise"; }
@ -1139,21 +1144,20 @@ private:
fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency; fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
} }
static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat, GrImprovedPerlinNoiseEffect(int octaves,
GrSamplerState::WrapMode::kClamp, SkScalar z,
GrSamplerState::Filter::kNearest};
GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData, std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
GrSurfaceProxyView permutationsView, std::unique_ptr<GrFragmentProcessor> permutationsFP,
GrSurfaceProxyView gradientView, std::unique_ptr<GrFragmentProcessor> gradientFP,
const SkMatrix& matrix) const SkMatrix& matrix)
: INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags) : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
, fOctaves(octaves) , fOctaves(octaves)
, fZ(z) , fZ(z)
, fPermutationsSampler(std::move(permutationsView), kRepeatXSampler)
, fGradientSampler(std::move(gradientView), kRepeatXSampler)
, fPaintingData(std::move(paintingData)) { , fPaintingData(std::move(paintingData)) {
this->setTextureSamplerCnt(2); permutationsFP->setSampledWithExplicitCoords();
this->registerChildProcessor(std::move(permutationsFP));
gradientFP->setSampledWithExplicitCoords();
this->registerChildProcessor(std::move(gradientFP));
fCoordTransform = GrCoordTransform(matrix); fCoordTransform = GrCoordTransform(matrix);
this->addCoordTransform(&fCoordTransform); this->addCoordTransform(&fCoordTransform);
} }
@ -1163,24 +1167,17 @@ private:
, fCoordTransform(that.fCoordTransform) , fCoordTransform(that.fCoordTransform)
, fOctaves(that.fOctaves) , fOctaves(that.fOctaves)
, fZ(that.fZ) , fZ(that.fZ)
, fPermutationsSampler(that.fPermutationsSampler)
, fGradientSampler(that.fGradientSampler)
, fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) { , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
this->setTextureSamplerCnt(2); this->cloneAndRegisterAllChildProcessors(that);
this->addCoordTransform(&fCoordTransform); this->addCoordTransform(&fCoordTransform);
} }
const TextureSampler& onTextureSampler(int i) const override {
return IthTextureSampler(i, fPermutationsSampler, fGradientSampler);
}
GR_DECLARE_FRAGMENT_PROCESSOR_TEST GR_DECLARE_FRAGMENT_PROCESSOR_TEST
GrCoordTransform fCoordTransform; GrCoordTransform fCoordTransform;
int fOctaves; int fOctaves;
SkScalar fZ; SkScalar fZ;
TextureSampler fPermutationsSampler;
TextureSampler fGradientSampler;
std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData; std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
typedef GrFragmentProcessor INHERITED; typedef GrFragmentProcessor INHERITED;
@ -1235,41 +1232,39 @@ void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
// perm function // perm function
const GrShaderVar permArgs[] = { const GrShaderVar permArgs[] = {
GrShaderVar("x", kHalf_GrSLType) {"x", kHalf_GrSLType}
}; };
SkString samplePerm = this->invokeChild(0, args, "float2(x, 0.5)");
SkString permFuncName; SkString permFuncName;
SkString permCode("return "); SkString permCode = SkStringPrintf("return %s.r * 255;", samplePerm.c_str());
fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0], "float2(x/256.0, 0.0)");
permCode.append(".r * 255.0;");
fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs, fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
permCode.c_str(), &permFuncName); permCode.c_str(), &permFuncName);
// grad function // grad function
const GrShaderVar gradArgs[] = { const GrShaderVar gradArgs[] = {
GrShaderVar("x", kHalf_GrSLType), {"x", kHalf_GrSLType},
GrShaderVar("p", kHalf3_GrSLType) {"p", kHalf3_GrSLType}
}; };
SkString sampleGrad = this->invokeChild(1, args, "float2(x, 0.5)");
SkString gradFuncName; SkString gradFuncName;
SkString gradCode("return half(dot("); SkString gradCode = SkStringPrintf("return half(dot(%s.rgb * 255.0 - float3(1.0), p));",
fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1], sampleGrad.c_str());
"float2(x/16.0, 0.0)");
gradCode.append(".rgb * 255.0 - float3(1.0), p));");
fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs, fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
gradCode.c_str(), &gradFuncName); gradCode.c_str(), &gradFuncName);
// lerp function // lerp function
const GrShaderVar lerpArgs[] = { const GrShaderVar lerpArgs[] = {
GrShaderVar("a", kHalf_GrSLType), {"a", kHalf_GrSLType},
GrShaderVar("b", kHalf_GrSLType), {"b", kHalf_GrSLType},
GrShaderVar("w", kHalf_GrSLType) {"w", kHalf_GrSLType}
}; };
SkString lerpFuncName; SkString lerpFuncName;
fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs, fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
"return a + w * (b - a);", &lerpFuncName); "return a + w * (b - a);", &lerpFuncName);
// noise function // noise function
const GrShaderVar noiseArgs[] = { const GrShaderVar noiseArgs[] = {
GrShaderVar("p", kHalf3_GrSLType), {"p", kHalf3_GrSLType},
}; };
SkString noiseFuncName; SkString noiseFuncName;
SkString noiseCode; SkString noiseCode;
@ -1306,7 +1301,7 @@ void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
// noiseOctaves function // noiseOctaves function
const GrShaderVar noiseOctavesArgs[] = { const GrShaderVar noiseOctavesArgs[] = {
GrShaderVar("p", kHalf3_GrSLType) {"p", kHalf3_GrSLType}
}; };
SkString noiseOctavesFuncName; SkString noiseOctavesFuncName;
SkString noiseOctavesCode; SkString noiseOctavesCode;
@ -1393,9 +1388,13 @@ std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcesso
const SkBitmap& gradientBitmap = paintingData->getGradientBitmap(); const SkBitmap& gradientBitmap = paintingData->getGradientBitmap();
SkASSERT(SkIsPow2(gradientBitmap.width()) && SkIsPow2(gradientBitmap.height())); SkASSERT(SkIsPow2(gradientBitmap.width()) && SkIsPow2(gradientBitmap.height()));
auto gradientView = GrMakeCachedBitmapProxyView(context, gradientBitmap); auto gradientView = GrMakeCachedBitmapProxyView(context, gradientBitmap);
return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData), return GrImprovedPerlinNoiseEffect::Make(fNumOctaves,
fSeed,
std::move(paintingData),
std::move(permutationsView), std::move(permutationsView),
std::move(gradientView), m); std::move(gradientView),
m,
*context->priv().caps());
} }
if (0 == fNumOctaves) { if (0 == fNumOctaves) {
@ -1432,7 +1431,8 @@ std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcesso
std::move(paintingData), std::move(paintingData),
std::move(permutationsView), std::move(permutationsView),
std::move(noiseView), std::move(noiseView),
m); m,
*context->priv().caps());
return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner)); return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
} }
return nullptr; return nullptr;