From: Ethan Nicholas Date: Tue, 2 May 2017 19:37:57 +0000 (-0400) Subject: eliminated GrGLSLExpr X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~36^2~516 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=93f20f5629e52eed732d2b9d6dbbb351cc30b2cd;p=platform%2Fupstream%2FlibSkiaSharp.git eliminated GrGLSLExpr Now that skslc performs all of the optimizations (and then some) that GrGLSLExpr is responsible for, it's just extra work for no benefit. Bug: skia: Change-Id: I40b0629e00a33873ed9fc6c0a9f41d8350221f9a Reviewed-on: https://skia-review.googlesource.com/14560 Commit-Queue: Ethan Nicholas Reviewed-by: Brian Salomon --- diff --git a/gn/gpu.gni b/gn/gpu.gni index 2c26062..b2f8555 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -38,7 +38,6 @@ skia_gpu_sources = [ # Private includes "$_include/private/GrAuditTrail.h", "$_include/private/GrGLSL.h", - "$_include/private/GrGLSL_impl.h", "$_include/private/GrInstancedPipelineInfo.h", "$_include/private/GrSingleOwner.h", "$_include/private/GrRenderTargetProxy.h", diff --git a/include/private/GrGLSL.h b/include/private/GrGLSL.h index 66f7be8..26954b4 100644 --- a/include/private/GrGLSL.h +++ b/include/private/GrGLSL.h @@ -138,245 +138,4 @@ static inline const char* GrGLSLTypeString(GrSLType t) { return ""; // suppress warning } -/** A generic base-class representing a GLSL expression. - * The instance can be a variable name, expression or vecN(0) or vecN(1). Does simple constant - * folding with help of 1 and 0. - * - * Clients should not use this class, rather the specific instantiations defined - * later, for example GrGLSLExpr4. - */ -template -class GrGLSLExpr { -public: - bool isOnes() const { return kOnes_ExprType == fType; } - bool isZeros() const { return kZeros_ExprType == fType; } - - const char* c_str() const { - if (kZeros_ExprType == fType) { - return Self::ZerosStr(); - } else if (kOnes_ExprType == fType) { - return Self::OnesStr(); - } - SkASSERT(!fExpr.isEmpty()); // Empty expressions should not be used. - return fExpr.c_str(); - } - - bool isValid() const { - return kFullExpr_ExprType != fType || !fExpr.isEmpty(); - } - -protected: - /** Constructs an invalid expression. - * Useful only as a return value from functions that never actually return - * this and instances that will be assigned to later. */ - GrGLSLExpr() - : fType(kFullExpr_ExprType) { - // The only constructor that is allowed to build an empty expression. - SkASSERT(!this->isValid()); - } - - /** Constructs an expression with all components as value v */ - explicit GrGLSLExpr(int v) { - if (v == 0) { - fType = kZeros_ExprType; - } else if (v == 1) { - fType = kOnes_ExprType; - } else { - fType = kFullExpr_ExprType; - fExpr.appendf(Self::CastIntStr(), v); - } - } - - /** Constructs an expression from a string. - * Argument expr is a simple expression or a parenthesized expression. */ - // TODO: make explicit once effects input Exprs. - GrGLSLExpr(const char expr[]) { - if (nullptr == expr) { // TODO: remove this once effects input Exprs. - fType = kOnes_ExprType; - } else { - fType = kFullExpr_ExprType; - fExpr = expr; - } - SkASSERT(this->isValid()); - } - - /** Constructs an expression from a string. - * Argument expr is a simple expression or a parenthesized expression. */ - // TODO: make explicit once effects input Exprs. - GrGLSLExpr(const SkString& expr) { - if (expr.isEmpty()) { // TODO: remove this once effects input Exprs. - fType = kOnes_ExprType; - } else { - fType = kFullExpr_ExprType; - fExpr = expr; - } - SkASSERT(this->isValid()); - } - - /** Constructs an expression from a string with one substitution. */ - GrGLSLExpr(const char format[], const char in0[]) - : fType(kFullExpr_ExprType) { - fExpr.appendf(format, in0); - } - - /** Constructs an expression from a string with two substitutions. */ - GrGLSLExpr(const char format[], const char in0[], const char in1[]) - : fType(kFullExpr_ExprType) { - fExpr.appendf(format, in0, in1); - } - - /** Returns expression casted to another type. - * Generic implementation that is called for non-trivial cases of casts. */ - template - static Self VectorCastImpl(const T& other); - - /** Returns a GLSL multiplication: component-wise or component-by-scalar. - * The multiplication will be component-wise or multiply each component by a scalar. - * - * The returned expression will compute the value of: - * vecN(in0.x * in1.x, ...) if dim(T0) == dim(T1) (component-wise) - * vecN(in0.x * in1, ...) if dim(T1) == 1 (vector by scalar) - * vecN(in0 * in1.x, ...) if dim(T0) == 1 (scalar by vector) - */ - template - static Self Mul(T0 in0, T1 in1); - - /** Returns a GLSL addition: component-wise or add a scalar to each component. - * Return value computes: - * vecN(in0.x + in1.x, ...) or vecN(in0.x + in1, ...) or vecN(in0 + in1.x, ...). - */ - template - static Self Add(T0 in0, T1 in1); - - /** Returns a GLSL subtraction: component-wise or subtract compoments by a scalar. - * Return value computes - * vecN(in0.x - in1.x, ...) or vecN(in0.x - in1, ...) or vecN(in0 - in1.x, ...). - */ - template - static Self Sub(T0 in0, T1 in1); - - /** Returns expression that accesses component(s) of the expression. - * format should be the form "%s.x" where 'x' is the component(s) to access. - * Caller is responsible for making sure the amount of components in the - * format string is equal to dim(T). - */ - template - T extractComponents(const char format[]) const; - -private: - enum ExprType { - kZeros_ExprType, - kOnes_ExprType, - kFullExpr_ExprType, - }; - ExprType fType; - SkString fExpr; -}; - -class GrGLSLExpr1; -class GrGLSLExpr4; - -/** Class representing a float GLSL expression. */ -class GrGLSLExpr1 : public GrGLSLExpr { -public: - GrGLSLExpr1() - : INHERITED() { - } - explicit GrGLSLExpr1(int v) - : INHERITED(v) { - } - GrGLSLExpr1(const char* expr) - : INHERITED(expr) { - } - GrGLSLExpr1(const SkString& expr) - : INHERITED(expr) { - } - - static GrGLSLExpr1 VectorCast(const GrGLSLExpr1& expr); - -private: - GrGLSLExpr1(const char format[], const char in0[]) - : INHERITED(format, in0) { - } - GrGLSLExpr1(const char format[], const char in0[], const char in1[]) - : INHERITED(format, in0, in1) { - } - - static const char* ZerosStr(); - static const char* OnesStr(); - static const char* CastStr(); - static const char* CastIntStr(); - - friend GrGLSLExpr1 operator*(const GrGLSLExpr1& in0, const GrGLSLExpr1&in1); - friend GrGLSLExpr1 operator+(const GrGLSLExpr1& in0, const GrGLSLExpr1&in1); - friend GrGLSLExpr1 operator-(const GrGLSLExpr1& in0, const GrGLSLExpr1&in1); - - friend class GrGLSLExpr; - friend class GrGLSLExpr; - - typedef GrGLSLExpr INHERITED; -}; - -/** Class representing a float vector (vec4) GLSL expression. */ -class GrGLSLExpr4 : public GrGLSLExpr { -public: - GrGLSLExpr4() - : INHERITED() { - } - explicit GrGLSLExpr4(int v) - : INHERITED(v) { - } - GrGLSLExpr4(const char* expr) - : INHERITED(expr) { - } - GrGLSLExpr4(const SkString& expr) - : INHERITED(expr) { - } - - typedef GrGLSLExpr1 AExpr; - AExpr a() const; - - /** GLSL vec4 cast / constructor, eg vec4(floatv) -> vec4(floatv, floatv, floatv, floatv) */ - static GrGLSLExpr4 VectorCast(const GrGLSLExpr1& expr); - static GrGLSLExpr4 VectorCast(const GrGLSLExpr4& expr); - -private: - GrGLSLExpr4(const char format[], const char in0[]) - : INHERITED(format, in0) { - } - GrGLSLExpr4(const char format[], const char in0[], const char in1[]) - : INHERITED(format, in0, in1) { - } - - static const char* ZerosStr(); - static const char* OnesStr(); - static const char* CastStr(); - static const char* CastIntStr(); - - // The vector-by-scalar and scalar-by-vector binary operations. - friend GrGLSLExpr4 operator*(const GrGLSLExpr1& in0, const GrGLSLExpr4&in1); - friend GrGLSLExpr4 operator+(const GrGLSLExpr1& in0, const GrGLSLExpr4&in1); - friend GrGLSLExpr4 operator-(const GrGLSLExpr1& in0, const GrGLSLExpr4&in1); - friend GrGLSLExpr4 operator*(const GrGLSLExpr4& in0, const GrGLSLExpr1&in1); - friend GrGLSLExpr4 operator+(const GrGLSLExpr4& in0, const GrGLSLExpr1&in1); - friend GrGLSLExpr4 operator-(const GrGLSLExpr4& in0, const GrGLSLExpr1&in1); - - // The vector-by-vector, i.e. component-wise, binary operations. - friend GrGLSLExpr4 operator*(const GrGLSLExpr4& in0, const GrGLSLExpr4&in1); - friend GrGLSLExpr4 operator+(const GrGLSLExpr4& in0, const GrGLSLExpr4&in1); - friend GrGLSLExpr4 operator-(const GrGLSLExpr4& in0, const GrGLSLExpr4&in1); - - friend class GrGLSLExpr; - - typedef GrGLSLExpr INHERITED; -}; - -/** - * Does an inplace mul, *=, of vec4VarName by mulFactor. - * A semicolon is added after the assignment. - */ -void GrGLSLMulVarBy4f(SkString* outAppend, const char* vec4VarName, const GrGLSLExpr4& mulFactor); - -#include "GrGLSL_impl.h" - #endif diff --git a/include/private/GrGLSL_impl.h b/include/private/GrGLSL_impl.h deleted file mode 100644 index bdd69cc..0000000 --- a/include/private/GrGLSL_impl.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrGLSL_impl_DEFINED -#define GrGLSL_impl_DEFINED - -template -template -inline Self GrGLSLExpr::VectorCastImpl(const T& expr) { - if (expr.isZeros()) { - return Self(0); - } - if (expr.isOnes()) { - return Self(1); - } - return Self(Self::CastStr(), expr.c_str()); -} - -template -template -inline Self GrGLSLExpr::Mul(T0 in0, T1 in1) { - if (in0.isZeros() || in1.isZeros()) { - return Self(0); - } - if (in0.isOnes()) { - return Self::VectorCast(in1); - } - if (in1.isOnes()) { - return Self::VectorCast(in0); - } - return Self("(%s * %s)", in0.c_str(), in1.c_str()); -} - -template -template -inline Self GrGLSLExpr::Add(T0 in0, T1 in1) { - if (in1.isZeros()) { - return Self::VectorCast(in0); - } - if (in0.isZeros()) { - return Self::VectorCast(in1); - } - if (in0.isOnes() && in1.isOnes()) { - return Self(2); - } - return Self("(%s + %s)", in0.c_str(), in1.c_str()); -} - -template -template -inline Self GrGLSLExpr::Sub(T0 in0, T1 in1) { - if (in1.isZeros()) { - return Self::VectorCast(in0); - } - if (in1.isOnes()) { - if (in0.isOnes()) { - return Self(0); - } - } - - return Self("(%s - %s)", in0.c_str(), in1.c_str()); -} - -template -template -T GrGLSLExpr::extractComponents(const char format[]) const { - if (this->isZeros()) { - return T(0); - } - if (this->isOnes()) { - return T(1); - } - return T(format, this->c_str()); -} - -inline GrGLSLExpr1 GrGLSLExpr1::VectorCast(const GrGLSLExpr1& expr) { - return expr; -} - -inline const char* GrGLSLExpr1::ZerosStr() { - return "0"; -} - -inline const char* GrGLSLExpr1::OnesStr() { - return "1.0"; -} - -// GrGLSLExpr1::CastStr() is unimplemented because using them is likely an -// error. This is now caught compile-time. - -inline const char* GrGLSLExpr1::CastIntStr() { - return "%d"; -} - -inline GrGLSLExpr1 operator*(const GrGLSLExpr1& in0, const GrGLSLExpr1& in1) { - return GrGLSLExpr1::Mul(in0, in1); -} - -inline GrGLSLExpr1 operator+(const GrGLSLExpr1& in0, const GrGLSLExpr1& in1) { - return GrGLSLExpr1::Add(in0, in1); -} - -inline GrGLSLExpr1 operator-(const GrGLSLExpr1& in0, const GrGLSLExpr1& in1) { - return GrGLSLExpr1::Sub(in0, in1); -} - -inline const char* GrGLSLExpr4::ZerosStr() { - return "vec4(0)"; -} - -inline const char* GrGLSLExpr4::OnesStr() { - return "vec4(1)"; -} - -inline const char* GrGLSLExpr4::CastStr() { - return "vec4(%s)"; -} - -inline const char* GrGLSLExpr4::CastIntStr() { - return "vec4(%d)"; -} - -inline GrGLSLExpr4 GrGLSLExpr4::VectorCast(const GrGLSLExpr1& expr) { - return INHERITED::VectorCastImpl(expr); -} - -inline GrGLSLExpr4 GrGLSLExpr4::VectorCast(const GrGLSLExpr4& expr) { - return expr; -} - -inline GrGLSLExpr4::AExpr GrGLSLExpr4::a() const { - return this->extractComponents("%s.a"); -} - -inline GrGLSLExpr4 operator*(const GrGLSLExpr1& in0, const GrGLSLExpr4& in1) { - return GrGLSLExpr4::Mul(in0, in1); -} - -inline GrGLSLExpr4 operator+(const GrGLSLExpr1& in0, const GrGLSLExpr4& in1) { - return GrGLSLExpr4::Add(in0, in1); -} - -inline GrGLSLExpr4 operator-(const GrGLSLExpr1& in0, const GrGLSLExpr4& in1) { - return GrGLSLExpr4::Sub(in0, in1); -} - -inline GrGLSLExpr4 operator*(const GrGLSLExpr4& in0, const GrGLSLExpr1& in1) { - return GrGLSLExpr4::Mul(in0, in1); -} - -inline GrGLSLExpr4 operator+(const GrGLSLExpr4& in0, const GrGLSLExpr1& in1) { - return GrGLSLExpr4::Add(in0, in1); -} - -inline GrGLSLExpr4 operator-(const GrGLSLExpr4& in0, const GrGLSLExpr1& in1) { - return GrGLSLExpr4::Sub(in0, in1); -} - -inline GrGLSLExpr4 operator*(const GrGLSLExpr4& in0, const GrGLSLExpr4& in1) { - return GrGLSLExpr4::Mul(in0, in1); -} - -inline GrGLSLExpr4 operator+(const GrGLSLExpr4& in0, const GrGLSLExpr4& in1) { - return GrGLSLExpr4::Add(in0, in1); -} - -inline GrGLSLExpr4 operator-(const GrGLSLExpr4& in0, const GrGLSLExpr4& in1) { - return GrGLSLExpr4::Sub(in0, in1); -} - -#endif diff --git a/src/core/SkLightingShader.cpp b/src/core/SkLightingShader.cpp index 600134d..0442913 100644 --- a/src/core/SkLightingShader.cpp +++ b/src/core/SkLightingShader.cpp @@ -168,7 +168,7 @@ public: fragBuilder->codeAppendf("vec4 diffuseColor = %s;", args.fInputColor); SkString dstNormalName("dstNormal"); - this->emitChild(0, nullptr, &dstNormalName, args); + this->emitChild(0, &dstNormalName, args); fragBuilder->codeAppendf("vec3 normal = %s.xyz;", dstNormalName.c_str()); diff --git a/src/core/SkNormalMapSource.cpp b/src/core/SkNormalMapSource.cpp index 65c5c89..fb133da 100644 --- a/src/core/SkNormalMapSource.cpp +++ b/src/core/SkNormalMapSource.cpp @@ -47,7 +47,7 @@ public: kDefault_GrSLPrecision, "Xform", &xformUniName); SkString dstNormalColorName("dstNormalColor"); - this->emitChild(0, nullptr, &dstNormalColorName, args); + this->emitChild(0, &dstNormalColorName, args); fragBuilder->codeAppendf("vec3 normal = normalize(%s.rgb - vec3(0.5));", dstNormalColorName.c_str()); diff --git a/src/core/SkRadialShadowMapShader.cpp b/src/core/SkRadialShadowMapShader.cpp new file mode 100644 index 0000000..d8a4de5 --- /dev/null +++ b/src/core/SkRadialShadowMapShader.cpp @@ -0,0 +1,428 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkLights.h" +#include "SkPoint3.h" +#include "SkRadialShadowMapShader.h" + +//////////////////////////////////////////////////////////////////////////// +#ifdef SK_EXPERIMENTAL_SHADOWING + + +/** \class SkRadialShadowMapShaderImpl + This subclass of shader applies shadowing radially around a light +*/ +class SkRadialShadowMapShaderImpl : public SkShader { +public: + /** Create a new shadowing shader that shadows radially around a light + */ + SkRadialShadowMapShaderImpl(sk_sp occluderShader, + sk_sp lights, + int diffuseWidth, int diffuseHeight) + : fOccluderShader(std::move(occluderShader)) + , fLight(std::move(lights)) + , fWidth(diffuseWidth) + , fHeight(diffuseHeight) { } + + bool isOpaque() const override; + +#if SK_SUPPORT_GPU + sk_sp asFragmentProcessor(const AsFPArgs&) const override; +#endif + + class ShadowMapRadialShaderContext : public SkShader::Context { + public: + // The context takes ownership of the states. It will call their destructors + // but will NOT free the memory. + ShadowMapRadialShaderContext(const SkRadialShadowMapShaderImpl&, const ContextRec&, + SkShader::Context* occluderContext, + void* heapAllocated); + + ~ShadowMapRadialShaderContext() override; + + void shadeSpan(int x, int y, SkPMColor[], int count) override; + + uint32_t getFlags() const override { return fFlags; } + + private: + SkShader::Context* fOccluderContext; + uint32_t fFlags; + + void* fHeapAllocated; + + typedef SkShader::Context INHERITED; + }; + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkRadialShadowMapShaderImpl) + +protected: + void flatten(SkWriteBuffer&) const override; + size_t onContextSize(const ContextRec&) const override; + Context* onCreateContext(const ContextRec&, void*) const override; + +private: + sk_sp fOccluderShader; + sk_sp fLight; + + int fWidth; + int fHeight; + + friend class SkRadialShadowMapShader; + + typedef SkShader INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////// + +#if SK_SUPPORT_GPU + +#include "GrContext.h" +#include "GrCoordTransform.h" +#include "GrFragmentProcessor.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "SkGr.h" +#include "SkImage_Base.h" +#include "GrInvariantOutput.h" +#include "SkSpecialImage.h" + +class RadialShadowMapFP : public GrFragmentProcessor { +public: + RadialShadowMapFP(sk_sp occluder, + sk_sp light, + int diffuseWidth, int diffuseHeight, + GrContext* context) { + fLightPos = light->light(0).pos(); + + fWidth = diffuseWidth; + fHeight = diffuseHeight; + + this->registerChildProcessor(std::move(occluder)); + this->initClassID(); + } + + class GLSLRadialShadowMapFP : public GrGLSLFragmentProcessor { + public: + GLSLRadialShadowMapFP() { } + + void emitCode(EmitArgs& args) override { + + GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + + const char* lightPosUniName = nullptr; + + fLightPosUni = uniformHandler->addUniform(kFragment_GrShaderFlag, + kVec3f_GrSLType, + kDefault_GrSLPrecision, + "lightPos", + &lightPosUniName); + + const char* widthUniName = nullptr; + const char* heightUniName = nullptr; + + fWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag, + kInt_GrSLType, + kDefault_GrSLPrecision, + "width", &widthUniName); + fHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag, + kInt_GrSLType, + kDefault_GrSLPrecision, + "height", &heightUniName); + + + SkString occluder("occluder"); + this->emitChild(0, &occluder, args); + + // Modify the input texture coordinates to index into our 1D output + fragBuilder->codeAppend("float distHere;"); + + // we use a max shadow distance of 2 times the max of width/height + fragBuilder->codeAppend("float closestDistHere = 2;"); + fragBuilder->codeAppend("vec2 coords = vMatrixCoord_0_0_Stage0;"); + fragBuilder->codeAppend("coords.y = 0;"); + fragBuilder->codeAppend("vec2 destCoords = vec2(0,0);"); + fragBuilder->codeAppendf("float step = 1.0 / %s;", heightUniName); + + // assume that we are at 0, 0 light pos + // TODO use correct light positions + + // this goes through each depth value in the final output buffer, + // basically raycasting outwards, and finding the first collision. + // we also increment coords.y to 2 instead 1 so our shadows stretch the whole screen. + fragBuilder->codeAppendf("for (coords.y = 0; coords.y <= 2; coords.y += step) {"); + + fragBuilder->codeAppend("float theta = (coords.x * 2.0 - 1.0) * 3.1415;"); + fragBuilder->codeAppend("float r = coords.y;"); + fragBuilder->codeAppend("destCoords = " + "vec2(r * cos(theta), - r * sin(theta)) /2.0 + 0.5;"); + fragBuilder->codeAppendf("vec2 lightOffset = (vec2(%s)/vec2(%s,%s) - 0.5)" + "* vec2(1.0, 1.0);", + lightPosUniName, widthUniName, heightUniName); + + fragBuilder->codeAppend("distHere = texture(uTextureSampler0_Stage1," + "destCoords + lightOffset).b;"); + fragBuilder->codeAppend("if (distHere > 0.0) {" + "closestDistHere = coords.y;" + "break;}"); + fragBuilder->codeAppend("}"); + + fragBuilder->codeAppendf("%s = vec4(vec3(closestDistHere / 2.0),1);", args.fOutputColor); + } + + static void GenKey(const GrProcessor& proc, const GrShaderCaps&, + GrProcessorKeyBuilder* b) { + b->add32(0); // nothing to add here + } + + protected: + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& proc) override { + const RadialShadowMapFP &radialShadowMapFP = proc.cast(); + + const SkVector3& lightPos = radialShadowMapFP.lightPos(); + if (lightPos != fLightPos) { + pdman.set3fv(fLightPosUni, 1, &lightPos.fX); + fLightPos = lightPos; + } + + int width = radialShadowMapFP.width(); + if (width != fWidth) { + pdman.set1i(fWidthUni, width); + fWidth = width; + } + int height = radialShadowMapFP.height(); + if (height != fHeight) { + pdman.set1i(fHeightUni, height); + fHeight = height; + } + } + + private: + SkVector3 fLightPos; + GrGLSLProgramDataManager::UniformHandle fLightPosUni; + + int fWidth; + GrGLSLProgramDataManager::UniformHandle fWidthUni; + int fHeight; + GrGLSLProgramDataManager::UniformHandle fHeightUni; + }; + + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { + GLSLRadialShadowMapFP::GenKey(*this, caps, b); + } + + const char* name() const override { return "RadialShadowMapFP"; } + + const SkVector3& lightPos() const { + return fLightPos; + } + + int width() const { return fWidth; } + int height() const { return fHeight; } + +private: + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { + return new GLSLRadialShadowMapFP; + } + + bool onIsEqual(const GrFragmentProcessor& proc) const override { + const RadialShadowMapFP& radialShadowMapFP = proc.cast(); + + if (fWidth != radialShadowMapFP.fWidth || fHeight != radialShadowMapFP.fHeight) { + return false; + } + + if (fLightPos != radialShadowMapFP.fLightPos) { + return false; + } + + return true; + } + + SkVector3 fLightPos; + + int fHeight; + int fWidth; +}; + +//////////////////////////////////////////////////////////////////////////// + +sk_sp SkRadialShadowMapShaderImpl::asFragmentProcessor + (const AsFPArgs& fpargs) const { + + sk_sp occluderFP = fOccluderShader->asFragmentProcessor(fpargs); + + sk_sp shadowFP = sk_make_sp(std::move(occluderFP), + fLight, fWidth, fHeight, + fpargs.fContext); + return shadowFP; +} + +#endif + +//////////////////////////////////////////////////////////////////////////// + +bool SkRadialShadowMapShaderImpl::isOpaque() const { + return fOccluderShader->isOpaque(); +} + +SkRadialShadowMapShaderImpl::ShadowMapRadialShaderContext::ShadowMapRadialShaderContext( + const SkRadialShadowMapShaderImpl& shader, const ContextRec& rec, + SkShader::Context* occluderContext, + void* heapAllocated) + : INHERITED(shader, rec) + , fOccluderContext(occluderContext) + , fHeapAllocated(heapAllocated) { + bool isOpaque = shader.isOpaque(); + + // update fFlags + uint32_t flags = 0; + if (isOpaque && (255 == this->getPaintAlpha())) { + flags |= kOpaqueAlpha_Flag; + } + + fFlags = flags; +} + +SkRadialShadowMapShaderImpl::ShadowMapRadialShaderContext::~ShadowMapRadialShaderContext() { + // The dependencies have been created outside of the context on memory that was allocated by + // the onCreateContext() method. Call the destructors and free the memory. + fOccluderContext->~Context(); + + sk_free(fHeapAllocated); +} + +static inline SkPMColor convert(SkColor3f color, U8CPU a) { + if (color.fX <= 0.0f) { + color.fX = 0.0f; + } else if (color.fX >= 255.0f) { + color.fX = 255.0f; + } + + if (color.fY <= 0.0f) { + color.fY = 0.0f; + } else if (color.fY >= 255.0f) { + color.fY = 255.0f; + } + + if (color.fZ <= 0.0f) { + color.fZ = 0.0f; + } else if (color.fZ >= 255.0f) { + color.fZ = 255.0f; + } + + return SkPreMultiplyARGB(a, (int) color.fX, (int) color.fY, (int) color.fZ); +} + +// larger is better (fewer times we have to loop), but we shouldn't +// take up too much stack-space (each one here costs 16 bytes) +#define BUFFER_MAX 16 +void SkRadialShadowMapShaderImpl::ShadowMapRadialShaderContext::shadeSpan + (int x, int y, SkPMColor result[], int count) { + do { + int n = SkTMin(count, BUFFER_MAX); + + // just fill with white for now + SkPMColor accum = convert(SkColor3f::Make(1.0f, 1.0f, 1.0f), 0xFF); + + for (int i = 0; i < n; ++i) { + result[i] = accum; + } + + result += n; + x += n; + count -= n; + } while (count > 0); +} + +//////////////////////////////////////////////////////////////////////////// + +#ifndef SK_IGNORE_TO_STRING +void SkRadialShadowMapShaderImpl::toString(SkString* str) const { + str->appendf("RadialShadowMapShader: ()"); +} +#endif + +sk_sp SkRadialShadowMapShaderImpl::CreateProc(SkReadBuffer& buf) { + + // Discarding SkShader flattenable params + bool hasLocalMatrix = buf.readBool(); + SkAssertResult(!hasLocalMatrix); + + sk_sp light = SkLights::MakeFromBuffer(buf); + + int diffuseWidth = buf.readInt(); + int diffuseHeight = buf.readInt(); + + sk_sp occluderShader(buf.readFlattenable()); + + return sk_make_sp(std::move(occluderShader), + std::move(light), + diffuseWidth, diffuseHeight); +} + +void SkRadialShadowMapShaderImpl::flatten(SkWriteBuffer& buf) const { + this->INHERITED::flatten(buf); + + fLight->flatten(buf); + + buf.writeInt(fWidth); + buf.writeInt(fHeight); + + buf.writeFlattenable(fOccluderShader.get()); +} + +size_t SkRadialShadowMapShaderImpl::onContextSize(const ContextRec& rec) const { + return sizeof(ShadowMapRadialShaderContext); +} + +SkShader::Context* SkRadialShadowMapShaderImpl::onCreateContext(const ContextRec& rec, + void* storage) const { + size_t heapRequired = fOccluderShader->contextSize(rec); + + void* heapAllocated = sk_malloc_throw(heapRequired); + + void* occluderContextStorage = heapAllocated; + + SkShader::Context* occluderContext = + fOccluderShader->createContext(rec, occluderContextStorage); + + if (!occluderContext) { + sk_free(heapAllocated); + return nullptr; + } + + return new (storage) ShadowMapRadialShaderContext(*this, rec, occluderContext, heapAllocated); +} + +/////////////////////////////////////////////////////////////////////////////// + +sk_sp SkRadialShadowMapShader::Make(sk_sp occluderShader, + sk_sp light, + int diffuseWidth, int diffuseHeight) { + if (!occluderShader) { + // TODO: Use paint's color in absence of a diffuseShader + // TODO: Use a default implementation of normalSource instead + return nullptr; + } + + return sk_make_sp(std::move(occluderShader), + std::move(light), + diffuseWidth, diffuseHeight); +} + +/////////////////////////////////////////////////////////////////////////////// + +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkRadialShadowMapShader) +SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialShadowMapShaderImpl) +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END + +/////////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/src/core/SkShadowShader.cpp b/src/core/SkShadowShader.cpp new file mode 100644 index 0000000..5729c64 --- /dev/null +++ b/src/core/SkShadowShader.cpp @@ -0,0 +1,955 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCanvas.h" +#include "SkReadBuffer.h" +#include "SkShadowShader.h" + +//////////////////////////////////////////////////////////////////////////// +#ifdef SK_EXPERIMENTAL_SHADOWING + + +/** \class SkShadowShaderImpl + This subclass of shader applies shadowing +*/ +class SkShadowShaderImpl : public SkShader { +public: + /** Create a new shadowing shader that shadows + @param to do to do + */ + SkShadowShaderImpl(sk_sp povDepthShader, + sk_sp diffuseShader, + sk_sp lights, + int diffuseWidth, int diffuseHeight, + const SkShadowParams& params) + : fPovDepthShader(std::move(povDepthShader)) + , fDiffuseShader(std::move(diffuseShader)) + , fLights(std::move(lights)) + , fDiffuseWidth(diffuseWidth) + , fDiffuseHeight(diffuseHeight) + , fShadowParams(params) { } + + bool isOpaque() const override; + +#if SK_SUPPORT_GPU + sk_sp asFragmentProcessor(const AsFPArgs&) const override; +#endif + + class ShadowShaderContext : public SkShader::Context { + public: + // The context takes ownership of the states. It will call their destructors + // but will NOT free the memory. + ShadowShaderContext(const SkShadowShaderImpl&, const ContextRec&, + SkShader::Context* povDepthContext, + SkShader::Context* diffuseContext, + void* heapAllocated); + + ~ShadowShaderContext() override; + + void shadeSpan(int x, int y, SkPMColor[], int count) override; + + uint32_t getFlags() const override { return fFlags; } + + private: + SkShader::Context* fPovDepthContext; + SkShader::Context* fDiffuseContext; + uint32_t fFlags; + + void* fHeapAllocated; + + int fNonAmbLightCnt; + SkPixmap* fShadowMapPixels; + + + typedef SkShader::Context INHERITED; + }; + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkShadowShaderImpl) + +protected: + void flatten(SkWriteBuffer&) const override; + size_t onContextSize(const ContextRec&) const override; + Context* onCreateContext(const ContextRec&, void*) const override; + +private: + sk_sp fPovDepthShader; + sk_sp fDiffuseShader; + sk_sp fLights; + + int fDiffuseWidth; + int fDiffuseHeight; + + SkShadowParams fShadowParams; + + friend class SkShadowShader; + + typedef SkShader INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////// + +#if SK_SUPPORT_GPU + +#include "GrCoordTransform.h" +#include "GrFragmentProcessor.h" +#include "GrInvariantOutput.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "SkGr.h" +#include "SkSpecialImage.h" +#include "SkImage_Base.h" +#include "GrContext.h" + +class ShadowFP : public GrFragmentProcessor { +public: + ShadowFP(sk_sp povDepth, + sk_sp diffuse, + sk_sp lights, + int diffuseWidth, int diffuseHeight, + const SkShadowParams& params, + GrContext* context) { + + fAmbientColor = lights->ambientLightColor(); + + fNumNonAmbLights = 0; // count of non-ambient lights + for (int i = 0; i < lights->numLights(); ++i) { + if (fNumNonAmbLights < SkShadowShader::kMaxNonAmbientLights) { + fLightColor[fNumNonAmbLights] = lights->light(i).color(); + + if (SkLights::Light::kPoint_LightType == lights->light(i).type()) { + fLightDirOrPos[fNumNonAmbLights] = lights->light(i).pos(); + fLightColor[fNumNonAmbLights].scale(lights->light(i).intensity()); + } else { + fLightDirOrPos[fNumNonAmbLights] = lights->light(i).dir(); + } + + fIsPointLight[fNumNonAmbLights] = + SkLights::Light::kPoint_LightType == lights->light(i).type(); + + fIsRadialLight[fNumNonAmbLights] = lights->light(i).isRadial(); + + SkImage_Base* shadowMap = ((SkImage_Base*)lights->light(i).getShadowMap()); + + // gets deleted when the ShadowFP is destroyed, and frees the GrTexture* + fTexture[fNumNonAmbLights] = sk_sp(shadowMap->asTextureRef(context, + GrSamplerParams::ClampNoFilter(), + SkDestinationSurfaceColorMode::kLegacy, + nullptr)); + fDepthMapSampler[fNumNonAmbLights].reset(fTexture[fNumNonAmbLights].get()); + this->addTextureSampler(&fDepthMapSampler[fNumNonAmbLights]); + + fDepthMapHeight[fNumNonAmbLights] = shadowMap->height(); + fDepthMapWidth[fNumNonAmbLights] = shadowMap->width(); + + fNumNonAmbLights++; + } + } + + fWidth = diffuseWidth; + fHeight = diffuseHeight; + + fShadowParams = params; + + this->registerChildProcessor(std::move(povDepth)); + this->registerChildProcessor(std::move(diffuse)); + this->initClassID(); + } + + class GLSLShadowFP : public GrGLSLFragmentProcessor { + public: + GLSLShadowFP() { } + + void emitCode(EmitArgs& args) override { + GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + const ShadowFP& shadowFP = args.fFp.cast(); + + SkASSERT(shadowFP.fNumNonAmbLights <= SkShadowShader::kMaxNonAmbientLights); + + // add uniforms + int32_t numLights = shadowFP.fNumNonAmbLights; + SkASSERT(numLights <= SkShadowShader::kMaxNonAmbientLights); + + int blurAlgorithm = shadowFP.fShadowParams.fType; + + const char* lightDirOrPosUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr}; + const char* lightColorUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr}; + const char* ambientColorUniName = nullptr; + + const char* depthMapWidthUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr}; + const char* depthMapHeightUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr}; + const char* widthUniName = nullptr; // dimensions of povDepth + const char* heightUniName = nullptr; + + const char* shBiasUniName = nullptr; + const char* minVarianceUniName = nullptr; + + // setting uniforms + for (int i = 0; i < shadowFP.fNumNonAmbLights; i++) { + SkString lightDirOrPosUniNameStr("lightDir"); + lightDirOrPosUniNameStr.appendf("%d", i); + SkString lightColorUniNameStr("lightColor"); + lightColorUniNameStr.appendf("%d", i); + SkString lightIntensityUniNameStr("lightIntensity"); + lightIntensityUniNameStr.appendf("%d", i); + + SkString depthMapWidthUniNameStr("dmapWidth"); + depthMapWidthUniNameStr.appendf("%d", i); + SkString depthMapHeightUniNameStr("dmapHeight"); + depthMapHeightUniNameStr.appendf("%d", i); + + fLightDirOrPosUni[i] = uniformHandler->addUniform(kFragment_GrShaderFlag, + kVec3f_GrSLType, + kDefault_GrSLPrecision, + lightDirOrPosUniNameStr.c_str(), + &lightDirOrPosUniName[i]); + fLightColorUni[i] = uniformHandler->addUniform(kFragment_GrShaderFlag, + kVec3f_GrSLType, + kDefault_GrSLPrecision, + lightColorUniNameStr.c_str(), + &lightColorUniName[i]); + + fDepthMapWidthUni[i] = uniformHandler->addUniform(kFragment_GrShaderFlag, + kInt_GrSLType, + kDefault_GrSLPrecision, + depthMapWidthUniNameStr.c_str(), + &depthMapWidthUniName[i]); + fDepthMapHeightUni[i] = uniformHandler->addUniform(kFragment_GrShaderFlag, + kInt_GrSLType, + kDefault_GrSLPrecision, + depthMapHeightUniNameStr.c_str(), + &depthMapHeightUniName[i]); + } + + fBiasingConstantUni = uniformHandler->addUniform(kFragment_GrShaderFlag, + kFloat_GrSLType, + kDefault_GrSLPrecision, + "shadowBias", &shBiasUniName); + fMinVarianceUni = uniformHandler->addUniform(kFragment_GrShaderFlag, + kFloat_GrSLType, + kDefault_GrSLPrecision, + "minVariance", &minVarianceUniName); + + fWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag, + kInt_GrSLType, + kDefault_GrSLPrecision, + "width", &widthUniName); + fHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag, + kInt_GrSLType, + kDefault_GrSLPrecision, + "height", &heightUniName); + + fAmbientColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag, + kVec3f_GrSLType, kDefault_GrSLPrecision, + "AmbientColor", &ambientColorUniName); + + SkString povDepthSampler("_povDepth"); + SkString povDepth("povDepth"); + this->emitChild(0, &povDepthSampler, args); + fragBuilder->codeAppendf("vec4 %s = %s;", povDepth.c_str(), povDepthSampler.c_str()); + + SkString diffuseColorSampler("_inDiffuseColor"); + SkString diffuseColor("inDiffuseColor"); + this->emitChild(1, &diffuseColorSampler, args); + fragBuilder->codeAppendf("vec4 %s = %s;", diffuseColor.c_str(), + diffuseColorSampler.c_str()); + + SkString depthMaps[SkShadowShader::kMaxNonAmbientLights]; + + fragBuilder->codeAppendf("vec4 resultDiffuseColor = %s;", diffuseColor.c_str()); + fragBuilder->codeAppend ("vec3 totalLightColor = vec3(0);"); + + // probability that a fragment is lit. For each light, we multiply this by the + // light's color to get its contribution to totalLightColor. + fragBuilder->codeAppend ("float lightProbability;"); + + // coordinates of current fragment in world space + fragBuilder->codeAppend ("vec3 worldCor;"); + + // Multiply by 255 to transform from sampler coordinates to world + // coordinates (since 1 channel is 0xFF) + // Note: vMatrixCoord_0_1_Stage0 is the texture sampler coordinates. + fragBuilder->codeAppendf("worldCor = vec3(vMatrixCoord_0_1_Stage0 * " + "vec2(%s, %s), %s.b * 255);", + widthUniName, heightUniName, povDepth.c_str()); + + // Applies the offset indexing that goes from our view space into the light's space. + for (int i = 0; i < shadowFP.fNumNonAmbLights; i++) { + SkString povCoord("povCoord"); + povCoord.appendf("%d", i); + + SkString offset("offset"); + offset.appendf("%d", i); + fragBuilder->codeAppendf("vec2 %s;", offset.c_str()); + + if (shadowFP.fIsPointLight[i]) { + fragBuilder->codeAppendf("vec3 fragToLight%d = %s - worldCor;", + i, lightDirOrPosUniName[i]); + fragBuilder->codeAppendf("float dist%d = length(fragToLight%d);", + i, i); + fragBuilder->codeAppendf("%s = vec2(-fragToLight%d) * povDepth.b;", + offset.c_str(), i); + fragBuilder->codeAppendf("fragToLight%d = normalize(fragToLight%d);", + i, i); + } + + if (shadowFP.fIsRadialLight[i]) { + fragBuilder->codeAppendf("vec2 %s = vec2(vMatrixCoord_0_1_Stage0.x, " + "1 - vMatrixCoord_0_1_Stage0.y);\n", + povCoord.c_str()); + + fragBuilder->codeAppendf("%s = (%s) * 2.0 - 1.0 + (vec2(%s)/vec2(%s,%s) - 0.5)" + "* vec2(-2.0, 2.0);\n", + povCoord.c_str(), povCoord.c_str(), + lightDirOrPosUniName[i], + widthUniName, heightUniName); + + fragBuilder->codeAppendf("float theta = atan(%s.y, %s.x);", + povCoord.c_str(), povCoord.c_str()); + fragBuilder->codeAppendf("float r = length(%s);", povCoord.c_str()); + + // map output of atan to [0, 1] + fragBuilder->codeAppendf("%s.x = (theta + 3.1415) / (2.0 * 3.1415);", + povCoord.c_str()); + fragBuilder->codeAppendf("%s.y = 0.0;", povCoord.c_str()); + } else { + // note that we flip the y-coord of the offset and then later add + // a value just to the y-coord of povCoord. This is to account for + // the shifted origins from switching from raster into GPU. + if (shadowFP.fIsPointLight[i]) { + // the 0.375s are precalculated transform values, given that the depth + // maps for pt lights are 4x the size (linearly) as diffuse maps. + // The vec2(0.375, -0.375) is used to transform us to + // the center of the map. + fragBuilder->codeAppendf("vec2 %s = ((vec2(%s, %s) *" + "vMatrixCoord_0_1_Stage0 +" + "vec2(0,%s - %s)" + "+ %s) / (vec2(%s, %s))) +" + "vec2(0.375, -0.375);", + povCoord.c_str(), + widthUniName, heightUniName, + depthMapHeightUniName[i], heightUniName, + offset.c_str(), + depthMapWidthUniName[i], + depthMapWidthUniName[i]); + } else { + fragBuilder->codeAppendf("%s = vec2(%s) * povDepth.b * " + "vec2(255.0, -255.0);", + offset.c_str(), lightDirOrPosUniName[i]); + + fragBuilder->codeAppendf("vec2 %s = ((vec2(%s, %s) *" + "vMatrixCoord_0_1_Stage0 +" + "vec2(0,%s - %s)" + "+ %s) / vec2(%s, %s));", + povCoord.c_str(), + widthUniName, heightUniName, + depthMapHeightUniName[i], heightUniName, + offset.c_str(), + depthMapWidthUniName[i], + depthMapWidthUniName[i]); + } + } + + fragBuilder->appendTextureLookup(&depthMaps[i], args.fTexSamplers[i], + povCoord.c_str(), + kVec2f_GrSLType); + } + + // helper variables for calculating shadowing + + // variance of depth at this fragment in the context of surrounding area + // (area size and weighting dependent on blur size and type) + fragBuilder->codeAppendf("float variance;"); + + // the difference in depth between the user POV and light POV. + fragBuilder->codeAppendf("float d;"); + + // add up light contributions from all lights to totalLightColor + for (int i = 0; i < numLights; i++) { + fragBuilder->codeAppendf("lightProbability = 1;"); + + if (shadowFP.fIsRadialLight[i]) { + fragBuilder->codeAppend("totalLightColor = vec3(0);"); + + fragBuilder->codeAppend("vec2 tc = vec2(povCoord0.x, 0.0);"); + fragBuilder->codeAppend("float depth = texture(uTextureSampler0_Stage1," + "povCoord0).b * 2.0;"); + + fragBuilder->codeAppendf("lightProbability = step(r, depth);"); + + // 2 is the maximum depth. If this is reached, probably we have + // not intersected anything. So values after this should be unshadowed. + fragBuilder->codeAppendf("if (%s.b != 0 || depth == 2) {" + "lightProbability = 1.0; }", + povDepth.c_str()); + } else { + // 1/512 == .00195... is less than half a pixel; imperceptible + fragBuilder->codeAppendf("if (%s.b <= %s.b + .001953125) {", + povDepth.c_str(), depthMaps[i].c_str()); + if (blurAlgorithm == SkShadowParams::kVariance_ShadowType) { + // We mess with depth and depth^2 in their given scales. + // (i.e. between 0 and 1) + fragBuilder->codeAppendf("vec2 moments%d = vec2(%s.b, %s.g);", + i, depthMaps[i].c_str(), depthMaps[i].c_str()); + + // variance biasing lessens light bleeding + fragBuilder->codeAppendf("variance = max(moments%d.y - " + "(moments%d.x * moments%d.x)," + "%s);", i, i, i, + minVarianceUniName); + + fragBuilder->codeAppendf("d = (%s.b) - moments%d.x;", + povDepth.c_str(), i); + fragBuilder->codeAppendf("lightProbability = " + "(variance / (variance + d * d));"); + + SkString clamp("clamp"); + clamp.appendf("%d", i); + + // choosing between light artifacts or correct shape shadows + // linstep + fragBuilder->codeAppendf("float %s = clamp((lightProbability - %s) /" + "(1 - %s), 0, 1);", + clamp.c_str(), shBiasUniName, shBiasUniName); + + fragBuilder->codeAppendf("lightProbability = %s;", clamp.c_str()); + } else { + fragBuilder->codeAppendf("if (%s.b >= %s.b) {", + povDepth.c_str(), depthMaps[i].c_str()); + fragBuilder->codeAppendf("lightProbability = 1;"); + fragBuilder->codeAppendf("} else { lightProbability = 0; }"); + } + + // VSM: The curved shadows near plane edges are artifacts from blurring + // lightDir.z is equal to the lightDir dot the surface normal. + fragBuilder->codeAppendf("}"); + } + + if (shadowFP.isPointLight(i)) { + fragBuilder->codeAppendf("totalLightColor += max(fragToLight%d.z, 0) * %s /" + "(1 + dist%d) * lightProbability;", + i, lightColorUniName[i], i); + } else { + fragBuilder->codeAppendf("totalLightColor += %s.z * %s * lightProbability;", + lightDirOrPosUniName[i], + lightColorUniName[i]); + } + + fragBuilder->codeAppendf("totalLightColor += %s;", ambientColorUniName); + fragBuilder->codeAppendf("%s = resultDiffuseColor * vec4(totalLightColor, 1);", + args.fOutputColor); + } + + } + + static void GenKey(const GrProcessor& proc, const GrShaderCaps&, + GrProcessorKeyBuilder* b) { + const ShadowFP& shadowFP = proc.cast(); + b->add32(shadowFP.fNumNonAmbLights); + int isPLR = 0; + for (int i = 0; i < SkShadowShader::kMaxNonAmbientLights; i++) { + isPLR = isPLR | ((shadowFP.fIsPointLight[i] ? 1 : 0) << i); + isPLR = isPLR | ((shadowFP.fIsRadialLight[i] ? 1 : 0) << (i+4)); + } + b->add32(isPLR); + b->add32(shadowFP.fShadowParams.fType); + } + + protected: + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& proc) override { + const ShadowFP &shadowFP = proc.cast(); + + for (int i = 0; i < shadowFP.numLights(); i++) { + const SkVector3& lightDirOrPos = shadowFP.lightDirOrPos(i); + if (lightDirOrPos != fLightDirOrPos[i]) { + pdman.set3fv(fLightDirOrPosUni[i], 1, &lightDirOrPos.fX); + fLightDirOrPos[i] = lightDirOrPos; + } + + const SkColor3f& lightColor = shadowFP.lightColor(i); + if (lightColor != fLightColor[i]) { + pdman.set3fv(fLightColorUni[i], 1, &lightColor.fX); + fLightColor[i] = lightColor; + } + + int depthMapWidth = shadowFP.depthMapWidth(i); + if (depthMapWidth != fDepthMapWidth[i]) { + pdman.set1i(fDepthMapWidthUni[i], depthMapWidth); + fDepthMapWidth[i] = depthMapWidth; + } + int depthMapHeight = shadowFP.depthMapHeight(i); + if (depthMapHeight != fDepthMapHeight[i]) { + pdman.set1i(fDepthMapHeightUni[i], depthMapHeight); + fDepthMapHeight[i] = depthMapHeight; + } + } + + SkScalar biasingConstant = shadowFP.shadowParams().fBiasingConstant; + if (biasingConstant != fBiasingConstant) { + pdman.set1f(fBiasingConstantUni, biasingConstant); + fBiasingConstant = biasingConstant; + } + + SkScalar minVariance = shadowFP.shadowParams().fMinVariance; + if (minVariance != fMinVariance) { + // transform variance from pixel-scale to normalized scale + pdman.set1f(fMinVarianceUni, minVariance / 65536.0f); + fMinVariance = minVariance / 65536.0f; + } + + int width = shadowFP.width(); + if (width != fWidth) { + pdman.set1i(fWidthUni, width); + fWidth = width; + } + int height = shadowFP.height(); + if (height != fHeight) { + pdman.set1i(fHeightUni, height); + fHeight = height; + } + + const SkColor3f& ambientColor = shadowFP.ambientColor(); + if (ambientColor != fAmbientColor) { + pdman.set3fv(fAmbientColorUni, 1, &ambientColor.fX); + fAmbientColor = ambientColor; + } + } + + private: + SkVector3 fLightDirOrPos[SkShadowShader::kMaxNonAmbientLights]; + GrGLSLProgramDataManager::UniformHandle + fLightDirOrPosUni[SkShadowShader::kMaxNonAmbientLights]; + + SkColor3f fLightColor[SkShadowShader::kMaxNonAmbientLights]; + GrGLSLProgramDataManager::UniformHandle + fLightColorUni[SkShadowShader::kMaxNonAmbientLights]; + + int fDepthMapWidth[SkShadowShader::kMaxNonAmbientLights]; + GrGLSLProgramDataManager::UniformHandle + fDepthMapWidthUni[SkShadowShader::kMaxNonAmbientLights]; + + int fDepthMapHeight[SkShadowShader::kMaxNonAmbientLights]; + GrGLSLProgramDataManager::UniformHandle + fDepthMapHeightUni[SkShadowShader::kMaxNonAmbientLights]; + + int fWidth; + GrGLSLProgramDataManager::UniformHandle fWidthUni; + int fHeight; + GrGLSLProgramDataManager::UniformHandle fHeightUni; + + SkScalar fBiasingConstant; + GrGLSLProgramDataManager::UniformHandle fBiasingConstantUni; + SkScalar fMinVariance; + GrGLSLProgramDataManager::UniformHandle fMinVarianceUni; + + SkColor3f fAmbientColor; + GrGLSLProgramDataManager::UniformHandle fAmbientColorUni; + }; + + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { + GLSLShadowFP::GenKey(*this, caps, b); + } + + const char* name() const override { return "shadowFP"; } + + int32_t numLights() const { return fNumNonAmbLights; } + const SkColor3f& ambientColor() const { return fAmbientColor; } + bool isPointLight(int i) const { + SkASSERT(i < fNumNonAmbLights); + return fIsPointLight[i]; + } + bool isRadialLight(int i) const { + SkASSERT(i < fNumNonAmbLights); + return fIsRadialLight[i]; + } + const SkVector3& lightDirOrPos(int i) const { + SkASSERT(i < fNumNonAmbLights); + return fLightDirOrPos[i]; + } + const SkVector3& lightColor(int i) const { + SkASSERT(i < fNumNonAmbLights); + return fLightColor[i]; + } + int depthMapWidth(int i) const { + SkASSERT(i < fNumNonAmbLights); + return fDepthMapWidth[i]; + } + int depthMapHeight(int i) const { + SkASSERT(i < fNumNonAmbLights); + return fDepthMapHeight[i]; + } + int width() const {return fWidth; } + int height() const {return fHeight; } + + const SkShadowParams& shadowParams() const {return fShadowParams; } + +private: + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLShadowFP; } + + bool onIsEqual(const GrFragmentProcessor& proc) const override { + const ShadowFP& shadowFP = proc.cast(); + if (fAmbientColor != shadowFP.fAmbientColor || + fNumNonAmbLights != shadowFP.fNumNonAmbLights) { + return false; + } + + if (fWidth != shadowFP.fWidth || fHeight != shadowFP.fHeight) { + return false; + } + + for (int i = 0; i < fNumNonAmbLights; i++) { + if (fLightDirOrPos[i] != shadowFP.fLightDirOrPos[i] || + fLightColor[i] != shadowFP.fLightColor[i] || + fIsPointLight[i] != shadowFP.fIsPointLight[i] || + fIsRadialLight[i] != shadowFP.fIsRadialLight[i]) { + return false; + } + + if (fDepthMapWidth[i] != shadowFP.fDepthMapWidth[i] || + fDepthMapHeight[i] != shadowFP.fDepthMapHeight[i]) { + return false; + } + } + + return true; + } + + int fNumNonAmbLights; + + bool fIsPointLight[SkShadowShader::kMaxNonAmbientLights]; + bool fIsRadialLight[SkShadowShader::kMaxNonAmbientLights]; + SkVector3 fLightDirOrPos[SkShadowShader::kMaxNonAmbientLights]; + SkColor3f fLightColor[SkShadowShader::kMaxNonAmbientLights]; + TextureSampler fDepthMapSampler[SkShadowShader::kMaxNonAmbientLights]; + sk_sp fTexture[SkShadowShader::kMaxNonAmbientLights]; + + int fDepthMapWidth[SkShadowShader::kMaxNonAmbientLights]; + int fDepthMapHeight[SkShadowShader::kMaxNonAmbientLights]; + + int fHeight; + int fWidth; + + SkShadowParams fShadowParams; + + SkColor3f fAmbientColor; +}; + +//////////////////////////////////////////////////////////////////////////// + +sk_sp SkShadowShaderImpl::asFragmentProcessor(const AsFPArgs& fpargs) const { + + sk_sp povDepthFP = fPovDepthShader->asFragmentProcessor(fpargs); + + sk_sp diffuseFP = fDiffuseShader->asFragmentProcessor(fpargs); + + sk_sp shadowfp = sk_make_sp(std::move(povDepthFP), + std::move(diffuseFP), + std::move(fLights), + fDiffuseWidth, fDiffuseHeight, + fShadowParams, fpargs.fContext); + return shadowfp; +} + + +#endif + +//////////////////////////////////////////////////////////////////////////// + +bool SkShadowShaderImpl::isOpaque() const { + return fDiffuseShader->isOpaque(); +} + +SkShadowShaderImpl::ShadowShaderContext::ShadowShaderContext( + const SkShadowShaderImpl& shader, const ContextRec& rec, + SkShader::Context* povDepthContext, + SkShader::Context* diffuseContext, + void* heapAllocated) + : INHERITED(shader, rec) + , fPovDepthContext(povDepthContext) + , fDiffuseContext(diffuseContext) + , fHeapAllocated(heapAllocated) { + bool isOpaque = shader.isOpaque(); + + // update fFlags + uint32_t flags = 0; + if (isOpaque && (255 == this->getPaintAlpha())) { + flags |= kOpaqueAlpha_Flag; + } + + fFlags = flags; + + const SkShadowShaderImpl& lightShader = static_cast(fShader); + + fNonAmbLightCnt = lightShader.fLights->numLights(); + fShadowMapPixels = new SkPixmap[fNonAmbLightCnt]; + + for (int i = 0; i < fNonAmbLightCnt; i++) { + if (lightShader.fLights->light(i).type() == SkLights::Light::kDirectional_LightType) { + lightShader.fLights->light(i).getShadowMap()-> + peekPixels(&fShadowMapPixels[i]); + } + } +} + +SkShadowShaderImpl::ShadowShaderContext::~ShadowShaderContext() { + delete[] fShadowMapPixels; + + // The dependencies have been created outside of the context on memory that was allocated by + // the onCreateContext() method. Call the destructors and free the memory. + fPovDepthContext->~Context(); + fDiffuseContext->~Context(); + + sk_free(fHeapAllocated); +} + +static inline SkPMColor convert(SkColor3f color, U8CPU a) { + if (color.fX <= 0.0f) { + color.fX = 0.0f; + } else if (color.fX >= 255.0f) { + color.fX = 255.0f; + } + + if (color.fY <= 0.0f) { + color.fY = 0.0f; + } else if (color.fY >= 255.0f) { + color.fY = 255.0f; + } + + if (color.fZ <= 0.0f) { + color.fZ = 0.0f; + } else if (color.fZ >= 255.0f) { + color.fZ = 255.0f; + } + + return SkPreMultiplyARGB(a, (int) color.fX, (int) color.fY, (int) color.fZ); +} + +// larger is better (fewer times we have to loop), but we shouldn't +// take up too much stack-space (each one here costs 16 bytes) +#define BUFFER_MAX 16 +void SkShadowShaderImpl::ShadowShaderContext::shadeSpan(int x, int y, + SkPMColor result[], int count) { + const SkShadowShaderImpl& lightShader = static_cast(fShader); + + SkPMColor diffuse[BUFFER_MAX]; + SkPMColor povDepth[BUFFER_MAX]; + + do { + int n = SkTMin(count, BUFFER_MAX); + + fDiffuseContext->shadeSpan(x, y, diffuse, n); + fPovDepthContext->shadeSpan(x, y, povDepth, n); + + for (int i = 0; i < n; ++i) { + SkColor diffColor = SkUnPreMultiply::PMColorToColor(diffuse[i]); + SkColor povDepthColor = povDepth[i]; + + SkColor3f totalLight = lightShader.fLights->ambientLightColor(); + // This is all done in linear unpremul color space (each component 0..255.0f though) + + for (int l = 0; l < lightShader.fLights->numLights(); ++l) { + const SkLights::Light& light = lightShader.fLights->light(l); + + int pvDepth = SkColorGetB(povDepthColor); // depth stored in blue channel + + if (light.type() == SkLights::Light::kDirectional_LightType) { + + int xOffset = SkScalarRoundToInt(light.dir().fX * pvDepth); + int yOffset = SkScalarRoundToInt(light.dir().fY * pvDepth); + + int shX = SkClampMax(x + i + xOffset, light.getShadowMap()->width() - 1); + int shY = SkClampMax(y + yOffset, light.getShadowMap()->height() - 1); + + int shDepth = 0; + int shDepthsq = 0; + + // pixmaps that point to things have nonzero heights + if (fShadowMapPixels[l].height() > 0) { + uint32_t pix = *fShadowMapPixels[l].addr32(shX, shY); + SkColor shColor(pix); + + shDepth = SkColorGetB(shColor); + shDepthsq = SkColorGetG(shColor) * 256; + } else { + // Make lights w/o a shadow map receive the full light contribution + shDepth = pvDepth; + } + + SkScalar lightProb = 1.0f; + if (pvDepth < shDepth) { + if (lightShader.fShadowParams.fType == + SkShadowParams::ShadowType::kVariance_ShadowType) { + int variance = SkMaxScalar(shDepthsq - shDepth * shDepth, + lightShader.fShadowParams.fMinVariance); + int d = pvDepth - shDepth; + + lightProb = (SkScalar) variance / ((SkScalar) (variance + d * d)); + + SkScalar bias = lightShader.fShadowParams.fBiasingConstant; + + lightProb = SkMaxScalar((lightProb - bias) / (1.0f - bias), 0.0f); + } else { + lightProb = 0.0f; + } + } + + // assume object normals are pointing straight up + totalLight.fX += light.dir().fZ * light.color().fX * lightProb; + totalLight.fY += light.dir().fZ * light.color().fY * lightProb; + totalLight.fZ += light.dir().fZ * light.color().fZ * lightProb; + + } else { + // right now we only expect directional and point light types. + SkASSERT(light.type() == SkLights::Light::kPoint_LightType); + + int height = lightShader.fDiffuseHeight; + + SkVector3 fragToLight = SkVector3::Make(light.pos().fX - x - i, + light.pos().fY - (height - y), + light.pos().fZ - pvDepth); + + SkScalar dist = fragToLight.length(); + SkScalar normalizedZ = fragToLight.fZ / dist; + + SkScalar distAttenuation = light.intensity() / (1.0f + dist); + + // assume object normals are pointing straight up + totalLight.fX += normalizedZ * light.color().fX * distAttenuation; + totalLight.fY += normalizedZ * light.color().fY * distAttenuation; + totalLight.fZ += normalizedZ * light.color().fZ * distAttenuation; + } + } + + SkColor3f totalColor = SkColor3f::Make(SkColorGetR(diffColor) * totalLight.fX, + SkColorGetG(diffColor) * totalLight.fY, + SkColorGetB(diffColor) * totalLight.fZ); + + result[i] = convert(totalColor, SkColorGetA(diffColor)); + } + + result += n; + x += n; + count -= n; + } while (count > 0); +} + +//////////////////////////////////////////////////////////////////////////// + +#ifndef SK_IGNORE_TO_STRING +void SkShadowShaderImpl::toString(SkString* str) const { + str->appendf("ShadowShader: ()"); +} +#endif + +sk_sp SkShadowShaderImpl::CreateProc(SkReadBuffer& buf) { + + // Discarding SkShader flattenable params + bool hasLocalMatrix = buf.readBool(); + SkAssertResult(!hasLocalMatrix); + + sk_sp lights = SkLights::MakeFromBuffer(buf); + + SkShadowParams params; + params.fMinVariance = buf.readScalar(); + params.fBiasingConstant = buf.readScalar(); + params.fType = (SkShadowParams::ShadowType) buf.readInt(); + params.fShadowRadius = buf.readScalar(); + + int diffuseWidth = buf.readInt(); + int diffuseHeight = buf.readInt(); + + sk_sp povDepthShader(buf.readFlattenable()); + sk_sp diffuseShader(buf.readFlattenable()); + + return sk_make_sp(std::move(povDepthShader), + std::move(diffuseShader), + std::move(lights), + diffuseWidth, diffuseHeight, + params); +} + +void SkShadowShaderImpl::flatten(SkWriteBuffer& buf) const { + this->INHERITED::flatten(buf); + + fLights->flatten(buf); + + buf.writeScalar(fShadowParams.fMinVariance); + buf.writeScalar(fShadowParams.fBiasingConstant); + buf.writeInt(fShadowParams.fType); + buf.writeScalar(fShadowParams.fShadowRadius); + + buf.writeInt(fDiffuseWidth); + buf.writeInt(fDiffuseHeight); + + buf.writeFlattenable(fPovDepthShader.get()); + buf.writeFlattenable(fDiffuseShader.get()); +} + +size_t SkShadowShaderImpl::onContextSize(const ContextRec& rec) const { + return sizeof(ShadowShaderContext); +} + +SkShader::Context* SkShadowShaderImpl::onCreateContext(const ContextRec& rec, + void* storage) const { + size_t heapRequired = fPovDepthShader->contextSize(rec) + + fDiffuseShader->contextSize(rec); + + void* heapAllocated = sk_malloc_throw(heapRequired); + + void* povDepthContextStorage = heapAllocated; + + SkShader::Context* povDepthContext = + fPovDepthShader->createContext(rec, povDepthContextStorage); + + if (!povDepthContext) { + sk_free(heapAllocated); + return nullptr; + } + + void* diffuseContextStorage = (char*)heapAllocated + fPovDepthShader->contextSize(rec); + + SkShader::Context* diffuseContext = fDiffuseShader->createContext(rec, diffuseContextStorage); + if (!diffuseContext) { + sk_free(heapAllocated); + return nullptr; + } + + return new (storage) ShadowShaderContext(*this, rec, povDepthContext, diffuseContext, + heapAllocated); +} + +/////////////////////////////////////////////////////////////////////////////// + +sk_sp SkShadowShader::Make(sk_sp povDepthShader, + sk_sp diffuseShader, + sk_sp lights, + int diffuseWidth, int diffuseHeight, + const SkShadowParams& params) { + if (!povDepthShader || !diffuseShader) { + // TODO: Use paint's color in absence of a diffuseShader + // TODO: Use a default implementation of normalSource instead + return nullptr; + } + + return sk_make_sp(std::move(povDepthShader), + std::move(diffuseShader), + std::move(lights), + diffuseWidth, diffuseHeight, + params); +} + +/////////////////////////////////////////////////////////////////////////////// + +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShadowShader) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkShadowShaderImpl) +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END + +/////////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/src/effects/GrAlphaThresholdFragmentProcessor.cpp b/src/effects/GrAlphaThresholdFragmentProcessor.cpp index 6c355c1..de1b74e 100644 --- a/src/effects/GrAlphaThresholdFragmentProcessor.cpp +++ b/src/effects/GrAlphaThresholdFragmentProcessor.cpp @@ -127,8 +127,7 @@ void GrGLAlphaThresholdFragmentProcessor::emitCode(EmitArgs& args) { "color.a = inner_thresh;" "}"); - fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, - (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr4("color")).c_str()); + fragBuilder->codeAppendf("%s = %s * color;", args.fOutputColor, args.fInputColor); } void GrGLAlphaThresholdFragmentProcessor::onSetData(const GrGLSLProgramDataManager& pdman, diff --git a/src/effects/SkArithmeticImageFilter.cpp b/src/effects/SkArithmeticImageFilter.cpp index a80ce19..d9c2b60 100644 --- a/src/effects/SkArithmeticImageFilter.cpp +++ b/src/effects/SkArithmeticImageFilter.cpp @@ -238,7 +238,7 @@ private: GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString dstColor("dstColor"); - this->emitChild(0, nullptr, &dstColor, args); + this->emitChild(0, &dstColor, args); fKUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec4f_GrSLType, kDefault_GrSLPrecision, "k"); diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp index cd2a36e..e6c4661 100644 --- a/src/effects/SkLightingImageFilter.cpp +++ b/src/effects/SkLightingImageFilter.cpp @@ -1915,9 +1915,7 @@ void GrGLLightingEffect::emitCode(EmitArgs& args) { args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale); fLight->emitLightColor(uniformHandler, fragBuilder, "surfaceToLight"); fragBuilder->codeAppend(");\n"); - SkString modulate; - GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); - fragBuilder->codeAppend(modulate.c_str()); + fragBuilder->codeAppendf("%s *= %s;\n", args.fOutputColor, args.fInputColor); } void GrGLLightingEffect::GenKey(const GrProcessor& proc, diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp index 8552c81..8e289e5 100644 --- a/src/effects/SkMagnifierImageFilter.cpp +++ b/src/effects/SkMagnifierImageFilter.cpp @@ -196,10 +196,8 @@ void GrGLMagnifierEffect::emitCode(EmitArgs& args) { &fColorSpaceHelper); fragBuilder->codeAppend(";\n"); - fragBuilder->codeAppendf("\t\t%s = output_color;", args.fOutputColor); - SkString modulate; - GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); - fragBuilder->codeAppend(modulate.c_str()); + fragBuilder->codeAppendf("\t\t%s = output_color;\n", args.fOutputColor); + fragBuilder->codeAppendf("%s *= %s;\n", args.fOutputColor, args.fInputColor); } void GrGLMagnifierEffect::onSetData(const GrGLSLProgramDataManager& pdman, diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp index d11b4da..e783488 100644 --- a/src/effects/SkMorphologyImageFilter.cpp +++ b/src/effects/SkMorphologyImageFilter.cpp @@ -276,9 +276,7 @@ void GrGLMorphologyEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("\t\t\tcoord.%s = min(highBound, coord.%s);", dir, dir); } fragBuilder->codeAppend("\t\t}\n"); - SkString modulate; - GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); - fragBuilder->codeAppend(modulate.c_str()); + fragBuilder->codeAppendf("%s *= %s;\n", args.fOutputColor, args.fInputColor); } void GrGLMorphologyEffect::GenKey(const GrProcessor& proc, diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp index 276eaac..f1cf195 100644 --- a/src/effects/gradients/SkGradientShader.cpp +++ b/src/effects/gradients/SkGradientShader.cpp @@ -1434,8 +1434,7 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui if (ge.fColorSpaceXform) { fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); } - fragBuilder->codeAppendf("%s = %s;", outputColor, - (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); + fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor); break; } @@ -1473,8 +1472,7 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui if (ge.fColorSpaceXform) { fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); } - fragBuilder->codeAppendf("%s = %s;", outputColor, - (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); + fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor); break; } @@ -1512,8 +1510,7 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui if (ge.fColorSpaceXform) { fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); } - fragBuilder->codeAppendf("%s = %s;", outputColor, - (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); + fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor); break; } @@ -1539,8 +1536,7 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); } - fragBuilder->codeAppendf("%s = %s;", outputColor, - (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); + fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor); break; } @@ -1571,8 +1567,7 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); } - fragBuilder->codeAppendf("%s = %s;", outputColor, - (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); + fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor); break; } diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp index 3529467..462766a 100644 --- a/src/gpu/GrFragmentProcessor.cpp +++ b/src/gpu/GrFragmentProcessor.cpp @@ -283,7 +283,7 @@ sk_sp GrFragmentProcessor::MakeInputPremulAndMulByOutput( public: void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - this->emitChild(0, nullptr, args); + this->emitChild(0, args); fragBuilder->codeAppendf("%s.rgb *= %s.rgb;", args.fOutputColor, args.fInputColor); fragBuilder->codeAppendf("%s *= %s.a;", args.fOutputColor, args.fInputColor); diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp index c60400e..70a0096 100644 --- a/src/gpu/effects/GrBicubicEffect.cpp +++ b/src/gpu/effects/GrBicubicEffect.cpp @@ -112,9 +112,8 @@ void GrGLBicubicEffect::emitCode(EmitArgs& args) { fragBuilder->appendColorGamutXform(&xformedColor, bicubicColor.c_str(), &fColorSpaceHelper); bicubicColor.swap(xformedColor); } - fragBuilder->codeAppendf("%s = %s;", - args.fOutputColor, (GrGLSLExpr4(bicubicColor.c_str()) * - GrGLSLExpr4(args.fInputColor)).c_str()); + fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputColor, bicubicColor.c_str(), + args.fInputColor); } void GrGLBicubicEffect::onSetData(const GrGLSLProgramDataManager& pdman, diff --git a/src/gpu/effects/GrConvexPolyEffect.cpp b/src/gpu/effects/GrConvexPolyEffect.cpp index 312c038..4b9599e 100644 --- a/src/gpu/effects/GrConvexPolyEffect.cpp +++ b/src/gpu/effects/GrConvexPolyEffect.cpp @@ -132,8 +132,7 @@ void GLAARectEffect::emitCode(EmitArgs& args) { if (GrProcessorEdgeTypeIsInverseFill(aare.getEdgeType())) { fragBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n"); } - fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, - (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); + fragBuilder->codeAppendf("\t\t%s = %s * alpha;\n", args.fOutputColor, args.fInputColor); } void GLAARectEffect::onSetData(const GrGLSLProgramDataManager& pdman, @@ -212,8 +211,7 @@ void GrGLConvexPolyEffect::emitCode(EmitArgs& args) { if (GrProcessorEdgeTypeIsInverseFill(cpe.getEdgeType())) { fragBuilder->codeAppend("\talpha = 1.0 - alpha;\n"); } - fragBuilder->codeAppendf("\t%s = %s;\n", args.fOutputColor, - (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); + fragBuilder->codeAppendf("\t%s = %s * alpha;\n", args.fOutputColor, args.fInputColor); } void GrGLConvexPolyEffect::onSetData(const GrGLSLProgramDataManager& pdman, diff --git a/src/gpu/effects/GrDitherEffect.cpp b/src/gpu/effects/GrDitherEffect.cpp index 864a5d2..0686750 100644 --- a/src/gpu/effects/GrDitherEffect.cpp +++ b/src/gpu/effects/GrDitherEffect.cpp @@ -74,7 +74,7 @@ void GLDitherEffect::emitCode(EmitArgs& args) { "fract(sin(dot(sk_FragCoord.xy, vec2(12.9898,78.233))) * " "43758.5453);\n"); fragBuilder->codeAppendf("\t\t%s = clamp((1.0/255.0) * vec4(r, r, r, r) + %s, 0, 1);\n", - args.fOutputColor, GrGLSLExpr4(args.fInputColor).c_str()); + args.fOutputColor, args.fInputColor); } ////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp index b4f1314..324c61e 100644 --- a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp +++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp @@ -91,10 +91,7 @@ void GrGLConvolutionEffect::emitCode(EmitArgs& args) { } fragBuilder->codeAppendf("coord += %s;\n", imgInc); } - - SkString modulate; - GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); - fragBuilder->codeAppend(modulate.c_str()); + fragBuilder->codeAppendf("%s *= %s;\n", args.fOutputColor, args.fInputColor); } void GrGLConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman, diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/src/gpu/effects/GrMatrixConvolutionEffect.cpp index 03d90ea..b3ea81a 100644 --- a/src/gpu/effects/GrMatrixConvolutionEffect.cpp +++ b/src/gpu/effects/GrMatrixConvolutionEffect.cpp @@ -114,10 +114,7 @@ void GrGLMatrixConvolutionEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("%s.rgb = clamp(sum.rgb * %s + %s, 0, 1);", args.fOutputColor, gain, bias); fragBuilder->codeAppendf("%s.rgb *= %s.a;", args.fOutputColor, args.fOutputColor); } - - SkString modulate; - GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); - fragBuilder->codeAppend(modulate.c_str()); + fragBuilder->codeAppendf("%s *= %s;\n", args.fOutputColor, args.fInputColor); } void GrGLMatrixConvolutionEffect::GenKey(const GrProcessor& processor, diff --git a/src/gpu/effects/GrOvalEffect.cpp b/src/gpu/effects/GrOvalEffect.cpp index 672f5d8..2eb1d85 100644 --- a/src/gpu/effects/GrOvalEffect.cpp +++ b/src/gpu/effects/GrOvalEffect.cpp @@ -140,8 +140,7 @@ void GLCircleEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppend("d = d > 0.5 ? 1.0 : 0.0;"); } - fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, - (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("d")).c_str()); + fragBuilder->codeAppendf("%s = %s * d;", args.fOutputColor, args.fInputColor); } void GLCircleEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&, @@ -333,8 +332,7 @@ void GLEllipseEffect::emitCode(EmitArgs& args) { SkFAIL("Hairline not expected here."); } - fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, - (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); + fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor); } void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&, diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp index 887bc00..8d18150 100644 --- a/src/gpu/effects/GrRRectEffect.cpp +++ b/src/gpu/effects/GrRRectEffect.cpp @@ -279,8 +279,7 @@ void GLCircularRRectEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppend("alpha = 1.0 - alpha;"); } - fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, - (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); + fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor); } void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&, @@ -590,8 +589,7 @@ void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);"); } - fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, - (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); + fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor); } void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&, diff --git a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp index 30a9faa..aa79937 100644 --- a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp +++ b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp @@ -415,7 +415,7 @@ public: ComposeOneFragmentProcessor::Child child = args.fFp.cast().child(); SkString childColor("child"); - this->emitChild(0, nullptr, &childColor, args); + this->emitChild(0, &childColor, args); const char* inputColor = args.fInputColor; // We don't try to optimize for this case at all diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp index 9ddfa80..0351819 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -40,12 +40,7 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrPipeline& pipeline, // uniforms, varyings, textures, etc GrGLProgramBuilder builder(gpu, pipeline, primProc, desc); - // TODO: Once all stages can handle taking a float or vec4 and correctly handling them we can - // seed correctly here - GrGLSLExpr4 inputColor; - GrGLSLExpr4 inputCoverage; - - if (!builder.emitAndInstallProcs(&inputColor, &inputCoverage)) { + if (!builder.emitAndInstallProcs()) { builder.cleanupFragmentProcessors(); return nullptr; } diff --git a/src/gpu/glsl/GrGLSL.cpp b/src/gpu/glsl/GrGLSL.cpp index d54ddee..76ffb82 100644 --- a/src/gpu/glsl/GrGLSL.cpp +++ b/src/gpu/glsl/GrGLSL.cpp @@ -45,15 +45,3 @@ void GrGLSLAppendDefaultFloatPrecisionDeclaration(GrSLPrecision p, } } } - -void GrGLSLMulVarBy4f(SkString* outAppend, const char* vec4VarName, const GrGLSLExpr4& mulFactor) { - if (mulFactor.isOnes()) { - *outAppend = SkString(); - } - - if (mulFactor.isZeros()) { - outAppend->appendf("%s = vec4(0);", vec4VarName); - } else { - outAppend->appendf("%s *= %s;", vec4VarName, mulFactor.c_str()); - } -} diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp index a779acc..4000b18 100644 --- a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp +++ b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp @@ -26,7 +26,6 @@ void GrGLSLFragmentProcessor::emitChild(int childIndex, const char* inputColor, void GrGLSLFragmentProcessor::emitChild(int childIndex, const char* inputColor, SkString* outputColor, EmitArgs& args) { - SkASSERT(outputColor); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; outputColor->append(fragBuilder->getMangleString()); @@ -36,6 +35,7 @@ void GrGLSLFragmentProcessor::emitChild(int childIndex, const char* inputColor, void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inputColor, const char* outputColor, EmitArgs& args) { + SkASSERT(inputColor); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->onBeforeChildProcEmitCode(); // call first so mangleString is updated diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.h b/src/gpu/glsl/GrGLSLFragmentProcessor.h index 1cf0d1d..05b3c06 100644 --- a/src/gpu/glsl/GrGLSLFragmentProcessor.h +++ b/src/gpu/glsl/GrGLSLFragmentProcessor.h @@ -156,6 +156,10 @@ public: return fChildProcessors[index]; } + inline void emitChild(int childIndex, SkString* outputColor, EmitArgs& parentArgs) { + this->emitChild(childIndex, "vec4(1.0)", outputColor, parentArgs); + } + /** Will emit the code of a child proc in its own scope. Pass in the parent's EmitArgs and * emitChild will automatically extract the coords and samplers of that child and pass them * on to the child's emitCode(). Also, any uniforms or functions emitted by the child will @@ -167,6 +171,10 @@ public: void emitChild(int childIndex, const char* inputColor, SkString* outputColor, EmitArgs& parentArgs); + inline void emitChild(int childIndex, EmitArgs& args) { + this->emitChild(childIndex, "vec4(1.0)", args); + } + /** Variation that uses the parent's output color variable to hold the child's output.*/ void emitChild(int childIndex, const char* inputColor, EmitArgs& parentArgs); diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp index 12e7ca2..3094f19 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp +++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp @@ -53,24 +53,24 @@ void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders, } } -bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, - GrGLSLExpr4* inputCoverage) { +bool GrGLSLProgramBuilder::emitAndInstallProcs() { // First we loop over all of the installed processors and collect coord transforms. These will // be sent to the GrGLSLPrimitiveProcessor in its emitCode function const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); - this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage); - - this->emitAndInstallFragProcs(inputColor, inputCoverage); - this->emitAndInstallXferProc(*inputColor, *inputCoverage); + SkString inputColor; + SkString inputCoverage; + this->emitAndInstallPrimProc(primProc, &inputColor, &inputCoverage); + this->emitAndInstallFragProcs(&inputColor, &inputCoverage); + this->emitAndInstallXferProc(inputColor, inputCoverage); this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput()); return this->checkSamplerCounts() && this->checkImageStorageCounts(); } void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc, - GrGLSLExpr4* outputColor, - GrGLSLExpr4* outputCoverage) { + SkString* outputColor, + SkString* outputCoverage) { // Program builders have a bit of state we need to clear with each effect AutoStageAdvance adv(this); this->nameExpression(outputColor, "outputColor"); @@ -139,16 +139,16 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr fFS.codeAppend("}"); } -void GrGLSLProgramBuilder::emitAndInstallFragProcs(GrGLSLExpr4* color, GrGLSLExpr4* coverage) { +void GrGLSLProgramBuilder::emitAndInstallFragProcs(SkString* color, SkString* coverage) { int transformedCoordVarsIdx = 0; - GrGLSLExpr4** inOut = &color; + SkString** inOut = &color; for (int i = 0; i < this->pipeline().numFragmentProcessors(); ++i) { if (i == this->pipeline().numColorFragmentProcessors()) { inOut = &coverage; } - GrGLSLExpr4 output; + SkString output; const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i); - this->emitAndInstallFragProc(fp, i, transformedCoordVarsIdx, **inOut, &output); + output = this->emitAndInstallFragProc(fp, i, transformedCoordVarsIdx, **inOut, output); GrFragmentProcessor::Iter iter(&fp); while (const GrFragmentProcessor* fp = iter.next()) { transformedCoordVarsIdx += fp->numCoordTransforms(); @@ -158,15 +158,16 @@ void GrGLSLProgramBuilder::emitAndInstallFragProcs(GrGLSLExpr4* color, GrGLSLExp } // TODO Processors cannot output zeros because an empty string is all 1s -// the fix is to allow effects to take the GrGLSLExpr4 directly -void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp, - int index, - int transformedCoordVarsIdx, - const GrGLSLExpr4& input, - GrGLSLExpr4* output) { +// the fix is to allow effects to take the SkString directly +SkString GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp, + int index, + int transformedCoordVarsIdx, + const SkString& input, + SkString output) { + SkASSERT(input.size()); // Program builders have a bit of state we need to clear with each effect AutoStageAdvance adv(this); - this->nameExpression(output, "output"); + this->nameExpression(&output, "output"); // Enclose custom code in a block to avoid namespace conflicts SkString openBrace; @@ -193,8 +194,8 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp, this->uniformHandler(), this->shaderCaps(), fp, - output->c_str(), - input.isOnes() ? nullptr : input.c_str(), + output.c_str(), + input.c_str(), coords, textureSamplers, bufferSamplers, @@ -209,10 +210,11 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp, fFragmentProcessors.push_back(fragProc); fFS.codeAppend("}"); + return output; } -void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrGLSLExpr4& colorIn, - const GrGLSLExpr4& coverageIn) { +void GrGLSLProgramBuilder::emitAndInstallXferProc(const SkString& colorIn, + const SkString& coverageIn) { // Program builders have a bit of state we need to clear with each effect AutoStageAdvance adv(this); @@ -249,8 +251,8 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrGLSLExpr4& colorIn, this->uniformHandler(), this->shaderCaps(), xp, - colorIn.c_str(), - coverageIn.c_str(), + colorIn.size() ? colorIn.c_str() : "vec4(1)", + coverageIn.size() ? coverageIn.c_str() : "vec4(1)", fFS.getPrimaryColorOutputName(), fFS.getSecondaryColorOutputName(), dstTextureSamplerHandle, @@ -445,12 +447,12 @@ void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* } } -void GrGLSLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) { +void GrGLSLProgramBuilder::nameExpression(SkString* output, const char* baseName) { // create var to hold stage result. If we already have a valid output name, just use that // otherwise create a new mangled one. This name is only valid if we are reordering stages // and have to tell stage exactly where to put its output. SkString outName; - if (output->isValid()) { + if (output->size()) { outName = output->c_str(); } else { this->nameVariable(&outName, '\0', baseName); diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h index 147eb98..4b1957e 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.h +++ b/src/gpu/glsl/GrGLSLProgramBuilder.h @@ -22,7 +22,7 @@ class GrShaderVar; class GrGLSLVaryingHandler; -class GrGLSLExpr4; +class SkString; class GrShaderCaps; typedef SkSTArray<8, GrGLSLFragmentProcessor*, true> GrGLSLFragProcs; @@ -110,7 +110,7 @@ protected: void addFeature(GrShaderFlags shaders, uint32_t featureBit, const char* extensionName); - bool emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage); + bool emitAndInstallProcs(); void cleanupFragmentProcessors(); @@ -140,19 +140,18 @@ private: }; // Generates a possibly mangled name for a stage variable and writes it to the fragment shader. - // If GrGLSLExpr4 has a valid name then it will use that instead - void nameExpression(GrGLSLExpr4*, const char* baseName); + void nameExpression(SkString*, const char* baseName); void emitAndInstallPrimProc(const GrPrimitiveProcessor&, - GrGLSLExpr4* outputColor, - GrGLSLExpr4* outputCoverage); - void emitAndInstallFragProcs(GrGLSLExpr4* colorInOut, GrGLSLExpr4* coverageInOut); - void emitAndInstallFragProc(const GrFragmentProcessor&, - int index, - int transformedCoordVarsIdx, - const GrGLSLExpr4& input, - GrGLSLExpr4* output); - void emitAndInstallXferProc(const GrGLSLExpr4& colorIn, const GrGLSLExpr4& coverageIn); + SkString* outputColor, + SkString* outputCoverage); + void emitAndInstallFragProcs(SkString* colorInOut, SkString* coverageInOut); + SkString emitAndInstallFragProc(const GrFragmentProcessor&, + int index, + int transformedCoordVarsIdx, + const SkString& input, + SkString output); + void emitAndInstallXferProc(const SkString& colorIn, const SkString& coverageIn); void emitSamplersAndImageStorages(const GrResourceIOProcessor& processor, SkTArray* outTexSamplerHandles, SkTArray* outBufferSamplerHandles, diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.cpp b/src/gpu/glsl/GrGLSLShaderBuilder.cpp index 2c7e5e4..1a681b5 100644 --- a/src/gpu/glsl/GrGLSLShaderBuilder.cpp +++ b/src/gpu/glsl/GrGLSLShaderBuilder.cpp @@ -101,9 +101,17 @@ void GrGLSLShaderBuilder::appendTextureLookupAndModulate( if (colorXformHelper && colorXformHelper->isValid()) { SkString xform; this->appendColorGamutXform(&xform, lookup.c_str(), colorXformHelper); - this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(xform)).c_str()); + if (modulation) { + this->codeAppendf("%s * %s", modulation, xform.c_str()); + } else { + this->codeAppendf("%s", xform.c_str()); + } } else { - this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str()); + if (modulation) { + this->codeAppendf("%s * %s", modulation, lookup.c_str()); + } else { + this->codeAppendf("%s", lookup.c_str()); + } } } diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp index ea0aa75..2e81fc2 100644 --- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp +++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp @@ -25,10 +25,7 @@ GrVkPipelineState* GrVkPipelineStateBuilder::CreatePipelineState( // uniforms, varyings, textures, etc GrVkPipelineStateBuilder builder(gpu, pipeline, primProc, desc); - GrGLSLExpr4 inputColor; - GrGLSLExpr4 inputCoverage; - - if (!builder.emitAndInstallProcs(&inputColor, &inputCoverage)) { + if (!builder.emitAndInstallProcs()) { builder.cleanupFragmentProcessors(); return nullptr; } diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp index 25cd312..6e9bef9 100644 --- a/tests/GLProgramsTest.cpp +++ b/tests/GLProgramsTest.cpp @@ -113,7 +113,7 @@ private: class GLFP : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs& args) override { - this->emitChild(0, nullptr, args); + this->emitChild(0, args); } private: