diff --git a/gn/gpu.gni b/gn/gpu.gni index ef751dba4c..6922c07590 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -350,6 +350,8 @@ skia_gpu_sources = [ "$_src/gpu/effects/GrOvalEffect.h", "$_src/gpu/effects/GrPorterDuffXferProcessor.cpp", "$_src/gpu/effects/GrPorterDuffXferProcessor.h", + "$_src/gpu/effects/GrRectBlurEffect.cpp", + "$_src/gpu/effects/GrRectBlurEffect.h", "$_src/gpu/effects/GrRRectEffect.cpp", "$_src/gpu/effects/GrRRectEffect.h", "$_src/gpu/effects/GrShadowGeoProc.cpp", diff --git a/gn/sksl.gni b/gn/sksl.gni index 1de85f6fae..615b5dcbcc 100644 --- a/gn/sksl.gni +++ b/gn/sksl.gni @@ -33,5 +33,6 @@ skia_gpu_processor_sources = [ "$_src/gpu/effects/GrConfigConversionEffect.fp", "$_src/gpu/effects/GrDitherEffect.fp", "$_src/gpu/effects/GrEllipseEffect.fp", + "$_src/gpu/effects/GrRectBlurEffect.fp", "$_src/gpu/effects/GrSimpleTextureEffect.fp", ] diff --git a/src/effects/GrAlphaThresholdFragmentProcessor.cpp b/src/effects/GrAlphaThresholdFragmentProcessor.cpp index e1badf7f21..5ef0221be7 100644 --- a/src/effects/GrAlphaThresholdFragmentProcessor.cpp +++ b/src/effects/GrAlphaThresholdFragmentProcessor.cpp @@ -34,6 +34,12 @@ public: const GrAlphaThresholdFragmentProcessor& _outer = args.fFp.cast(); (void)_outer; + auto colorXform = _outer.colorXform(); + (void)colorXform; + auto innerThreshold = _outer.innerThreshold(); + (void)innerThreshold; + auto outerThreshold = _outer.outerThreshold(); + (void)outerThreshold; fColorSpaceHelper.emitCode(args.fUniformHandler, _outer.colorXform().get()); fInnerThresholdVar = args.fUniformHandler->addUniform( kFragment_GrShaderFlag, kHalf_GrSLType, kDefault_GrSLPrecision, "innerThreshold"); diff --git a/src/effects/GrCircleBlurFragmentProcessor.cpp b/src/effects/GrCircleBlurFragmentProcessor.cpp index 5a825f49f5..647afb8076 100644 --- a/src/effects/GrCircleBlurFragmentProcessor.cpp +++ b/src/effects/GrCircleBlurFragmentProcessor.cpp @@ -263,6 +263,12 @@ public: const GrCircleBlurFragmentProcessor& _outer = args.fFp.cast(); (void)_outer; + auto circleRect = _outer.circleRect(); + (void)circleRect; + auto textureRadius = _outer.textureRadius(); + (void)textureRadius; + auto solidRadius = _outer.solidRadius(); + (void)solidRadius; fCircleDataVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, kDefault_GrSLPrecision, "circleData"); fragBuilder->codeAppendf( diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index ca7de71914..7da42459f4 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -26,6 +26,7 @@ #include "GrShaderCaps.h" #include "GrStyle.h" #include "GrTextureProxy.h" +#include "effects/GrRectBlurEffect.h" #include "effects/GrSimpleTextureEffect.h" #include "effects/GrTextureDomain.h" #include "glsl/GrGLSLFragmentProcessor.h" @@ -761,253 +762,6 @@ void SkBlurMaskFilterImpl::flatten(SkWriteBuffer& buffer) const { #if SK_SUPPORT_GPU -class GrGLRectBlurEffect; - -class GrRectBlurEffect : public GrFragmentProcessor { -public: - ~GrRectBlurEffect() override { } - - const char* name() const override { return "RectBlur"; } - - static std::unique_ptr Make(GrResourceProvider* resourceProvider, - const SkRect& rect, float sigma) { - int doubleProfileSize = SkScalarCeilToInt(12*sigma); - - if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) { - // if the blur sigma is too large so the gaussian overlaps the whole - // rect in either direction, fall back to CPU path for now. - return nullptr; - } - - sk_sp blurProfile(CreateBlurProfileTexture(resourceProvider, sigma)); - if (!blurProfile) { - return nullptr; - } - // in OpenGL ES, mediump floats have a minimum range of 2^14. If we have coordinates bigger - // than that, the shader math will end up with infinities and result in the blur effect not - // working correctly. To avoid this, we switch into highp when the coordinates are too big. - // As 2^14 is the minimum range but the actual range can be bigger, we might end up - // switching to highp sooner than strictly necessary, but most devices that have a bigger - // range for mediump also have mediump being exactly the same as highp (e.g. all non-OpenGL - // ES devices), and thus incur no additional penalty for the switch. - static const SkScalar kMAX_BLUR_COORD = SkIntToScalar(16000); - GrSLPrecision precision; - if (SkScalarAbs(rect.top()) > kMAX_BLUR_COORD || - SkScalarAbs(rect.left()) > kMAX_BLUR_COORD || - SkScalarAbs(rect.bottom()) > kMAX_BLUR_COORD || - SkScalarAbs(rect.right()) > kMAX_BLUR_COORD || - SkScalarAbs(rect.width()) > kMAX_BLUR_COORD || - SkScalarAbs(rect.height()) > kMAX_BLUR_COORD) { - precision = kHigh_GrSLPrecision; - } else { - precision = kDefault_GrSLPrecision; - } - - return std::unique_ptr( - new GrRectBlurEffect(rect, sigma, std::move(blurProfile), precision)); - } - - std::unique_ptr clone() const override { - return std::unique_ptr(new GrRectBlurEffect( - fRect, fSigma, sk_ref_sp(fBlurProfileSampler.proxy()), fPrecision)); - } - - const SkRect& getRect() const { return fRect; } - float getSigma() const { return fSigma; } - GrSLPrecision precision() const { return fPrecision; } - -private: - GrRectBlurEffect(const SkRect& rect, float sigma, - sk_sp blurProfile, GrSLPrecision fPrecision); - - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - - void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; - - bool onIsEqual(const GrFragmentProcessor&) const override; - - static sk_sp CreateBlurProfileTexture(GrResourceProvider*, float sigma); - - SkRect fRect; - float fSigma; - TextureSampler fBlurProfileSampler; - GrSLPrecision fPrecision; - - GR_DECLARE_FRAGMENT_PROCESSOR_TEST - - typedef GrFragmentProcessor INHERITED; -}; - -class GrGLRectBlurEffect : public GrGLSLFragmentProcessor { -public: - void emitCode(EmitArgs&) override; - - static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b); - -protected: - void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; - -private: - typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; - - UniformHandle fProxyRectUniform; - UniformHandle fProfileSizeUniform; - - typedef GrGLSLFragmentProcessor INHERITED; -}; - -void OutputRectBlurProfileLookup(GrGLSLFPFragmentBuilder* fragBuilder, - GrGLSLFragmentProcessor::SamplerHandle sampler, - const char *output, - const char *profileSize, const char *loc, - const char *blurred_width, - const char *sharp_width) { - fragBuilder->codeAppendf("half %s;", output); - fragBuilder->codeAppendf("{"); - fragBuilder->codeAppendf("half coord = ((abs(%s - 0.5 * %s) - 0.5 * %s)) / %s;", - loc, blurred_width, sharp_width, profileSize); - fragBuilder->codeAppendf("%s = ", output); - fragBuilder->appendTextureLookup(sampler, "half2(coord,0.5)"); - fragBuilder->codeAppend(".a;"); - fragBuilder->codeAppendf("}"); -} - - -void GrGLRectBlurEffect::GenKey(const GrProcessor& proc, const GrShaderCaps&, - GrProcessorKeyBuilder* b) { - const GrRectBlurEffect& rbe = proc.cast(); - - b->add32(rbe.precision()); -} - - -void GrGLRectBlurEffect::emitCode(EmitArgs& args) { - const GrRectBlurEffect& rbe = args.fFp.cast(); - - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - - const char *rectName; - const char *profileSizeName; - - const char* floatType = rbe.precision() == kHigh_GrSLPrecision ? "float" : "half"; - fProxyRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, - rbe.precision() == kHigh_GrSLPrecision ? - kFloat4_GrSLType : kHalf4_GrSLType, - "proxyRect", - &rectName); - fProfileSizeUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, - kHalf_GrSLType, - "profileSize", - &profileSizeName); - - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - - if (args.fInputColor) { - fragBuilder->codeAppendf("half4 src=%s;", args.fInputColor); - } else { - fragBuilder->codeAppendf("half4 src=half4(1);"); - } - - fragBuilder->codeAppendf("%s2 translatedPos = sk_FragCoord.xy - %s.xy;", floatType, rectName); - fragBuilder->codeAppendf("%s width = %s.z - %s.x;", floatType, rectName, rectName); - fragBuilder->codeAppendf("%s height = %s.w - %s.y;", floatType, rectName, rectName); - - fragBuilder->codeAppendf("%s2 smallDims = half2(width - %s, height - %s);", floatType, - profileSizeName, profileSizeName); - fragBuilder->codeAppendf("%s center = 2.0 * floor(%s/2.0 + .25) - 1.0;", floatType, - profileSizeName); - fragBuilder->codeAppendf("%s2 wh = smallDims - half2(center,center);", floatType); - - OutputRectBlurProfileLookup(fragBuilder, args.fTexSamplers[0], "horiz_lookup", profileSizeName, - "translatedPos.x", "width", "wh.x"); - OutputRectBlurProfileLookup(fragBuilder, args.fTexSamplers[0], "vert_lookup", profileSizeName, - "translatedPos.y", "height", "wh.y"); - - fragBuilder->codeAppendf("half final = horiz_lookup * vert_lookup;"); - fragBuilder->codeAppendf("%s = src * final;", args.fOutputColor); -} - -void GrGLRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrFragmentProcessor& proc) { - const GrRectBlurEffect& rbe = proc.cast(); - SkRect rect = rbe.getRect(); - - pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); - pdman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma())); -} - -sk_sp GrRectBlurEffect::CreateBlurProfileTexture( - GrResourceProvider* resourceProvider, - float sigma) { - unsigned int profileSize = SkScalarCeilToInt(6*sigma); - - static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey key; - GrUniqueKey::Builder builder(&key, kDomain, 1); - builder[0] = profileSize; - builder.finish(); - - sk_sp blurProfile(resourceProvider->findOrCreateProxyByUniqueKey( - key, kTopLeft_GrSurfaceOrigin)); - if (!blurProfile) { - GrSurfaceDesc texDesc; - texDesc.fOrigin = kTopLeft_GrSurfaceOrigin; - texDesc.fWidth = profileSize; - texDesc.fHeight = 1; - texDesc.fConfig = kAlpha_8_GrPixelConfig; - - std::unique_ptr profile(SkBlurMask::ComputeBlurProfile(sigma)); - - blurProfile = GrSurfaceProxy::MakeDeferred(resourceProvider, - texDesc, SkBudgeted::kYes, profile.get(), 0); - if (!blurProfile) { - return nullptr; - } - - SkASSERT(blurProfile->origin() == kTopLeft_GrSurfaceOrigin); - resourceProvider->assignUniqueKeyToProxy(key, blurProfile.get()); - } - - return blurProfile; -} - -GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, - sk_sp blurProfile, - GrSLPrecision precision) - : INHERITED(kGrRectBlurEffect_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag) - , fRect(rect) - , fSigma(sigma) - , fBlurProfileSampler(std::move(blurProfile)) - , fPrecision(precision) { - this->addTextureSampler(&fBlurProfileSampler); -} - -void GrRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const { - GrGLRectBlurEffect::GenKey(*this, caps, b); -} - -GrGLSLFragmentProcessor* GrRectBlurEffect::onCreateGLSLInstance() const { - return new GrGLRectBlurEffect; -} - -bool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& sBase) const { - const GrRectBlurEffect& s = sBase.cast(); - return this->getSigma() == s.getSigma() && this->getRect() == s.getRect(); -} - -GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect); - -#if GR_TEST_UTILS -std::unique_ptr GrRectBlurEffect::TestCreate(GrProcessorTestData* d) { - float sigma = d->fRandom->nextRangeF(3,8); - float width = d->fRandom->nextRangeF(200,300); - float height = d->fRandom->nextRangeF(200,300); - return GrRectBlurEffect::Make(d->resourceProvider(), - SkRect::MakeWH(width, height), sigma); -} -#endif - bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context, GrRenderTargetContext* renderTargetContext, GrPaint&& paint, diff --git a/src/gpu/effects/GrArithmeticFP.cpp b/src/gpu/effects/GrArithmeticFP.cpp index bc73b45dc2..fec3fbffad 100644 --- a/src/gpu/effects/GrArithmeticFP.cpp +++ b/src/gpu/effects/GrArithmeticFP.cpp @@ -23,6 +23,16 @@ public: GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrArithmeticFP& _outer = args.fFp.cast(); (void)_outer; + auto k1 = _outer.k1(); + (void)k1; + auto k2 = _outer.k2(); + (void)k2; + auto k3 = _outer.k3(); + (void)k3; + auto k4 = _outer.k4(); + (void)k4; + auto enforcePMColor = _outer.enforcePMColor(); + (void)enforcePMColor; fKVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType, kDefault_GrSLPrecision, "k"); SkString _child0("_child0"); diff --git a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp index 551adeac8f..2e42b238ab 100644 --- a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp +++ b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp @@ -24,6 +24,8 @@ public: const GrBlurredEdgeFragmentProcessor& _outer = args.fFp.cast(); (void)_outer; + auto mode = _outer.mode(); + (void)mode; fragBuilder->codeAppendf( "half factor = half(1.0 - float(%s.w));\n@switch (%d) {\n case 0:\n " "factor = half(exp(float(float(-factor * factor) * 4.0)) - " diff --git a/src/gpu/effects/GrCircleEffect.cpp b/src/gpu/effects/GrCircleEffect.cpp index 3c0e11b621..b181669d4d 100644 --- a/src/gpu/effects/GrCircleEffect.cpp +++ b/src/gpu/effects/GrCircleEffect.cpp @@ -23,6 +23,12 @@ public: GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrCircleEffect& _outer = args.fFp.cast(); (void)_outer; + auto edgeType = _outer.edgeType(); + (void)edgeType; + auto center = _outer.center(); + (void)center; + auto radius = _outer.radius(); + (void)radius; prevRadius = -1.0; fCircleVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, kDefault_GrSLPrecision, "circle"); diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp index 0d2a139816..d8c9044bbb 100644 --- a/src/gpu/effects/GrConfigConversionEffect.cpp +++ b/src/gpu/effects/GrConfigConversionEffect.cpp @@ -23,6 +23,8 @@ public: GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrConfigConversionEffect& _outer = args.fFp.cast(); (void)_outer; + auto pmConversion = _outer.pmConversion(); + (void)pmConversion; fragBuilder->forceHighPrecision(); fragBuilder->codeAppendf( diff --git a/src/gpu/effects/GrDitherEffect.cpp b/src/gpu/effects/GrDitherEffect.cpp index 2498ffc134..88b8bdba9d 100644 --- a/src/gpu/effects/GrDitherEffect.cpp +++ b/src/gpu/effects/GrDitherEffect.cpp @@ -23,6 +23,8 @@ public: GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrDitherEffect& _outer = args.fFp.cast(); (void)_outer; + auto rangeType = _outer.rangeType(); + (void)rangeType; fragBuilder->codeAppendf( "half value;\nhalf range;\n@switch (%d) {\n case 0:\n range = " "0.0039215686274509803;\n break;\n case 1:\n range = " diff --git a/src/gpu/effects/GrEllipseEffect.cpp b/src/gpu/effects/GrEllipseEffect.cpp index 8621c9a242..61b8f96c07 100644 --- a/src/gpu/effects/GrEllipseEffect.cpp +++ b/src/gpu/effects/GrEllipseEffect.cpp @@ -23,6 +23,12 @@ public: GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrEllipseEffect& _outer = args.fFp.cast(); (void)_outer; + auto edgeType = _outer.edgeType(); + (void)edgeType; + auto center = _outer.center(); + (void)center; + auto radii = _outer.radii(); + (void)radii; prevRadii = half2(-1.0); useScale = sk_Caps.floatPrecisionVaries; fEllipseVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType, diff --git a/src/gpu/effects/GrRectBlurEffect.cpp b/src/gpu/effects/GrRectBlurEffect.cpp new file mode 100644 index 0000000000..3b2d8a1927 --- /dev/null +++ b/src/gpu/effects/GrRectBlurEffect.cpp @@ -0,0 +1,167 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* + * This file was autogenerated from GrRectBlurEffect.fp; do not modify. + */ +#include "GrRectBlurEffect.h" +#if SK_SUPPORT_GPU +#include "glsl/GrGLSLColorSpaceXformHelper.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "glsl/GrGLSLProgramBuilder.h" +#include "SkSLCPP.h" +#include "SkSLUtil.h" +class GrGLSLRectBlurEffect : public GrGLSLFragmentProcessor { +public: + GrGLSLRectBlurEffect() {} + void emitCode(EmitArgs& args) override { + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + const GrRectBlurEffect& _outer = args.fFp.cast(); + (void)_outer; + auto rect = _outer.rect(); + (void)rect; + auto sigma = _outer.sigma(); + (void)sigma; + highPrecision = ((((abs(rect.left()) > 16000.0 || abs(rect.top()) > 16000.0) || + abs(rect.right()) > 16000.0) || + abs(rect.bottom()) > 16000.0) || + abs(rect.right() - rect.left()) > 16000.0) || + abs(rect.bottom() - rect.top()) > 16000.0; + fRectVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType, + kDefault_GrSLPrecision, "rect"); + if (!highPrecision) { + fProxyRectHalfVar = + args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, + kDefault_GrSLPrecision, "proxyRectHalf"); + } + if (highPrecision) { + fProxyRectFloatVar = + args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType, + kDefault_GrSLPrecision, "proxyRectFloat"); + } + fProfileSizeVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, + kDefault_GrSLPrecision, "profileSize"); + fragBuilder->codeAppendf( + "bool highPrecision = %s;\n@if (highPrecision) {\n float2 translatedPos = " + "sk_FragCoord.xy - %s.xy;\n float width = %s.z - %s.x;\n float height = %s.w " + "- %s.y;\n float2 smallDims = float2(width - float(%s), height - float(%s));\n " + " float center = 2.0 * floor(float(float(%s / 2.0) + 0.25)) - 1.0;\n float2 wh " + "= smallDims - float2(center, center);\n half hcoord = " + "half((abs(translatedPos.x - 0.5 * width) - 0.5 * wh.x) / float(%s));\n half " + "hlookup = texture(%s, float2(float(hcoord), 0.5)).%s.w", + (highPrecision ? "true" : "false"), args.fUniformHandler->getUniformCStr(fRectVar), + args.fUniformHandler->getUniformCStr(fRectVar), + args.fUniformHandler->getUniformCStr(fRectVar), + args.fUniformHandler->getUniformCStr(fRectVar), + args.fUniformHandler->getUniformCStr(fRectVar), + args.fUniformHandler->getUniformCStr(fProfileSizeVar), + args.fUniformHandler->getUniformCStr(fProfileSizeVar), + args.fUniformHandler->getUniformCStr(fProfileSizeVar), + args.fUniformHandler->getUniformCStr(fProfileSizeVar), + fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(), + fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str()); + fragBuilder->codeAppendf( + ";\n half vcoord = half((abs(translatedPos.y - 0.5 * height) - 0.5 * wh.y) / " + "float(%s));\n half vlookup = texture(%s, float2(float(vcoord), 0.5)).%s.w;\n " + " %s = (%s * hlookup) * vlookup;\n} else {\n half2 translatedPos = " + "half2(sk_FragCoord.xy - %s.xy);\n half width = half(%s.z - %s.x);\n half " + "height = half(%s.w - %s.y);\n half2 smallDims = half2(width - %s, height - " + "%s);\n half center = half(2.0 * floor(float(float(%s / 2.0) + 0.25)) - 1.0);\n " + " half2 wh = smallDims - half2(float2(floa", + args.fUniformHandler->getUniformCStr(fProfileSizeVar), + fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(), + fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(), + args.fOutputColor, args.fInputColor ? args.fInputColor : "half4(1)", + args.fUniformHandler->getUniformCStr(fRectVar), + args.fUniformHandler->getUniformCStr(fRectVar), + args.fUniformHandler->getUniformCStr(fRectVar), + args.fUniformHandler->getUniformCStr(fRectVar), + args.fUniformHandler->getUniformCStr(fRectVar), + args.fUniformHandler->getUniformCStr(fProfileSizeVar), + args.fUniformHandler->getUniformCStr(fProfileSizeVar), + args.fUniformHandler->getUniformCStr(fProfileSizeVar)); + fragBuilder->codeAppendf( + "t(center), float(center)));\n half hcoord = " + "half((abs(float(float(translatedPos.x) - 0.5 * float(width))) - 0.5 * " + "float(wh.x)) / float(%s));\n half hlookup = texture(%s, float2(float(hcoord), " + "0.5)).%s.w;\n half vcoord = half((abs(float(float(translatedPos.y) - 0.5 * " + "float(height))) - 0.5 * float(wh.y)) / float(%s));\n half vlookup = " + "texture(%s, float2(float(vcoord), 0.5)).%s.w;\n %s = (%s * hlookup) * " + "vlookup;\n}\n", + args.fUniformHandler->getUniformCStr(fProfileSizeVar), + fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(), + fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(), + args.fUniformHandler->getUniformCStr(fProfileSizeVar), + fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(), + fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(), + args.fOutputColor, args.fInputColor ? args.fInputColor : "half4(1)"); + } + +private: + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& _proc) override { + const GrRectBlurEffect& _outer = _proc.cast(); + { + const SkRect rectValue = _outer.rect(); + pdman.set4fv(fRectVar, 1, (float*)&rectValue); + } + UniformHandle& rect = fRectVar; + (void)rect; + auto sigma = _outer.sigma(); + (void)sigma; + UniformHandle& blurProfile = fBlurProfileVar; + (void)blurProfile; + UniformHandle& proxyRectHalf = fProxyRectHalfVar; + (void)proxyRectHalf; + UniformHandle& proxyRectFloat = fProxyRectFloatVar; + (void)proxyRectFloat; + UniformHandle& profileSize = fProfileSizeVar; + (void)profileSize; + + pdman.set1f(profileSize, SkScalarCeilToScalar(6 * sigma)); + } + bool highPrecision; + UniformHandle fProxyRectHalfVar; + UniformHandle fProxyRectFloatVar; + UniformHandle fProfileSizeVar; + UniformHandle fRectVar; + UniformHandle fBlurProfileVar; +}; +GrGLSLFragmentProcessor* GrRectBlurEffect::onCreateGLSLInstance() const { + return new GrGLSLRectBlurEffect(); +} +void GrRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const {} +bool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const { + const GrRectBlurEffect& that = other.cast(); + (void)that; + if (fRect != that.fRect) return false; + if (fSigma != that.fSigma) return false; + if (fBlurProfile != that.fBlurProfile) return false; + return true; +} +GrRectBlurEffect::GrRectBlurEffect(const GrRectBlurEffect& src) + : INHERITED(kGrRectBlurEffect_ClassID, src.optimizationFlags()) + , fRect(src.fRect) + , fSigma(src.fSigma) + , fBlurProfile(src.fBlurProfile) { + this->addTextureSampler(&fBlurProfile); +} +std::unique_ptr GrRectBlurEffect::clone() const { + return std::unique_ptr(new GrRectBlurEffect(*this)); +} +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect); +#if GR_TEST_UTILS +std::unique_ptr GrRectBlurEffect::TestCreate(GrProcessorTestData* data) { + float sigma = data->fRandom->nextRangeF(3, 8); + float width = data->fRandom->nextRangeF(200, 300); + float height = data->fRandom->nextRangeF(200, 300); + return GrRectBlurEffect::Make(data->resourceProvider(), SkRect::MakeWH(width, height), sigma); +} +#endif +#endif diff --git a/src/gpu/effects/GrRectBlurEffect.fp b/src/gpu/effects/GrRectBlurEffect.fp new file mode 100644 index 0000000000..fe5d59ed0b --- /dev/null +++ b/src/gpu/effects/GrRectBlurEffect.fp @@ -0,0 +1,123 @@ +@header { + #include "GrResourceProvider.h" + #include "../effects/SkBlurMask.h" +} + +in uniform float4 rect; +in float sigma; +in uniform sampler2D blurProfile; + +// in OpenGL ES, mediump floats have a minimum range of 2^14. If we have coordinates bigger than +// that, the shader math will end up with infinities and result in the blur effect not working +// correctly. To avoid this, we switch into highp when the coordinates are too big. As 2^14 is the +// minimum range but the actual range can be bigger, we might end up switching to highp sooner than +// strictly necessary, but most devices that have a bigger range for mediump also have mediump being +// exactly the same as highp (e.g. all non-OpenGL ES devices), and thus incur no additional penalty +// for the switch. +layout(key) bool highPrecision = abs(rect.x) > 16000 || abs(rect.y) > 16000 || + abs(rect.z) > 16000 || abs(rect.w) > 16000 || + abs(rect.z - rect.x) > 16000 || abs(rect.w - rect.y) > 16000; + +layout(when=!highPrecision) uniform half4 proxyRectHalf; +layout(when=highPrecision) uniform float4 proxyRectFloat; +uniform half profileSize; + + +@class { + static sk_sp CreateBlurProfileTexture(GrResourceProvider* resourceProvider, + float sigma) { + unsigned int profileSize = SkScalarCeilToInt(6 * sigma); + + static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); + GrUniqueKey key; + GrUniqueKey::Builder builder(&key, kDomain, 1); + builder[0] = profileSize; + builder.finish(); + + sk_sp blurProfile(resourceProvider->findOrCreateProxyByUniqueKey( + key, kTopLeft_GrSurfaceOrigin)); + if (!blurProfile) { + GrSurfaceDesc texDesc; + texDesc.fOrigin = kTopLeft_GrSurfaceOrigin; + texDesc.fWidth = profileSize; + texDesc.fHeight = 1; + texDesc.fConfig = kAlpha_8_GrPixelConfig; + + std::unique_ptr profile(SkBlurMask::ComputeBlurProfile(sigma)); + + blurProfile = GrSurfaceProxy::MakeDeferred(resourceProvider, + texDesc, SkBudgeted::kYes, profile.get(), 0); + if (!blurProfile) { + return nullptr; + } + + SkASSERT(blurProfile->origin() == kTopLeft_GrSurfaceOrigin); + resourceProvider->assignUniqueKeyToProxy(key, blurProfile.get()); + } + + return blurProfile; + } +} + +@make { + static std::unique_ptr Make(GrResourceProvider* resourceProvider, + const SkRect& rect, float sigma) { + int doubleProfileSize = SkScalarCeilToInt(12*sigma); + + if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) { + // if the blur sigma is too large so the gaussian overlaps the whole + // rect in either direction, fall back to CPU path for now. + return nullptr; + } + + sk_sp blurProfile(CreateBlurProfileTexture(resourceProvider, sigma)); + if (!blurProfile) { + return nullptr; + } + + return std::unique_ptr(new GrRectBlurEffect(rect, sigma, + std::move(blurProfile))); + } +} + +void main() { + @if (highPrecision) { + float2 translatedPos = sk_FragCoord.xy - rect.xy; + float width = rect.z - rect.x; + float height = rect.w - rect.y; + float2 smallDims = float2(width - profileSize, height - profileSize); + float center = 2 * floor(profileSize / 2 + 0.25) - 1; + float2 wh = smallDims - float2(center, center); + half hcoord = ((abs(translatedPos.x - 0.5 * width) - 0.5 * wh.x)) / profileSize; + half hlookup = texture(blurProfile, float2(hcoord, 0.5)).a; + half vcoord = ((abs(translatedPos.y - 0.5 * height) - 0.5 * wh.y)) / profileSize; + half vlookup = texture(blurProfile, float2(vcoord, 0.5)).a; + sk_OutColor = sk_InColor * hlookup * vlookup; + } else { + half2 translatedPos = sk_FragCoord.xy - rect.xy; + half width = rect.z - rect.x; + half height = rect.w - rect.y; + half2 smallDims = half2(width - profileSize, height - profileSize); + half center = 2 * floor(profileSize / 2 + 0.25) - 1; + half2 wh = smallDims - float2(center, center); + half hcoord = ((abs(translatedPos.x - 0.5 * width) - 0.5 * wh.x)) / profileSize; + half hlookup = texture(blurProfile, float2(hcoord, 0.5)).a; + half vcoord = ((abs(translatedPos.y - 0.5 * height) - 0.5 * wh.y)) / profileSize; + half vlookup = texture(blurProfile, float2(vcoord, 0.5)).a; + sk_OutColor = sk_InColor * hlookup * vlookup; + } +} + +@setData(pdman) { + pdman.set1f(profileSize, SkScalarCeilToScalar(6 * sigma)); +} + +@optimizationFlags { kCompatibleWithCoverageAsAlpha_OptimizationFlag } + +@test(data) { + float sigma = data->fRandom->nextRangeF(3,8); + float width = data->fRandom->nextRangeF(200,300); + float height = data->fRandom->nextRangeF(200,300); + return GrRectBlurEffect::Make(data->resourceProvider(), + SkRect::MakeWH(width, height), sigma); +} diff --git a/src/gpu/effects/GrRectBlurEffect.h b/src/gpu/effects/GrRectBlurEffect.h new file mode 100644 index 0000000000..7a8bc2c005 --- /dev/null +++ b/src/gpu/effects/GrRectBlurEffect.h @@ -0,0 +1,100 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* + * This file was autogenerated from GrRectBlurEffect.fp; do not modify. + */ +#ifndef GrRectBlurEffect_DEFINED +#define GrRectBlurEffect_DEFINED +#include "SkTypes.h" +#if SK_SUPPORT_GPU + +#include "GrResourceProvider.h" +#include "../effects/SkBlurMask.h" +#include "GrFragmentProcessor.h" +#include "GrCoordTransform.h" +#include "GrColorSpaceXform.h" +class GrRectBlurEffect : public GrFragmentProcessor { +public: + static sk_sp CreateBlurProfileTexture(GrResourceProvider* resourceProvider, + float sigma) { + unsigned int profileSize = SkScalarCeilToInt(6 * sigma); + + static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); + GrUniqueKey key; + GrUniqueKey::Builder builder(&key, kDomain, 1); + builder[0] = profileSize; + builder.finish(); + + sk_sp blurProfile( + resourceProvider->findOrCreateProxyByUniqueKey(key, kTopLeft_GrSurfaceOrigin)); + if (!blurProfile) { + GrSurfaceDesc texDesc; + texDesc.fOrigin = kTopLeft_GrSurfaceOrigin; + texDesc.fWidth = profileSize; + texDesc.fHeight = 1; + texDesc.fConfig = kAlpha_8_GrPixelConfig; + + std::unique_ptr profile(SkBlurMask::ComputeBlurProfile(sigma)); + + blurProfile = GrSurfaceProxy::MakeDeferred(resourceProvider, texDesc, SkBudgeted::kYes, + profile.get(), 0); + if (!blurProfile) { + return nullptr; + } + + SkASSERT(blurProfile->origin() == kTopLeft_GrSurfaceOrigin); + resourceProvider->assignUniqueKeyToProxy(key, blurProfile.get()); + } + + return blurProfile; + } + SkRect rect() const { return fRect; } + float sigma() const { return fSigma; } + + static std::unique_ptr Make(GrResourceProvider* resourceProvider, + const SkRect& rect, float sigma) { + int doubleProfileSize = SkScalarCeilToInt(12 * sigma); + + if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) { + // if the blur sigma is too large so the gaussian overlaps the whole + // rect in either direction, fall back to CPU path for now. + return nullptr; + } + + sk_sp blurProfile(CreateBlurProfileTexture(resourceProvider, sigma)); + if (!blurProfile) { + return nullptr; + } + + return std::unique_ptr( + new GrRectBlurEffect(rect, sigma, std::move(blurProfile))); + } + GrRectBlurEffect(const GrRectBlurEffect& src); + std::unique_ptr clone() const override; + const char* name() const override { return "RectBlurEffect"; } + +private: + GrRectBlurEffect(SkRect rect, float sigma, sk_sp blurProfile) + : INHERITED(kGrRectBlurEffect_ClassID, + (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fRect(rect) + , fSigma(sigma) + , fBlurProfile(std::move(blurProfile)) { + this->addTextureSampler(&fBlurProfile); + } + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; + bool onIsEqual(const GrFragmentProcessor&) const override; + GR_DECLARE_FRAGMENT_PROCESSOR_TEST + SkRect fRect; + float fSigma; + TextureSampler fBlurProfile; + typedef GrFragmentProcessor INHERITED; +}; +#endif +#endif diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp index 2c44ce4111..c3634f5739 100644 --- a/src/gpu/effects/GrSimpleTextureEffect.cpp +++ b/src/gpu/effects/GrSimpleTextureEffect.cpp @@ -23,6 +23,10 @@ public: GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrSimpleTextureEffect& _outer = args.fFp.cast(); (void)_outer; + auto colorXform = _outer.colorXform(); + (void)colorXform; + auto matrix = _outer.matrix(); + (void)matrix; fColorSpaceHelper.emitCode(args.fUniformHandler, _outer.colorXform().get()); SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); fragBuilder->codeAppendf( diff --git a/src/sksl/SkSLCPP.h b/src/sksl/SkSLCPP.h index 808e83290f..d67990820b 100644 --- a/src/sksl/SkSLCPP.h +++ b/src/sksl/SkSLCPP.h @@ -10,8 +10,11 @@ // functions used by CPP programs created by skslc +#include #include "SkPoint.h" +using std::abs; + // macros to make sk_Caps. work from C++ code #define sk_Caps (*args.fShaderCaps) diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp index a7008400ce..0b2ef78016 100644 --- a/src/sksl/SkSLCPPCodeGenerator.cpp +++ b/src/sksl/SkSLCPPCodeGenerator.cpp @@ -148,10 +148,15 @@ void CPPCodeGenerator::writeRuntimeValue(const Type& type, const String& cppCode this->write(type.name() + "(%f, %f)"); fFormatArgs.push_back(cppCode + ".fX"); fFormatArgs.push_back(cppCode + ".fY"); + } else if (type == *fContext.fFloat4_Type || type == *fContext.fHalf4_Type) { + this->write(type.name() + "(%f, %f, %f, %f)"); + fFormatArgs.push_back(cppCode + ".left()"); + fFormatArgs.push_back(cppCode + ".top()"); + fFormatArgs.push_back(cppCode + ".right()"); + fFormatArgs.push_back(cppCode + ".bottom()"); } else { - this->write(type.name()); - this->write("\n"); - ABORT("unsupported runtime value type\n"); + printf("unsupported runtime value type '%s'\n", String(type.fName).c_str()); + ASSERT(false); } } @@ -180,7 +185,26 @@ void CPPCodeGenerator::writeIntLiteral(const IntLiteral& i) { this->write(to_string((int32_t) i.fValue)); } +void CPPCodeGenerator::writeSwizzle(const Swizzle& swizzle) { + if (fCPPMode) { + ASSERT(swizzle.fComponents.size() == 1); // no support for multiple swizzle components yet + this->writeExpression(*swizzle.fBase, kPostfix_Precedence); + switch (swizzle.fComponents[0]) { + case 0: this->write(".left()"); break; + case 1: this->write(".top()"); break; + case 2: this->write(".right()"); break; + case 3: this->write(".bottom()"); break; + } + } else { + INHERITED::writeSwizzle(swizzle); + } +} + void CPPCodeGenerator::writeVariableReference(const VariableReference& ref) { + if (fCPPMode) { + this->write(ref.fVariable.fName); + return; + } switch (ref.fVariable.fModifiers.fLayout.fBuiltin) { case SK_INCOLOR_BUILTIN: this->write("%s"); @@ -434,15 +458,22 @@ void CPPCodeGenerator::writePrivateVarValues() { for (const auto& raw : decls->fVars) { VarDeclaration& decl = (VarDeclaration&) *raw; if (is_private(*decl.fVar) && decl.fValue) { - this->writef("%s = %s;\n", - String(decl.fVar->fName).c_str(), - decl.fValue->description().c_str()); + this->writef("%s = ", String(decl.fVar->fName).c_str()); + fCPPMode = true; + this->writeExpression(*decl.fValue, kAssignment_Precedence); + fCPPMode = false; + this->write(";\n"); } } } } } +static bool is_accessible(const Variable& var) { + return Type::kSampler_Kind != var.fType.kind() && + Type::kOther_Kind != var.fType.kind(); +} + void CPPCodeGenerator::writeCodeAppend(const String& code) { // codeAppendf can only handle appending 1024 bytes at a time, so we need to break the string // into chunks. Unfortunately we can't tell exactly how long the string is going to end up, @@ -484,6 +515,22 @@ bool CPPCodeGenerator::writeEmitCode(std::vector& uniforms) { this->writef(" const %s& _outer = args.fFp.cast<%s>();\n" " (void) _outer;\n", fFullName.c_str(), fFullName.c_str()); + for (const auto& p : fProgram.fElements) { + if (ProgramElement::kVar_Kind == p->fKind) { + const VarDeclarations* decls = (const VarDeclarations*) p.get(); + for (const auto& raw : decls->fVars) { + VarDeclaration& decl = (VarDeclaration&) *raw; + String nameString(decl.fVar->fName); + const char* name = nameString.c_str(); + if (SectionAndParameterHelper::IsParameter(*decl.fVar) && + is_accessible(*decl.fVar)) { + this->writef(" auto %s = _outer.%s();\n" + " (void) %s;\n", + name, name, name); + } + } + } + } this->writePrivateVarValues(); for (const auto u : uniforms) { this->addUniform(*u); diff --git a/src/sksl/SkSLCPPCodeGenerator.h b/src/sksl/SkSLCPPCodeGenerator.h index ea4d030826..a93b885a5c 100644 --- a/src/sksl/SkSLCPPCodeGenerator.h +++ b/src/sksl/SkSLCPPCodeGenerator.h @@ -41,6 +41,8 @@ private: void writeIntLiteral(const IntLiteral& i) override; + void writeSwizzle(const Swizzle& swizzle) override; + void writeVariableReference(const VariableReference& ref) override; String getSamplerHandle(const Variable& var); @@ -87,6 +89,8 @@ private: std::vector fFormatArgs; std::set fWrittenTransformedCoords; bool fNeedColorSpaceHelper = false; + // if true, we are writing a C++ expression instead of a GLSL expression + bool fCPPMode = false; typedef GLSLCodeGenerator INHERITED; }; diff --git a/src/sksl/SkSLGLSLCodeGenerator.h b/src/sksl/SkSLGLSLCodeGenerator.h index 7c736b35a1..e9a63ac48f 100644 --- a/src/sksl/SkSLGLSLCodeGenerator.h +++ b/src/sksl/SkSLGLSLCodeGenerator.h @@ -142,7 +142,7 @@ protected: void writeFieldAccess(const FieldAccess& f); - void writeSwizzle(const Swizzle& swizzle); + virtual void writeSwizzle(const Swizzle& swizzle); static Precedence GetBinaryPrecedence(Token::Kind op); diff --git a/src/sksl/ir/SkSLLayout.h b/src/sksl/ir/SkSLLayout.h index 8bf0472a95..dc676280d6 100644 --- a/src/sksl/ir/SkSLLayout.h +++ b/src/sksl/ir/SkSLLayout.h @@ -232,18 +232,6 @@ struct Layout { result += separator + "when = " + fWhen; separator = ", "; } - switch (fKey) { - case kNo_Key: - break; - case kKey_Key: - result += separator + "key"; - separator = ", "; - break; - case kIdentity_Key: - result += separator + "key=identity"; - separator = ", "; - break; - } if (result.size() > 0) { result = "layout (" + result + ")"; }