Reland "Base Gradient FP Refactor"

This reverts commit 1ea5656a28.

Reason for revert: Fixed google3 build failure

Original change's description:
> Revert "Base Gradient FP Refactor"
> 
> This reverts commit 10f7a1e075.
> 
> Reason for revert: broke google3 roll
> Original change's description:
> > Base Gradient FP Refactor
> > 
> > --
> > 
> > Redefines how gradients will be written in the GPU back-end:
> > 
> > They are split into three fragment processor components: master, layout, and colorizer.
> > The layout FP is responsible for converting the fragment position into an interpolant value, t.
> > Each high-level gradient--such as linear, radial, etc.--are implemented solely in a layout FP.
> > The colorizer FP is responsible for converting t into a color.
> > The master FP invokes the layout, clamps t into the proper domain, and then invokes the colorizer.
> > GrGradientShader provides factory functions to create FP graphs from SkGradientShader instances.
> > This pattern is documented in gpu/gradients/README.md.
> > 
> > Goals for current CL
> > ====================
> > 
> > Outline the FP components by providing .fp implementations for the simplest gradients.
> > Defines a two-color single interval colorizer and a linear gradient layout, and the master effect.
> > A MakeLinear() factory function is provided that can convert SkGradientShaders that fit these constraints.
> > SkLinearGradient first attempts to use the new system, falling back to the original GrGradientEffect.
> > 
> > Future CLs
> > ==========
> > 
> > To keep the CL reviews manageable, additional dependent CLs will be added that gradually replace past functionality.
> > A CL for each layout will be defined.
> > CLs for the different analytic colorizer cases and the textured gradient case will be defined.
> > Once the new system supports all current layouts and colorizer capabilities, all old GPU gradient code will be removed.
> > After this clean-up, analytic colorization can hopefully be expanded to reduce the usage of textured gradients.
> > 
> > Bug: skia:
> > Change-Id: Iafe7b8b4071491a71c473babcd7bedda659150c1
> > Reviewed-on: https://skia-review.googlesource.com/148120
> > Commit-Queue: Michael Ludwig <michaelludwig@google.com>
> > Reviewed-by: Brian Salomon <bsalomon@google.com>
> 
> TBR=bsalomon@google.com,michaelludwig@google.com
> 
> Change-Id: Ib735e323795ac8874cb00b007a915786b50517a6
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: skia:
> Reviewed-on: https://skia-review.googlesource.com/153600
> Reviewed-by: Cary Clark <caryclark@google.com>
> Commit-Queue: Cary Clark <caryclark@google.com>

TBR=bsalomon@google.com,caryclark@google.com,michaelludwig@google.com

Change-Id: Ibf6ffbcb1af0dfbdac7317151aeb08f18f84c7fd
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/153887
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
Michael Ludwig 2018-09-12 15:22:16 -04:00 committed by Skia Commit-Bot
parent b98fb5b082
commit 4f94ef6cbd
24 changed files with 835 additions and 1 deletions

View File

