Avoid multiplication by alpha in fragment shader when known to be 1.
Implemented for image shaders, image draws, and gradient shaders.
Reimplement GrFragmentProcessor::OverrideInput as GrOverrideInputFragmentProcessor.fp.
It allows specification of whether the replacement input color should be
a literal in the shader code or a uniform. For above use case use with literal white.
Make key in variables in fp files work for 4f colors.
Fix issue in CPP code gen from .fp where when + key vars that pushed multiple values
into the shader key only skipped the first key value when the when condition is not
true.
Bug: skia:7722
Change-Id: Id7c865132d620e8cdea8b00f2a627103eef171ac
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/201985
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
diff --git a/src/gpu/effects/GrMixerEffect.fp b/src/gpu/effects/GrMixerEffect.fp
index cb0c979..9b6acf7 100644
--- a/src/gpu/effects/GrMixerEffect.fp
+++ b/src/gpu/effects/GrMixerEffect.fp
@@ -15,27 +15,11 @@
static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp0,
const std::unique_ptr<GrFragmentProcessor>& fp1) {
- auto get_flags = [](const std::unique_ptr<GrFragmentProcessor>& fp) {
- auto flags = kNone_OptimizationFlags;
-
- if (fp->compatibleWithCoverageAsAlpha()) {
- flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
- }
-
- if (fp->preservesOpaqueInput()) {
- flags |= kPreservesOpaqueInput_OptimizationFlag;
- }
-
- if (fp->hasConstantOutputForConstantInput()) {
- flags |= kConstantOutputForConstantInput_OptimizationFlag;
- }
-
- return flags;
- };
-
- const auto fp0_flags = get_flags(fp0);
-
- return fp1 ? (fp0_flags & get_flags(fp1)) : fp0_flags;
+ auto flags = ProcessorOptimizationFlags(fp0.get());
+ if (fp1) {
+ flags &= ProcessorOptimizationFlags(fp1.get());
+ }
+ return flags;
}
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
diff --git a/src/gpu/effects/GrOverrideInputFragmentProcessor.fp b/src/gpu/effects/GrOverrideInputFragmentProcessor.fp
new file mode 100644
index 0000000..9f7ee9e
--- /dev/null
+++ b/src/gpu/effects/GrOverrideInputFragmentProcessor.fp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// Ignores its own input color and invokes 'fp' with a constant color
+// The constant color can either be specified as a literal or as a
+// uniform, controlled by useUniform.
+
+in fragmentProcessor fp;
+layout(key) in bool useUniform;
+layout(when=useUniform, ctype=SkPMColor4f) in uniform half4 uniformColor;
+layout(when=!useUniform, key, ctype=SkPMColor4f) in half4 literalColor;
+
+@make {
+ static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
+ const SkPMColor4f& color,
+ bool useUniform = true) {
+ return std::unique_ptr<GrFragmentProcessor>(
+ new GrOverrideInputFragmentProcessor(std::move(fp), useUniform, color, color));
+ }
+}
+
+@class {
+ static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp,
+ const SkPMColor4f& color) {
+ auto childFlags = ProcessorOptimizationFlags(fp.get());
+ auto flags = kNone_OptimizationFlags;
+ if (childFlags & kConstantOutputForConstantInput_OptimizationFlag) {
+ flags |= kConstantOutputForConstantInput_OptimizationFlag;
+ }
+ if ((childFlags & kPreservesOpaqueInput_OptimizationFlag) && color.isOpaque()) {
+ flags |= kPreservesOpaqueInput_OptimizationFlag;
+ }
+ return flags;
+ }
+
+ SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
+ return ConstantOutputForConstantInput(this->childProcessor(0), uniformColor);
+ }
+}
+
+@optimizationFlags { OptFlags(fp, useUniform ? uniformColor : literalColor) }
+
+void main() {
+ half4 constColor;
+ @if(useUniform) {
+ constColor = uniformColor;
+ } else {
+ constColor = literalColor;
+ }
+ sk_OutColor = process(fp, constColor);
+}
diff --git a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
index e3064bf..b5730fb 100644
--- a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
+++ b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
@@ -326,17 +326,8 @@
case SkBlendMode::kSrcIn:
case SkBlendMode::kDstIn:
case SkBlendMode::kModulate:
- if (fp->compatibleWithCoverageAsAlpha()) {
- if (fp->preservesOpaqueInput()) {
- flags = kPreservesOpaqueInput_OptimizationFlag |
- kCompatibleWithCoverageAsAlpha_OptimizationFlag;
- } else {
- flags = kCompatibleWithCoverageAsAlpha_OptimizationFlag;
- }
- } else {
- flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
- : kNone_OptimizationFlags;
- }
+ flags = ProcessorOptimizationFlags(fp) &
+ ~kConstantOutputForConstantInput_OptimizationFlag;
break;
// Produces zero when both are opaque, indeterminate if one is opaque.
diff --git a/src/gpu/effects/generated/GrMixerEffect.h b/src/gpu/effects/generated/GrMixerEffect.h
index d318285..4c30fba 100644
--- a/src/gpu/effects/generated/GrMixerEffect.h
+++ b/src/gpu/effects/generated/GrMixerEffect.h
@@ -17,27 +17,11 @@
public:
static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp0,
const std::unique_ptr<GrFragmentProcessor>& fp1) {
- auto get_flags = [](const std::unique_ptr<GrFragmentProcessor>& fp) {
- auto flags = kNone_OptimizationFlags;
-
- if (fp->compatibleWithCoverageAsAlpha()) {
- flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
- }
-
- if (fp->preservesOpaqueInput()) {
- flags |= kPreservesOpaqueInput_OptimizationFlag;
- }
-
- if (fp->hasConstantOutputForConstantInput()) {
- flags |= kConstantOutputForConstantInput_OptimizationFlag;
- }
-
- return flags;
- };
-
- const auto fp0_flags = get_flags(fp0);
-
- return fp1 ? (fp0_flags & get_flags(fp1)) : fp0_flags;
+ auto flags = ProcessorOptimizationFlags(fp0.get());
+ if (fp1) {
+ flags &= ProcessorOptimizationFlags(fp1.get());
+ }
+ return flags;
}
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
diff --git a/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp b/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp
new file mode 100644
index 0000000..c3d2d27
--- /dev/null
+++ b/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2019 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 GrOverrideInputFragmentProcessor.fp; do not modify.
+ **************************************************************************************************/
+#include "GrOverrideInputFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLOverrideInputFragmentProcessor : public GrGLSLFragmentProcessor {
+public:
+ GrGLSLOverrideInputFragmentProcessor() {}
+ void emitCode(EmitArgs& args) override {
+ GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+ const GrOverrideInputFragmentProcessor& _outer =
+ args.fFp.cast<GrOverrideInputFragmentProcessor>();
+ (void)_outer;
+ auto useUniform = _outer.useUniform;
+ (void)useUniform;
+ auto uniformColor = _outer.uniformColor;
+ (void)uniformColor;
+ auto literalColor = _outer.literalColor;
+ (void)literalColor;
+ if (useUniform) {
+ uniformColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
+ kHalf4_GrSLType, "uniformColor");
+ }
+ fragBuilder->codeAppendf(
+ "half4 constColor;\n@if (%s) {\n constColor = %s;\n} else {\n constColor = "
+ "half4(%f, %f, %f, %f);\n}",
+ (_outer.useUniform ? "true" : "false"),
+ uniformColorVar.isValid() ? args.fUniformHandler->getUniformCStr(uniformColorVar)
+ : "half4(0)",
+ _outer.literalColor.fR, _outer.literalColor.fG, _outer.literalColor.fB,
+ _outer.literalColor.fA);
+ SkString _input0("constColor");
+ SkString _child0("_child0");
+ this->emitChild(_outer.fp_index, _input0.c_str(), &_child0, args);
+ fragBuilder->codeAppendf("\n%s = %s;\n", args.fOutputColor, _child0.c_str());
+ }
+
+private:
+ void onSetData(const GrGLSLProgramDataManager& pdman,
+ const GrFragmentProcessor& _proc) override {
+ const GrOverrideInputFragmentProcessor& _outer =
+ _proc.cast<GrOverrideInputFragmentProcessor>();
+ {
+ if (uniformColorVar.isValid()) {
+ pdman.set4fv(uniformColorVar, 1, (_outer.uniformColor).vec());
+ }
+ }
+ }
+ UniformHandle uniformColorVar;
+};
+GrGLSLFragmentProcessor* GrOverrideInputFragmentProcessor::onCreateGLSLInstance() const {
+ return new GrGLSLOverrideInputFragmentProcessor();
+}
+void GrOverrideInputFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+ GrProcessorKeyBuilder* b) const {
+ b->add32((int32_t)useUniform);
+ if (!useUniform) {
+ uint16_t red = SkFloatToHalf(literalColor.fR);
+ uint16_t green = SkFloatToHalf(literalColor.fG);
+ uint16_t blue = SkFloatToHalf(literalColor.fB);
+ uint16_t alpha = SkFloatToHalf(literalColor.fA);
+ b->add32(((uint32_t)red << 16) | green);
+ b->add32(((uint32_t)blue << 16) | alpha);
+ }
+}
+bool GrOverrideInputFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const {
+ const GrOverrideInputFragmentProcessor& that = other.cast<GrOverrideInputFragmentProcessor>();
+ (void)that;
+ if (useUniform != that.useUniform) return false;
+ if (uniformColor != that.uniformColor) return false;
+ if (literalColor != that.literalColor) return false;
+ return true;
+}
+GrOverrideInputFragmentProcessor::GrOverrideInputFragmentProcessor(
+ const GrOverrideInputFragmentProcessor& src)
+ : INHERITED(kGrOverrideInputFragmentProcessor_ClassID, src.optimizationFlags())
+ , fp_index(src.fp_index)
+ , useUniform(src.useUniform)
+ , uniformColor(src.uniformColor)
+ , literalColor(src.literalColor) {
+ this->registerChildProcessor(src.childProcessor(fp_index).clone());
+}
+std::unique_ptr<GrFragmentProcessor> GrOverrideInputFragmentProcessor::clone() const {
+ return std::unique_ptr<GrFragmentProcessor>(new GrOverrideInputFragmentProcessor(*this));
+}
diff --git a/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h b/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h
new file mode 100644
index 0000000..d7cacee
--- /dev/null
+++ b/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019 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 GrOverrideInputFragmentProcessor.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrOverrideInputFragmentProcessor_DEFINED
+#define GrOverrideInputFragmentProcessor_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrOverrideInputFragmentProcessor : public GrFragmentProcessor {
+public:
+ static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp,
+ const SkPMColor4f& color) {
+ auto childFlags = ProcessorOptimizationFlags(fp.get());
+ auto flags = kNone_OptimizationFlags;
+ if (childFlags & kConstantOutputForConstantInput_OptimizationFlag) {
+ flags |= kConstantOutputForConstantInput_OptimizationFlag;
+ }
+ if ((childFlags & kPreservesOpaqueInput_OptimizationFlag) && color.isOpaque()) {
+ flags |= kPreservesOpaqueInput_OptimizationFlag;
+ }
+ return flags;
+ }
+
+ SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
+ return ConstantOutputForConstantInput(this->childProcessor(0), uniformColor);
+ }
+
+ static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
+ const SkPMColor4f& color,
+ bool useUniform = true) {
+ return std::unique_ptr<GrFragmentProcessor>(
+ new GrOverrideInputFragmentProcessor(std::move(fp), useUniform, color, color));
+ }
+ GrOverrideInputFragmentProcessor(const GrOverrideInputFragmentProcessor& src);
+ std::unique_ptr<GrFragmentProcessor> clone() const override;
+ const char* name() const override { return "OverrideInputFragmentProcessor"; }
+ int fp_index = -1;
+ bool useUniform;
+ SkPMColor4f uniformColor;
+ SkPMColor4f literalColor;
+
+private:
+ GrOverrideInputFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp,
+ bool useUniform,
+ SkPMColor4f uniformColor,
+ SkPMColor4f literalColor)
+ : INHERITED(kGrOverrideInputFragmentProcessor_ClassID,
+ (OptimizationFlags)OptFlags(fp, useUniform ? uniformColor : literalColor))
+ , useUniform(useUniform)
+ , uniformColor(uniformColor)
+ , literalColor(literalColor) {
+ SkASSERT(fp);
+ fp_index = this->numChildProcessors();
+ this->registerChildProcessor(std::move(fp));
+ }
+ GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+ void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+ bool onIsEqual(const GrFragmentProcessor&) const override;
+ GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+ typedef GrFragmentProcessor INHERITED;
+};
+#endif