@ -400,6 +400,18 @@ skia_gpu_sources = [
"$_src/gpu/effects/GrYUVtoRGBEffect.cpp",
"$_src/gpu/effects/GrYUVtoRGBEffect.h",
# gradients
"$_src/gpu/gradients/GrSingleIntervalGradientColorizer.cpp",
"$_src/gpu/gradients/GrSingleIntervalGradientColorizer.h",
"$_src/gpu/gradients/GrLinearGradientLayout.cpp",
"$_src/gpu/gradients/GrLinearGradientLayout.h",
"$_src/gpu/gradients/GrClampedGradientEffect.cpp",
"$_src/gpu/gradients/GrClampedGradientEffect.h",
"$_src/gpu/gradients/GrTiledGradientEffect.cpp",
"$_src/gpu/gradients/GrTiledGradientEffect.h",
"$_src/gpu/gradients/GrGradientShader.cpp",
"$_src/gpu/gradients/GrGradientShader.h",
# text
"$_src/gpu/text/GrAtlasManager.cpp",
"$_src/gpu/text/GrAtlasManager.h",

View File

@ -46,4 +46,8 @@ skia_gpu_processor_sources = [
"$_src/gpu/effects/GrSimpleTextureEffect.fp",
"$_src/gpu/effects/GrUnpremulInputFragmentProcessor.fp",
"$_src/gpu/effects/GrYUVtoRGBEffect.fp",
"$_src/gpu/gradients/GrSingleIntervalGradientColorizer.fp",
"$_src/gpu/gradients/GrLinearGradientLayout.fp",
"$_src/gpu/gradients/GrClampedGradientEffect.fp",
"$_src/gpu/gradients/GrTiledGradientEffect.fp",
]

View File

@ -418,6 +418,7 @@ INCLUDES = [
"src/ports",
"src/sfnt",
"src/shaders",
"src/shaders/gradients",
"src/sksl",
"src/utils",
"third_party/gif",

View File

@ -95,6 +95,7 @@ public:
kGrCCPathProcessor_ClassID,
kGrCircleBlurFragmentProcessor_ClassID,
kGrCircleEffect_ClassID,
kGrClampedGradientEffect_ClassID,
kGrColorSpaceXformEffect_ClassID,
kGrConfigConversionEffect_ClassID,
kGrConicEffect_ClassID,
@ -113,6 +114,7 @@ public:
kGrImprovedPerlinNoiseEffect_ClassID,
kGrLightingEffect_ClassID,
kGrLinearGradient_ClassID,
kGrLinearGradientLayout_ClassID,
kGrLumaColorFilterEffect_ClassID,
kGrMagnifierEffect_ClassID,
kGrMatrixConvolutionEffect_ClassID,
@ -129,11 +131,13 @@ public:
kGrRRectBlurEffect_ClassID,
kGrRRectShadowGeoProc_ClassID,
kGrSimpleTextureEffect_ClassID,
kGrSingleIntervalGradientColorizer_ClassID,
kGrSkSLFP_ClassID,
kGrSpecularLightingEffect_ClassID,
kGrSRGBEffect_ClassID,
kGrSweepGradient_ClassID,
kGrTextureDomainEffect_ClassID,
kGrTiledGradientEffect_ClassID,
kGrUnpremulInputFragmentProcessor_ClassID,
kGrYUVtoRGBEffect_ClassID,
kHighContrastFilterEffect_ClassID,

View File

@ -0,0 +1,91 @@
/*
* Copyright 2018 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 GrClampedGradientEffect.fp; do not modify.
**************************************************************************************************/
#include "GrClampedGradientEffect.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLProgramBuilder.h"
#include "GrTexture.h"
#include "SkSLCPP.h"
#include "SkSLUtil.h"
class GrGLSLClampedGradientEffect : public GrGLSLFragmentProcessor {
public:
GrGLSLClampedGradientEffect() {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
const GrClampedGradientEffect& _outer = args.fFp.cast<GrClampedGradientEffect>();
(void)_outer;
auto leftBorderColor = _outer.leftBorderColor();
(void)leftBorderColor;
auto rightBorderColor = _outer.rightBorderColor();
(void)rightBorderColor;
fLeftBorderColorVar = args.fUniformHandler->addUniform(
kFragment_GrShaderFlag, kHalf4_GrSLType, kDefault_GrSLPrecision, "leftBorderColor");
fRightBorderColorVar =
args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType,
kDefault_GrSLPrecision, "rightBorderColor");
SkString _child1("_child1");
this->emitChild(1, &_child1, args);
fragBuilder->codeAppendf(
"half4 t = %s;\nif (t.x < 0.0) {\n %s = %s;\n} else if (float(t.x) > 1.0) {\n "
" %s = %s;\n} else {",
_child1.c_str(), args.fOutputColor,
args.fUniformHandler->getUniformCStr(fLeftBorderColorVar), args.fOutputColor,
args.fUniformHandler->getUniformCStr(fRightBorderColorVar));
SkString _input0("t");
SkString _child0("_child0");
this->emitChild(0, _input0.c_str(), &_child0, args);
fragBuilder->codeAppendf("\n %s = %s;\n}\n", args.fOutputColor, _child0.c_str());
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {
const GrClampedGradientEffect& _outer = _proc.cast<GrClampedGradientEffect>();
{
const GrColor4f& leftBorderColorValue = _outer.leftBorderColor();
if (fLeftBorderColorPrev != leftBorderColorValue) {
fLeftBorderColorPrev = leftBorderColorValue;
pdman.set4fv(fLeftBorderColorVar, 1, leftBorderColorValue.fRGBA);
}
const GrColor4f& rightBorderColorValue = _outer.rightBorderColor();
if (fRightBorderColorPrev != rightBorderColorValue) {
fRightBorderColorPrev = rightBorderColorValue;
pdman.set4fv(fRightBorderColorVar, 1, rightBorderColorValue.fRGBA);
}
}
}
GrColor4f fLeftBorderColorPrev = GrColor4f::kIllegalConstructor;
GrColor4f fRightBorderColorPrev = GrColor4f::kIllegalConstructor;
UniformHandle fLeftBorderColorVar;
UniformHandle fRightBorderColorVar;
};
GrGLSLFragmentProcessor* GrClampedGradientEffect::onCreateGLSLInstance() const {
return new GrGLSLClampedGradientEffect();
}
void GrClampedGradientEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {}
bool GrClampedGradientEffect::onIsEqual(const GrFragmentProcessor& other) const {
const GrClampedGradientEffect& that = other.cast<GrClampedGradientEffect>();
(void)that;
if (fLeftBorderColor != that.fLeftBorderColor) return false;
if (fRightBorderColor != that.fRightBorderColor) return false;
return true;
}
GrClampedGradientEffect::GrClampedGradientEffect(const GrClampedGradientEffect& src)
: INHERITED(kGrClampedGradientEffect_ClassID, src.optimizationFlags())
, fLeftBorderColor(src.fLeftBorderColor)
, fRightBorderColor(src.fRightBorderColor) {
this->registerChildProcessor(src.childProcessor(0).clone());
this->registerChildProcessor(src.childProcessor(1).clone());
}
std::unique_ptr<GrFragmentProcessor> GrClampedGradientEffect::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrClampedGradientEffect(*this));
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
// This master effect implements clamping on the layout coordinate and requires specifying the
// border colors that are used when outside the clamped boundary. Gradients with the
// SkShader::kClamp_TileMode should use the colors at their first and last stop (after adding dummy
// stops for t=0,t=1) as the border color. This will automatically replicate the edge color, even if
// when there is a hard stop.
//
// The SkShader::kDecal_TileMode can be produced by specifying transparent black as the border
// colors, regardless of the gradient's stop colors.
in fragmentProcessor colorizer;
in fragmentProcessor gradLayout;
layout(ctype=GrColor4f, tracked) in uniform half4 leftBorderColor; // t < 0.0
layout(ctype=GrColor4f, tracked) in uniform half4 rightBorderColor; // t > 1.0
void main() {
half4 t = process(gradLayout);
// If t.x is below 0, use the left border color without invoking the child processor. If any t.x
// is above 1, use the right border color. Otherwise, t is in the [0, 1] range assumed by the
// colorizer FP, so delegate to the child processor.
if (t.x < 0) {
sk_OutColor = leftBorderColor;
} else if (t.x > 1.0) {
sk_OutColor = rightBorderColor;
} else {
sk_OutColor = process(colorizer, t);
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright 2018 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 GrClampedGradientEffect.fp; do not modify.
**************************************************************************************************/
#ifndef GrClampedGradientEffect_DEFINED
#define GrClampedGradientEffect_DEFINED
#include "SkTypes.h"
#include "GrFragmentProcessor.h"
#include "GrCoordTransform.h"
class GrClampedGradientEffect : public GrFragmentProcessor {
public:
const GrColor4f& leftBorderColor() const { return fLeftBorderColor; }
const GrColor4f& rightBorderColor() const { return fRightBorderColor; }
static std::unique_ptr<GrFragmentProcessor> Make(
std::unique_ptr<GrFragmentProcessor> colorizer,
std::unique_ptr<GrFragmentProcessor> gradLayout, GrColor4f leftBorderColor,
GrColor4f rightBorderColor) {
return std::unique_ptr<GrFragmentProcessor>(new GrClampedGradientEffect(
std::move(colorizer), std::move(gradLayout), leftBorderColor, rightBorderColor));
}
GrClampedGradientEffect(const GrClampedGradientEffect& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "ClampedGradientEffect"; }
private:
GrClampedGradientEffect(std::unique_ptr<GrFragmentProcessor> colorizer,
std::unique_ptr<GrFragmentProcessor> gradLayout,
GrColor4f leftBorderColor, GrColor4f rightBorderColor)
: INHERITED(kGrClampedGradientEffect_ClassID, kNone_OptimizationFlags)
, fLeftBorderColor(leftBorderColor)
, fRightBorderColor(rightBorderColor) {
this->registerChildProcessor(std::move(colorizer));
this->registerChildProcessor(std::move(gradLayout));
}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
GrColor4f fLeftBorderColor;
GrColor4f fRightBorderColor;
typedef GrFragmentProcessor INHERITED;
};
#endif

View File

@ -0,0 +1,133 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrGradientShader.h"
#include "GrClampedGradientEffect.h"
#include "GrTiledGradientEffect.h"
#include "GrLinearGradientLayout.h"
#include "GrSingleIntervalGradientColorizer.h"
#include "SkGradientShaderPriv.h"
#include "GrColor.h"
// Analyze the shader's color stops and positions and chooses an appropriate colorizer to represent
// the gradient.
static std::unique_ptr<GrFragmentProcessor> make_colorizer(const SkGradientShaderBase& shader,
const GrFPArgs& args, const GrColor4f* colors) {
// If there are hard stops at the beginning or end, the first and/or last color should be
// ignored by the colorizer since it should only be used in a clamped border color. By detecting
// and removing these stops at the beginning, it makes optimizing the remaining color stops
// simpler.
// SkGradientShaderBase guarantees that fOrigPos[0] == 0 by adding a dummy
bool bottomHardStop = shader.fOrigPos && SkScalarNearlyEqual(shader.fOrigPos[0],
shader.fOrigPos[1]);
// The same is true for fOrigPos[end] == 1
bool topHardStop = shader.fOrigPos &&
SkScalarNearlyEqual(shader.fOrigPos[shader.fColorCount - 2],
shader.fOrigPos[shader.fColorCount - 1]);
int offset = 0;
int count = shader.fColorCount;
if (bottomHardStop) {
offset += 1;
count--;
}
if (topHardStop) {
count--;
}
// Currently only supports 2-color single intervals. However, when the gradient has hard stops
// and is clamped, certain 3 or 4 color gradients are equivalent to a two color interval
if (count == 2) {
return GrSingleIntervalGradientColorizer::Make(colors[offset], colors[offset + 1]);
}
return nullptr;
}
// Combines the colorizer and layout with an appropriately configured master effect based on the
// gradient's tile mode
static std::unique_ptr<GrFragmentProcessor> make_gradient(const SkGradientShaderBase& shader,
const GrFPArgs& args, std::unique_ptr<GrFragmentProcessor> layout) {
// No shader is possible if a layout couldn't be created, e.g. a layout-specific Make() returned
// null.
if (layout == nullptr) {
return nullptr;
}
// Convert all colors into destination space and into GrColor4fs, and handle
// premul issues depending on the interpolation mode
bool inputPremul = shader.getGradFlags() & SkGradientShader::kInterpolateColorsInPremul_Flag;
SkAutoSTMalloc<4, GrColor4f> colors(shader.fColorCount);
SkColor4fXformer xformedColors(shader.fOrigColors4f, shader.fColorCount,
shader.fColorSpace.get(), args.fDstColorSpaceInfo->colorSpace());
for (int i = 0; i < shader.fColorCount; i++) {
colors[i] = GrColor4f::FromSkColor4f(xformedColors.fColors[i]);
if (inputPremul) {
colors[i] = colors[i].premul();
}
}
// All gradients are colorized the same way, regardless of layout
std::unique_ptr<GrFragmentProcessor> colorizer = make_colorizer(shader, args, colors.get());
if (colorizer == nullptr) {
return nullptr;
}
// All tile modes are supported (unless something was added to SkShader)
std::unique_ptr<GrFragmentProcessor> master;
switch(shader.getTileMode()) {
case SkShader::kRepeat_TileMode:
master = GrTiledGradientEffect::Make(std::move(colorizer), std::move(layout),
/* mirror */ false);
break;
case SkShader::kMirror_TileMode:
master = GrTiledGradientEffect::Make(std::move(colorizer), std::move(layout),
/* mirror */ true);
break;
case SkShader::kClamp_TileMode:
// For the clamped mode, the border colors are the first and last colors, corresponding
// to t=0 and t=1, because SkGradientShaderBase enforces that by adding color stops as
// appropriate. If there is a hard stop, this grabs the expected outer colors for the
// border.
master = GrClampedGradientEffect::Make(std::move(colorizer), std::move(layout),
colors[0], colors[shader.fColorCount - 1]);
break;
case SkShader::kDecal_TileMode:
master = GrClampedGradientEffect::Make(std::move(colorizer), std::move(layout),
GrColor4f::TransparentBlack(),
GrColor4f::TransparentBlack());
break;
}
if (master == nullptr) {
// Unexpected tile mode
return nullptr;
}
if (!inputPremul) {
// When interpolating unpremul colors, the output of the gradient
// effect fp's will also be unpremul, so wrap it to ensure its premul.
// - this is unnecessary when interpolating premul colors since the
// output color is premul by nature
master = GrFragmentProcessor::PremulOutput(std::move(master));
}
return GrFragmentProcessor::MulChildByInputAlpha(std::move(master));
}
namespace GrGradientShader {
std::unique_ptr<GrFragmentProcessor> MakeLinear(const SkLinearGradient& shader,
const GrFPArgs& args) {
return make_gradient(shader, args, GrLinearGradientLayout::Make(shader, args));
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrGradientShader_DEFINE
#define GrGradientShader_DEFINE
#include "GrFPArgs.h"
#include "SkGradientShaderPriv.h"
#include "SkLinearGradient.h"
namespace GrGradientShader {
std::unique_ptr<GrFragmentProcessor> MakeLinear(const SkLinearGradient& shader,
const GrFPArgs& args);
}
#endif // GrGradientShader_DEFINE

View File

@ -0,0 +1,65 @@
/*
* Copyright 2018 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 GrLinearGradientLayout.fp; do not modify.
**************************************************************************************************/
#include "GrLinearGradientLayout.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLProgramBuilder.h"
#include "GrTexture.h"
#include "SkSLCPP.h"
#include "SkSLUtil.h"
class GrGLSLLinearGradientLayout : public GrGLSLFragmentProcessor {
public:
GrGLSLLinearGradientLayout() {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
const GrLinearGradientLayout& _outer = args.fFp.cast<GrLinearGradientLayout>();
(void)_outer;
auto gradientMatrix = _outer.gradientMatrix();
(void)gradientMatrix;
SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
fragBuilder->codeAppendf("%s = half4(half(%s.x));\n", args.fOutputColor,
sk_TransformedCoords2D_0.c_str());
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {}
};
GrGLSLFragmentProcessor* GrLinearGradientLayout::onCreateGLSLInstance() const {
return new GrGLSLLinearGradientLayout();
}
void GrLinearGradientLayout::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {}
bool GrLinearGradientLayout::onIsEqual(const GrFragmentProcessor& other) const {
const GrLinearGradientLayout& that = other.cast<GrLinearGradientLayout>();
(void)that;
if (fGradientMatrix != that.fGradientMatrix) return false;
return true;
}
GrLinearGradientLayout::GrLinearGradientLayout(const GrLinearGradientLayout& src)
: INHERITED(kGrLinearGradientLayout_ClassID, src.optimizationFlags())
, fGradientMatrix(src.fGradientMatrix)
, fCoordTransform0(src.fCoordTransform0) {
this->addCoordTransform(&fCoordTransform0);
}
std::unique_ptr<GrFragmentProcessor> GrLinearGradientLayout::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrLinearGradientLayout(*this));
}
std::unique_ptr<GrFragmentProcessor> GrLinearGradientLayout::Make(const SkLinearGradient& grad,
const GrFPArgs& args) {
SkMatrix matrix;
if (!grad.totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix)->invert(&matrix)) {
return nullptr;
}
matrix.postConcat(grad.getGradientMatrix());
return std::unique_ptr<GrFragmentProcessor>(new GrLinearGradientLayout(matrix));
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
in half4x4 gradientMatrix;
@coordTransform {
gradientMatrix
}
void main() {
sk_OutColor = half4(sk_TransformedCoords2D[0].x);
}
//////////////////////////////////////////////////////////////////////////////
@header {
#include "SkLinearGradient.h"
}
@make {
static std::unique_ptr<GrFragmentProcessor> Make(const SkLinearGradient& gradient,
const GrFPArgs& args);
}
@cppEnd {
std::unique_ptr<GrFragmentProcessor> GrLinearGradientLayout::Make(
const SkLinearGradient& grad, const GrFPArgs& args) {
SkMatrix matrix;
if (!grad.totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix)->invert(&matrix)) {
return nullptr;
}
matrix.postConcat(grad.getGradientMatrix());
return std::unique_ptr<GrFragmentProcessor>(new GrLinearGradientLayout(matrix));
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2018 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 GrLinearGradientLayout.fp; do not modify.
**************************************************************************************************/
#ifndef GrLinearGradientLayout_DEFINED
#define GrLinearGradientLayout_DEFINED
#include "SkTypes.h"
#include "SkLinearGradient.h"
#include "GrFragmentProcessor.h"
#include "GrCoordTransform.h"
class GrLinearGradientLayout : public GrFragmentProcessor {
public:
const SkMatrix44& gradientMatrix() const { return fGradientMatrix; }
static std::unique_ptr<GrFragmentProcessor> Make(const SkLinearGradient& gradient,
const GrFPArgs& args);
GrLinearGradientLayout(const GrLinearGradientLayout& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "LinearGradientLayout"; }
private:
GrLinearGradientLayout(SkMatrix44 gradientMatrix)
: INHERITED(kGrLinearGradientLayout_ClassID, kNone_OptimizationFlags)
, fGradientMatrix(gradientMatrix)
, fCoordTransform0(gradientMatrix) {
this->addCoordTransform(&fCoordTransform0);
}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
SkMatrix44 fGradientMatrix;
GrCoordTransform fCoordTransform0;
typedef GrFragmentProcessor INHERITED;
};
#endif

View File

@ -0,0 +1,82 @@
/*
* Copyright 2018 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 GrSingleIntervalGradientColorizer.fp; do not modify.
**************************************************************************************************/
#include "GrSingleIntervalGradientColorizer.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLProgramBuilder.h"
#include "GrTexture.h"
#include "SkSLCPP.h"
#include "SkSLUtil.h"
class GrGLSLSingleIntervalGradientColorizer : public GrGLSLFragmentProcessor {
public:
GrGLSLSingleIntervalGradientColorizer() {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
const GrSingleIntervalGradientColorizer& _outer =
args.fFp.cast<GrSingleIntervalGradientColorizer>();
(void)_outer;
auto start = _outer.start();
(void)start;
auto end = _outer.end();
(void)end;
fStartVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType,
kDefault_GrSLPrecision, "start");
fEndVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType,
kDefault_GrSLPrecision, "end");
fragBuilder->codeAppendf("half t = %s.x;\n%s = (1.0 - t) * %s + t * %s;\n",
args.fInputColor, args.fOutputColor,
args.fUniformHandler->getUniformCStr(fStartVar),
args.fUniformHandler->getUniformCStr(fEndVar));
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {
const GrSingleIntervalGradientColorizer& _outer =
_proc.cast<GrSingleIntervalGradientColorizer>();
{
const GrColor4f& startValue = _outer.start();
if (fStartPrev != startValue) {
fStartPrev = startValue;
pdman.set4fv(fStartVar, 1, startValue.fRGBA);
}
const GrColor4f& endValue = _outer.end();
if (fEndPrev != endValue) {
fEndPrev = endValue;
pdman.set4fv(fEndVar, 1, endValue.fRGBA);
}
}
}
GrColor4f fStartPrev = GrColor4f::kIllegalConstructor;
GrColor4f fEndPrev = GrColor4f::kIllegalConstructor;
UniformHandle fStartVar;
UniformHandle fEndVar;
};
GrGLSLFragmentProcessor* GrSingleIntervalGradientColorizer::onCreateGLSLInstance() const {
return new GrGLSLSingleIntervalGradientColorizer();
}
void GrSingleIntervalGradientColorizer::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {}
bool GrSingleIntervalGradientColorizer::onIsEqual(const GrFragmentProcessor& other) const {
const GrSingleIntervalGradientColorizer& that = other.cast<GrSingleIntervalGradientColorizer>();
(void)that;
if (fStart != that.fStart) return false;
if (fEnd != that.fEnd) return false;
return true;
}
GrSingleIntervalGradientColorizer::GrSingleIntervalGradientColorizer(
const GrSingleIntervalGradientColorizer& src)
: INHERITED(kGrSingleIntervalGradientColorizer_ClassID, src.optimizationFlags())
, fStart(src.fStart)
, fEnd(src.fEnd) {}
std::unique_ptr<GrFragmentProcessor> GrSingleIntervalGradientColorizer::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrSingleIntervalGradientColorizer(*this));
}

View File

@ -0,0 +1,21 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
// This only supports a 2-color single interval so it is a simple linear interpolation between the
// two end points based on t. But it serves as a good test for connecting all of the plumbing into a
// functional gradient shader.
layout(ctype=GrColor4f, tracked) in uniform half4 start;
layout(ctype=GrColor4f, tracked) in uniform half4 end;
void main() {
half t = sk_InColor.x;
// Clamping and/or wrapping was already handled by the parent shader so the output color is a
// simple lerp.
sk_OutColor = (1 - t) * start + t * end;
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2018 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 GrSingleIntervalGradientColorizer.fp; do not modify.
**************************************************************************************************/
#ifndef GrSingleIntervalGradientColorizer_DEFINED
#define GrSingleIntervalGradientColorizer_DEFINED
#include "SkTypes.h"
#include "GrFragmentProcessor.h"
#include "GrCoordTransform.h"
class GrSingleIntervalGradientColorizer : public GrFragmentProcessor {
public:
const GrColor4f& start() const { return fStart; }
const GrColor4f& end() const { return fEnd; }
static std::unique_ptr<GrFragmentProcessor> Make(GrColor4f start, GrColor4f end) {
return std::unique_ptr<GrFragmentProcessor>(
new GrSingleIntervalGradientColorizer(start, end));
}
GrSingleIntervalGradientColorizer(const GrSingleIntervalGradientColorizer& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "SingleIntervalGradientColorizer"; }
private:
GrSingleIntervalGradientColorizer(GrColor4f start, GrColor4f end)
: INHERITED(kGrSingleIntervalGradientColorizer_ClassID, kNone_OptimizationFlags)
, fStart(start)
, fEnd(end) {}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
GrColor4f fStart;
GrColor4f fEnd;
typedef GrFragmentProcessor INHERITED;
};
#endif

View File

@ -0,0 +1,66 @@
/*
* Copyright 2018 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 GrTiledGradientEffect.fp; do not modify.
**************************************************************************************************/
#include "GrTiledGradientEffect.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLProgramBuilder.h"
#include "GrTexture.h"
#include "SkSLCPP.h"
#include "SkSLUtil.h"
class GrGLSLTiledGradientEffect : public GrGLSLFragmentProcessor {
public:
GrGLSLTiledGradientEffect() {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
const GrTiledGradientEffect& _outer = args.fFp.cast<GrTiledGradientEffect>();
(void)_outer;
auto mirror = _outer.mirror();
(void)mirror;
SkString _child1("_child1");
this->emitChild(1, &_child1, args);
fragBuilder->codeAppendf(
"half4 t = %s;\n@if (%s) {\n half t_1 = t.x - 1.0;\n half tiled_t = "
"(float(t_1) - 2.0 * floor(float(float(t_1) * 0.5))) - 1.0;\n if "
"(sk_Caps.mustDoOpBetweenFloorAndAbs) {\n tiled_t = "
"half(clamp(float(tiled_t), -1.0, 1.0));\n }\n t.x = "
"half(abs(float(tiled_t)));\n} else {\n t.x = half(fract(float(t.x)));\n}",
_child1.c_str(), (_outer.mirror() ? "true" : "false"));
SkString _input0("t");
SkString _child0("_child0");
this->emitChild(0, _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 {}
};
GrGLSLFragmentProcessor* GrTiledGradientEffect::onCreateGLSLInstance() const {
return new GrGLSLTiledGradientEffect();
}
void GrTiledGradientEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {
b->add32((int32_t)fMirror);
}
bool GrTiledGradientEffect::onIsEqual(const GrFragmentProcessor& other) const {
const GrTiledGradientEffect& that = other.cast<GrTiledGradientEffect>();
(void)that;
if (fMirror != that.fMirror) return false;
return true;
}
GrTiledGradientEffect::GrTiledGradientEffect(const GrTiledGradientEffect& src)
: INHERITED(kGrTiledGradientEffect_ClassID, src.optimizationFlags()), fMirror(src.fMirror) {
this->registerChildProcessor(src.childProcessor(0).clone());
this->registerChildProcessor(src.childProcessor(1).clone());
}
std::unique_ptr<GrFragmentProcessor> GrTiledGradientEffect::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrTiledGradientEffect(*this));
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
// Provides tiling for the repeat or mirror modes.
in fragmentProcessor colorizer;
in fragmentProcessor gradLayout;
layout(key) in bool mirror;
void main() {
half4 t = process(gradLayout);
@if(mirror) {
half t_1 = t.x - 1;
half tiled_t = t_1 - 2 * floor(t_1 * 0.5) - 1;
if (sk_Caps.mustDoOpBetweenFloorAndAbs) {
// At this point the expected value of tiled_t should between -1 and 1, so this clamp
// has no effect other than to break up the floor and abs calls and make sure the
// compiler doesn't merge them back together.
tiled_t = clamp(tiled_t, -1, 1);
}
t.x = abs(tiled_t);
} else {
// Simple repeat mode
t.x = fract(t.x);
}
// t.x has been tiled (repeat or mirrored), but pass through remaining 3 components unmodified.
sk_OutColor = process(colorizer, t);
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2018 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 GrTiledGradientEffect.fp; do not modify.
**************************************************************************************************/
#ifndef GrTiledGradientEffect_DEFINED
#define GrTiledGradientEffect_DEFINED
#include "SkTypes.h"
#include "GrFragmentProcessor.h"
#include "GrCoordTransform.h"
class GrTiledGradientEffect : public GrFragmentProcessor {
public:
bool mirror() const { return fMirror; }
static std::unique_ptr<GrFragmentProcessor> Make(
std::unique_ptr<GrFragmentProcessor> colorizer,
std::unique_ptr<GrFragmentProcessor> gradLayout, bool mirror) {
return std::unique_ptr<GrFragmentProcessor>(
new GrTiledGradientEffect(std::move(colorizer), std::move(gradLayout), mirror));
}
GrTiledGradientEffect(const GrTiledGradientEffect& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "TiledGradientEffect"; }
private:
GrTiledGradientEffect(std::unique_ptr<GrFragmentProcessor> colorizer,
std::unique_ptr<GrFragmentProcessor> gradLayout, bool mirror)
: INHERITED(kGrTiledGradientEffect_ClassID, kNone_OptimizationFlags), fMirror(mirror) {
this->registerChildProcessor(std::move(colorizer));
this->registerChildProcessor(std::move(gradLayout));
}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
bool fMirror;
typedef GrFragmentProcessor INHERITED;
};
#endif

View File

@ -0,0 +1,35 @@
Gradients on the GPU
====================
Gradients can be thought of, at a very high level, as three pieces:
1. A color interpolator that is one dimensional, returning a color for an input
within the range [0.0, 1.0]. This obfuscates the the definition of specific
color stops and how to wrap, tile, or clamp out of bound inputs. A color
interpolator will be named GrYGradientColorizer
2. A layout that converts from 2D geometry/position to the one dimensional
domain of the color interpolator. This is how a linear or radial gradient
distinguishes itself. When designing a new gradient, this is the component
that you have to implement. A layout will generally be named
GrXGradientLayout
3. A master effect that composes the layout and color interpolator together. It
is also responsible for implementing the clamping behavior that can be
abstracted away from both the layout and colorization.
GrClampedGradientEffect handles clamped and decal tile modes, while
GrTiledGradientEffect implements repeat and mirror tile modes. The GrClampedGradientEffect requires border colors to be specified outside of its colorizer child, but these border colors may be defined by the gradient color stops. Both of these master effects delegate calculating a t interpolant to a child process, perform their respective tile mode operations, and possibly convert the tiled t value (guaranteed to be within 0 and 1) into an output color using their child colorizer process.
Because of how child processors are currently defined, where they have a single
half4 input and a single half4 output, their is a type mismatch between the 1D
t value and the 4D inputs/outputs of the layout and colorizer processes. For
now, the master effect assumes an untiled t is output in sk_OutColor.x by the
layout and it tiles solely off of that value. Any value in y, z, or w are
passed into the colorizer unmodified. The colorizer should assume that the
valid tiled t value is in sk_InColor.x and can safely ignore y, z, and w.
Currently there are color interpolators (colorizers) for analytic color cases
(evaluated directly on the GPU) and sampling a generated texture map.
GrGradientShader provides static factory functions to create
GrFragmentProcessor graphs that reproduce a particular SkGradientShader.

View File

@ -68,6 +68,8 @@ public:
uint32_t getGradFlags() const { return fGradFlags; }
const SkMatrix& getGradientMatrix() const { return fPtsToUnit; }
protected:
class GradientShaderBase4fContext;

View File

@ -99,6 +99,8 @@ SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const {
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "SkGr.h"
#include "gradients/GrGradientShader.h"
/////////////////////////////////////////////////////////////////////
class GrLinearGradient : public GrGradientEffect {
@ -194,6 +196,12 @@ std::unique_ptr<GrFragmentProcessor> SkLinearGradient::asFragmentProcessor(
const GrFPArgs& args) const {
SkASSERT(args.fContext);
// Try to use new gradient system first
std::unique_ptr<GrFragmentProcessor> gradient = GrGradientShader::MakeLinear(*this, args);
if (gradient) {
return gradient;
}
SkMatrix matrix;
if (!this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix)->invert(&matrix)) {
return nullptr;

View File

@ -62,7 +62,6 @@ public:
SkScalar getEndRadius() const { return fRadius2; }
Type getType() const { return fType; }
const SkMatrix& getGradientMatrix() const { return fPtsToUnit; }
const FocalData& getFocalData() const { return fFocalData; }
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTwoPointConicalGradient)

View File

@ -135,6 +135,7 @@ static void fill_caps(const SKSL_CAPS_CLASS& caps,
CAP(mustEnableAdvBlendEqs);
CAP(mustEnableSpecificAdvBlendEqs);
CAP(mustDeclareFragmentShaderOutput);
CAP(mustDoOpBetweenFloorAndAbs);
CAP(canUseAnyFunctionInShader);
CAP(floatIs32Bits);
CAP(integerSupport);

View File

@ -109,6 +109,10 @@ public:
return true;
}
bool mustDoOpBetweenFloorAndAbs() const {
return false;
}
bool mustEnableAdvBlendEqs() const {
return false;
}