Remove generalized gradient code

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2223203003

Review-Url: https://codereview.chromium.org/2223203003
This commit is contained in:
fmenozzi 2016-08-10 08:57:24 -07:00 committed by Commit bot
parent 9d155afef4
commit 0c63006b88
2 changed files with 479 additions and 229 deletions

View File

@ -228,21 +228,48 @@ void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
desc.flatten(buffer);
}
SkGradientShaderBase::GpuColorType SkGradientShaderBase::getGpuColorType(SkColor colors[3]) const {
if (fColorCount <= 3) {
memcpy(colors, fOrigColors, fColorCount * sizeof(SkColor));
}
static inline bool close_to_one_half(const SkFixed& val) {
return SkScalarNearlyEqual(SkFixedToScalar(val), SK_ScalarHalf);
}
if (SkShader::kClamp_TileMode == fTileMode) {
if (2 == fColorCount) {
return kTwo_GpuColorType;
} else if (3 == fColorCount &&
(SkScalarAbs(
SkFixedToScalar(fRecs[1].fPos) - SK_ScalarHalf) < SK_Scalar1 / 1000)) {
return kThree_GpuColorType;
GrGradientEffect::ColorType GrGradientEffect::determineColorTypeAndNumHardStops(
const SkGradientShaderBase& shader) {
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
if (shader.fOrigPos) {
if (4 == shader.fColorCount) {
if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
SkScalarNearlyEqual(shader.fOrigPos[1], 0.5f) &&
SkScalarNearlyEqual(shader.fOrigPos[2], 0.5f) &&
SkScalarNearlyEqual(shader.fOrigPos[3], 1.0f)) {
return kHardStopCentered_ColorType;
}
} else if (3 == shader.fColorCount) {
if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
SkScalarNearlyEqual(shader.fOrigPos[1], 0.0f) &&
SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) {
return kHardStopLeftEdged_ColorType;
} else if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
SkScalarNearlyEqual(shader.fOrigPos[1], 1.0f) &&
SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) {
return kHardStopRightEdged_ColorType;
}
}
}
return kTexture_GpuColorType;
#endif
if (SkShader::kClamp_TileMode == shader.getTileMode()) {
if (2 == shader.fColorCount) {
return kTwo_ColorType;
} else if (3 == shader.fColorCount &&
close_to_one_half(shader.getRecs()[1].fPos)) {
return kThree_ColorType;
}
}
return kTexture_ColorType;
}
void SkGradientShaderBase::FlipGradientColors(SkColor* colorDst, Rec* recDst,
@ -911,114 +938,147 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
#include "glsl/GrGLSLUniformHandler.h"
#include "SkGr.h"
GrGradientEffect::GLSLProcessor::GLSLProcessor()
: fCachedYCoord(SK_ScalarMax) {
static inline int color_type_to_color_count(GrGradientEffect::ColorType colorType) {
switch (colorType) {
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
case GrGradientEffect::kHardStopCentered_ColorType:
return 4;
case GrGradientEffect::kHardStopLeftEdged_ColorType:
case GrGradientEffect::kHardStopRightEdged_ColorType:
return 3;
#endif
case GrGradientEffect::kTwo_ColorType:
return 2;
case GrGradientEffect::kThree_ColorType:
return 3;
case GrGradientEffect::kTexture_ColorType:
return 0;
}
SkDEBUGFAIL("Unhandled ColorType in color_type_to_color_count()");
return -1;
}
void GrGradientEffect::GLSLProcessor::emitUniforms(GrGLSLUniformHandler* uniformHandler,
const GrGradientEffect& ge) {
if (SkGradientShaderBase::kTwo_GpuColorType == ge.getColorType()) { // 2 Color case
fColorStartUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
kVec4f_GrSLType, kDefault_GrSLPrecision,
"GradientStartColor");
fColorEndUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
kVec4f_GrSLType, kDefault_GrSLPrecision,
"GradientEndColor");
} else if (SkGradientShaderBase::kThree_GpuColorType == ge.getColorType()) { // 3 Color Case
fColorStartUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
kVec4f_GrSLType, kDefault_GrSLPrecision,
"GradientStartColor");
fColorMidUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
kVec4f_GrSLType, kDefault_GrSLPrecision,
"GradientMidColor");
fColorEndUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
kVec4f_GrSLType, kDefault_GrSLPrecision,
"GradientEndColor");
} else { // if not a fast case
if (int colorCount = color_type_to_color_count(ge.getColorType())) {
fColorsUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag,
kVec4f_GrSLType,
kDefault_GrSLPrecision,
"Colors",
colorCount);
} else {
fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
kFloat_GrSLType, kDefault_GrSLPrecision,
"GradientYCoordFS");
}
}
static inline void set_color_uni(const GrGLSLProgramDataManager& pdman,
const GrGLSLProgramDataManager::UniformHandle uni,
const SkColor* color) {
pdman.set4f(uni,
SkColorGetR(*color) / 255.f,
SkColorGetG(*color) / 255.f,
SkColorGetB(*color) / 255.f,
SkColorGetA(*color) / 255.f);
static inline void set_after_interp_color_uni_array(const GrGLSLProgramDataManager& pdman,
const GrGLSLProgramDataManager::UniformHandle uni,
const SkTDArray<SkColor>& colors) {
int count = colors.count();
constexpr int kSmallCount = 10;
SkAutoSTArray<4*kSmallCount, float> vals(4*count);
for (int i = 0; i < colors.count(); i++) {
// RGBA
vals[4*i + 0] = SkColorGetR(colors[i]) / 255.f;
vals[4*i + 1] = SkColorGetG(colors[i]) / 255.f;
vals[4*i + 2] = SkColorGetB(colors[i]) / 255.f;
vals[4*i + 3] = SkColorGetA(colors[i]) / 255.f;
}
pdman.set4fv(uni, colors.count(), vals.get());
}
static inline void set_mul_color_uni(const GrGLSLProgramDataManager& pdman,
const GrGLSLProgramDataManager::UniformHandle uni,
const SkColor* color){
float a = SkColorGetA(*color) / 255.f;
float aDiv255 = a / 255.f;
pdman.set4f(uni,
SkColorGetR(*color) * aDiv255,
SkColorGetG(*color) * aDiv255,
SkColorGetB(*color) * aDiv255,
a);
static inline void set_before_interp_color_uni_array(const GrGLSLProgramDataManager& pdman,
const GrGLSLProgramDataManager::UniformHandle uni,
const SkTDArray<SkColor>& colors) {
int count = colors.count();
constexpr int kSmallCount = 10;
SkAutoSTArray<4*kSmallCount, float> vals(4*count);
for (int i = 0; i < count; i++) {
float a = SkColorGetA(colors[i]) / 255.f;
float aDiv255 = a / 255.f;
// RGBA
vals[4*i + 0] = SkColorGetR(colors[i]) * aDiv255;
vals[4*i + 1] = SkColorGetG(colors[i]) * aDiv255;
vals[4*i + 2] = SkColorGetB(colors[i]) * aDiv255;
vals[4*i + 3] = a;
}
pdman.set4fv(uni, count, vals.get());
}
void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& pdman,
const GrProcessor& processor) {
const GrGradientEffect& e = processor.cast<GrGradientEffect>();
switch (e.getColorType()) {
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
case GrGradientEffect::kHardStopCentered_ColorType:
case GrGradientEffect::kHardStopLeftEdged_ColorType:
case GrGradientEffect::kHardStopRightEdged_ColorType:
#endif
case GrGradientEffect::kTwo_ColorType:
case GrGradientEffect::kThree_ColorType: {
if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
set_before_interp_color_uni_array(pdman, fColorsUni, e.fColors);
} else {
set_after_interp_color_uni_array(pdman, fColorsUni, e.fColors);
}
if (SkGradientShaderBase::kTwo_GpuColorType == e.getColorType()){
if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
set_mul_color_uni(pdman, fColorStartUni, e.getColors(0));
set_mul_color_uni(pdman, fColorEndUni, e.getColors(1));
} else {
set_color_uni(pdman, fColorStartUni, e.getColors(0));
set_color_uni(pdman, fColorEndUni, e.getColors(1));
break;
}
} else if (SkGradientShaderBase::kThree_GpuColorType == e.getColorType()){
if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
set_mul_color_uni(pdman, fColorStartUni, e.getColors(0));
set_mul_color_uni(pdman, fColorMidUni, e.getColors(1));
set_mul_color_uni(pdman, fColorEndUni, e.getColors(2));
} else {
set_color_uni(pdman, fColorStartUni, e.getColors(0));
set_color_uni(pdman, fColorMidUni, e.getColors(1));
set_color_uni(pdman, fColorEndUni, e.getColors(2));
}
} else {
SkScalar yCoord = e.getYCoord();
if (yCoord != fCachedYCoord) {
pdman.set1f(fFSYUni, yCoord);
fCachedYCoord = yCoord;
case GrGradientEffect::kTexture_ColorType: {
SkScalar yCoord = e.getYCoord();
if (yCoord != fCachedYCoord) {
pdman.set1f(fFSYUni, yCoord);
fCachedYCoord = yCoord;
}
break;
}
}
}
uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor& processor) {
const GrGradientEffect& e = processor.cast<GrGradientEffect>();
uint32_t key = 0;
if (SkGradientShaderBase::kTwo_GpuColorType == e.getColorType()) {
key |= kTwoColorKey;
} else if (SkGradientShaderBase::kThree_GpuColorType == e.getColorType()) {
key |= kThreeColorKey;
}
if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
key |= kPremulBeforeInterpKey;
}
if (GrGradientEffect::kTwo_ColorType == e.getColorType()) {
key |= kTwoColorKey;
} else if (GrGradientEffect::kThree_ColorType == e.getColorType()) {
key |= kThreeColorKey;
}
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
else if (GrGradientEffect::kHardStopCentered_ColorType == e.getColorType()) {
key |= kHardStopCenteredKey;
} else if (GrGradientEffect::kHardStopLeftEdged_ColorType == e.getColorType()) {
key |= kHardStopZeroZeroOneKey;
} else if (GrGradientEffect::kHardStopRightEdged_ColorType == e.getColorType()) {
key |= kHardStopZeroOneOneKey;
}
if (SkShader::TileMode::kClamp_TileMode == e.fTileMode) {
key |= kClampTileMode;
} else if (SkShader::TileMode::kRepeat_TileMode == e.fTileMode) {
key |= kRepeatTileMode;
} else {
key |= kMirrorTileMode;
}
#endif
return key;
}
@ -1030,56 +1090,183 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui
const char* outputColor,
const char* inputColor,
const SamplerHandle* texSamplers) {
if (SkGradientShaderBase::kTwo_GpuColorType == ge.getColorType()){
fragBuilder->codeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n",
uniformHandler->getUniformVariable(fColorStartUni).c_str(),
uniformHandler->getUniformVariable(fColorEndUni).c_str(),
gradientTValue);
// Note that we could skip this step if both colors are known to be opaque. Two
// considerations:
// The gradient SkShader reporting opaque is more restrictive than necessary in the two pt
// case. Make sure the key reflects this optimization (and note that it can use the same
// shader as thekBeforeIterp case). This same optimization applies to the 3 color case
// below.
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
fragBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
switch (ge.getColorType()) {
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
case kHardStopCentered_ColorType: {
const char* t = gradientTValue;
const char* colors = uniformHandler->getUniformCStr(fColorsUni);
fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
// Account for tile mode
if (SkShader::kRepeat_TileMode == ge.fTileMode) {
fragBuilder->codeAppendf("clamp_t = fract(%s);", t);
} else if (SkShader::kMirror_TileMode == ge.fTileMode) {
fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t);
fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t);
fragBuilder->codeAppendf(" clamp_t = fract(%s);", t);
fragBuilder->codeAppendf(" } else {");
fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t);
fragBuilder->codeAppendf(" }");
fragBuilder->codeAppendf("}");
}
// Calculate color
fragBuilder->codeAppendf("float relative_t = fract(2.0 * clamp_t);");
if (SkShader::kClamp_TileMode == ge.fTileMode) {
fragBuilder->codeAppendf("relative_t += step(1.0, %s);", t);
}
fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], relative_t);", colors,
colors);
fragBuilder->codeAppendf("if (clamp_t >= 0.5) {");
fragBuilder->codeAppendf(" colorTemp = mix(%s[2], %s[3], relative_t);", colors,
colors);
fragBuilder->codeAppendf("}");
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
}
fragBuilder->codeAppendf("%s = %s;", outputColor,
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
break;
}
fragBuilder->codeAppendf("\t%s = %s;\n", outputColor,
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
} else if (SkGradientShaderBase::kThree_GpuColorType == ge.getColorType()) {
fragBuilder->codeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n",
gradientTValue);
fragBuilder->codeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s;\n",
uniformHandler->getUniformVariable(fColorStartUni).c_str());
if (!glslCaps->canUseMinAndAbsTogether()) {
// The Tegra3 compiler will sometimes never return if we have
// min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression.
fragBuilder->codeAppend("\tfloat minAbs = abs(oneMinus2t);\n");
fragBuilder->codeAppend("\tminAbs = minAbs > 1.0 ? 1.0 : minAbs;\n");
fragBuilder->codeAppendf("\tcolorTemp += (1.0 - minAbs) * %s;\n",
uniformHandler->getUniformVariable(fColorMidUni).c_str());
} else {
fragBuilder->codeAppendf("\tcolorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s;\n",
uniformHandler->getUniformVariable(fColorMidUni).c_str());
}
fragBuilder->codeAppendf("\tcolorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s;\n",
uniformHandler->getUniformVariable(fColorEndUni).c_str());
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
fragBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
case kHardStopLeftEdged_ColorType: {
const char* t = gradientTValue;
const char* colors = uniformHandler->getUniformCStr(fColorsUni);
fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
// Account for tile mode
if (SkShader::kRepeat_TileMode == ge.fTileMode) {
fragBuilder->codeAppendf("clamp_t = fract(%s);", t);
} else if (SkShader::kMirror_TileMode == ge.fTileMode) {
fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t);
fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t);
fragBuilder->codeAppendf(" clamp_t = fract(%s);", t);
fragBuilder->codeAppendf(" } else {");
fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t);
fragBuilder->codeAppendf(" }");
fragBuilder->codeAppendf("}");
}
fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[1], %s[2], clamp_t);", colors,
colors);
if (SkShader::kClamp_TileMode == ge.fTileMode) {
fragBuilder->codeAppendf("if (%s < 0.0) {", t);
fragBuilder->codeAppendf(" colorTemp = %s[0];", colors);
fragBuilder->codeAppendf("}");
}
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
}
fragBuilder->codeAppendf("%s = %s;", outputColor,
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
break;
}
fragBuilder->codeAppendf("\t%s = %s;\n", outputColor,
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
} else {
fragBuilder->codeAppendf("\tvec2 coord = vec2(%s, %s);\n",
gradientTValue,
uniformHandler->getUniformVariable(fFSYUni).c_str());
fragBuilder->codeAppendf("\t%s = ", outputColor);
fragBuilder->appendTextureLookupAndModulate(inputColor,
texSamplers[0],
"coord");
fragBuilder->codeAppend(";\n");
case kHardStopRightEdged_ColorType: {
const char* t = gradientTValue;
const char* colors = uniformHandler->getUniformCStr(fColorsUni);
fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
// Account for tile mode
if (SkShader::kRepeat_TileMode == ge.fTileMode) {
fragBuilder->codeAppendf("clamp_t = fract(%s);", t);
} else if (SkShader::kMirror_TileMode == ge.fTileMode) {
fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t);
fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t);
fragBuilder->codeAppendf(" clamp_t = fract(%s);", t);
fragBuilder->codeAppendf(" } else {");
fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t);
fragBuilder->codeAppendf(" }");
fragBuilder->codeAppendf("}");
}
fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], clamp_t);", colors,
colors);
if (SkShader::kClamp_TileMode == ge.fTileMode) {
fragBuilder->codeAppendf("if (%s > 1.0) {", t);
fragBuilder->codeAppendf(" colorTemp = %s[2];", colors);
fragBuilder->codeAppendf("}");
}
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
}
fragBuilder->codeAppendf("%s = %s;", outputColor,
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
break;
}
#endif
case kTwo_ColorType: {
const char* t = gradientTValue;
const char* colors = uniformHandler->getUniformCStr(fColorsUni);
fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], clamp(%s, 0.0, 1.0));",
colors, colors, t);
// We could skip this step if both colors are known to be opaque. Two
// considerations:
// The gradient SkShader reporting opaque is more restrictive than necessary in the two
// pt case. Make sure the key reflects this optimization (and note that it can use the
// same shader as thekBeforeIterp case). This same optimization applies to the 3 color
// case below.
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
}
fragBuilder->codeAppendf("%s = %s;", outputColor,
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
break;
}
case kThree_ColorType: {
const char* t = gradientTValue;
const char* colors = uniformHandler->getUniformCStr(fColorsUni);
fragBuilder->codeAppendf("float oneMinus2t = 1.0 - (2.0 * %s);", t);
fragBuilder->codeAppendf("vec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s[0];",
colors);
if (!glslCaps->canUseMinAndAbsTogether()) {
// The Tegra3 compiler will sometimes never return if we have
// min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression.
fragBuilder->codeAppendf("float minAbs = abs(oneMinus2t);");
fragBuilder->codeAppendf("minAbs = minAbs > 1.0 ? 1.0 : minAbs;");
fragBuilder->codeAppendf("colorTemp += (1.0 - minAbs) * %s[1];", colors);
} else {
fragBuilder->codeAppendf("colorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s[1];",
colors);
}
fragBuilder->codeAppendf("colorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s[2];", colors);
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
}
fragBuilder->codeAppendf("%s = %s;", outputColor,
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
break;
}
case kTexture_ColorType: {
const char* fsyuni = uniformHandler->getUniformCStr(fFSYUni);
fragBuilder->codeAppendf("vec2 coord = vec2(%s, %s);", gradientTValue, fsyuni);
fragBuilder->codeAppendf("%s = ", outputColor);
fragBuilder->appendTextureLookupAndModulate(inputColor, texSamplers[0], "coord");
fragBuilder->codeAppend(";");
break;
}
}
}
@ -1092,56 +1279,87 @@ GrGradientEffect::GrGradientEffect(GrContext* ctx,
fIsOpaque = shader.isOpaque();
fColorType = shader.getGpuColorType(&fColors[0]);
fColorType = this->determineColorTypeAndNumHardStops(shader);
// The two and three color specializations do not currently support tiling.
if (SkGradientShaderBase::kTwo_GpuColorType == fColorType ||
SkGradientShaderBase::kThree_GpuColorType == fColorType) {
fRow = -1;
if (SkGradientShader::kInterpolateColorsInPremul_Flag & shader.getGradFlags()) {
fPremulType = kBeforeInterp_PremulType;
} else {
fPremulType = kAfterInterp_PremulType;
if (kTexture_ColorType != fColorType) {
if (shader.fOrigColors) {
fColors = SkTDArray<SkColor>(shader.fOrigColors, shader.fColorCount);
}
fCoordTransform.reset(kCoordSet, matrix);
} else {
// doesn't matter how this is set, just be consistent because it is part of the effect key.
fPremulType = kBeforeInterp_PremulType;
SkBitmap bitmap;
shader.getGradientTableBitmap(&bitmap);
GrTextureStripAtlas::Desc desc;
desc.fWidth = bitmap.width();
desc.fHeight = 32;
desc.fRowHeight = bitmap.height();
desc.fContext = ctx;
desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *ctx->caps());
fAtlas = GrTextureStripAtlas::GetAtlas(desc);
SkASSERT(fAtlas);
// We always filter the gradient table. Each table is one row of a texture, always y-clamp.
GrTextureParams params;
params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
params.setTileModeX(tileMode);
fRow = fAtlas->lockRow(bitmap);
if (-1 != fRow) {
fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf * fAtlas->getNormalizedTexelHeight();
fCoordTransform.reset(kCoordSet, matrix, fAtlas->getTexture(), params.filterMode());
fTextureAccess.reset(fAtlas->getTexture(), params);
} else {
SkAutoTUnref<GrTexture> texture(
GrRefCachedBitmapTexture(ctx, bitmap, params, SkSourceGammaTreatment::kRespect));
if (!texture) {
return;
}
fCoordTransform.reset(kCoordSet, matrix, texture, params.filterMode());
fTextureAccess.reset(texture, params);
fYCoord = SK_ScalarHalf;
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
if (shader.fOrigPos) {
fPositions = SkTDArray<SkScalar>(shader.fOrigPos, shader.fColorCount);
}
this->addTextureAccess(&fTextureAccess);
fTileMode = tileMode;
#endif
}
switch (fColorType) {
// The two and three color specializations do not currently support tiling.
case kTwo_ColorType:
case kThree_ColorType:
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
case kHardStopLeftEdged_ColorType:
case kHardStopRightEdged_ColorType:
case kHardStopCentered_ColorType:
#endif
fRow = -1;
if (SkGradientShader::kInterpolateColorsInPremul_Flag & shader.getGradFlags()) {
fPremulType = kBeforeInterp_PremulType;
} else {
fPremulType = kAfterInterp_PremulType;
}
fCoordTransform.reset(kCoordSet, matrix);
break;
case kTexture_ColorType:
// doesn't matter how this is set, just be consistent because it is part of the
// effect key.
fPremulType = kBeforeInterp_PremulType;
SkBitmap bitmap;
shader.getGradientTableBitmap(&bitmap);
GrTextureStripAtlas::Desc desc;
desc.fWidth = bitmap.width();
desc.fHeight = 32;
desc.fRowHeight = bitmap.height();
desc.fContext = ctx;
desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *ctx->caps());
fAtlas = GrTextureStripAtlas::GetAtlas(desc);
SkASSERT(fAtlas);
// We always filter the gradient table. Each table is one row of a texture, always
// y-clamp.
GrTextureParams params;
params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
params.setTileModeX(tileMode);
fRow = fAtlas->lockRow(bitmap);
if (-1 != fRow) {
fYCoord = fAtlas->getYOffset(fRow)+SK_ScalarHalf*fAtlas->getNormalizedTexelHeight();
fCoordTransform.reset(kCoordSet, matrix, fAtlas->getTexture(), params.filterMode());
fTextureAccess.reset(fAtlas->getTexture(), params);
} else {
SkAutoTUnref<GrTexture> texture(
GrRefCachedBitmapTexture(ctx, bitmap, params,
SkSourceGammaTreatment::kRespect));
if (!texture) {
return;
}
fCoordTransform.reset(kCoordSet, matrix, texture, params.filterMode());
fTextureAccess.reset(texture, params);
fYCoord = SK_ScalarHalf;
}
this->addTextureAccess(&fTextureAccess);
break;
}
this->addCoordTransform(&fCoordTransform);
}
@ -1152,30 +1370,27 @@ GrGradientEffect::~GrGradientEffect() {
}
bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const {
const GrGradientEffect& s = processor.cast<GrGradientEffect>();
const GrGradientEffect& ge = processor.cast<GrGradientEffect>();
if (this->fColorType == s.getColorType()){
if (SkGradientShaderBase::kTwo_GpuColorType == fColorType) {
if (this->getPremulType() != s.getPremulType() ||
*this->getColors(0) != *s.getColors(0) ||
*this->getColors(1) != *s.getColors(1)) {
return false;
}
} else if (SkGradientShaderBase::kThree_GpuColorType == fColorType) {
if (this->getPremulType() != s.getPremulType() ||
*this->getColors(0) != *s.getColors(0) ||
*this->getColors(1) != *s.getColors(1) ||
*this->getColors(2) != *s.getColors(2)) {
if (this->fColorType == ge.getColorType()) {
if (kTexture_ColorType == fColorType) {
if (fYCoord != ge.getYCoord()) {
return false;
}
} else {
if (fYCoord != s.getYCoord()) {
if (this->getPremulType() != ge.getPremulType() ||
this->fColors.count() != ge.fColors.count()) {
return false;
}
for (int i = 0; i < this->fColors.count(); i++) {
if (*this->getColors(i) != *ge.getColors(i)) {
return false;
}
}
}
SkASSERT(this->useAtlas() == s.useAtlas());
SkASSERT(this->useAtlas() == ge.useAtlas());
return true;
}

View File

@ -19,6 +19,8 @@
#include "SkShader.h"
#include "SkOnce.h"
#define GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1
static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
int count) {
if (count > 0) {
@ -128,7 +130,8 @@ public:
bool getDither() const { return fCacheDither; }
private:
// Working pointers. If either is nullptr, we need to recompute the corresponding cache values.
// Working pointers. If either is nullptr, we need to recompute the corresponding
// cache values.
uint16_t* fCache16;
SkPMColor* fCache32;
@ -197,17 +200,6 @@ public:
kDitherStride16 = kCache16Count,
};
enum GpuColorType {
kTwo_GpuColorType,
kThree_GpuColorType, // Symmetric three color
kTexture_GpuColorType
};
// Determines and returns the gradient is a two color gradient, symmetric three color gradient
// or other (texture gradient). If it is two or symmetric three color, the colors array will
// also be filled with the gradient colors
GpuColorType getGpuColorType(SkColor colors[3]) const;
uint32_t getGradFlags() const { return fGradFlags; }
protected:
@ -220,7 +212,6 @@ protected:
const SkMatrix fPtsToUnit;
TileMode fTileMode;
TileProc fTileProc;
int fColorCount;
uint8_t fGradFlags;
struct Rec {
@ -254,9 +245,15 @@ private:
public:
SkColor* fOrigColors; // original colors, before modulation by paint in context.
SkScalar* fOrigPos; // original positions
int fColorCount;
SkTArray<sk_sp<SkShader>> fSubGradients;
bool colorsAreOpaque() const { return fColorsAreOpaque; }
TileMode getTileMode() const { return fTileMode; }
Rec* getRecs() const { return fRecs; }
private:
bool fColorsAreOpaque;
@ -336,9 +333,30 @@ public:
virtual ~GrGradientEffect();
bool useAtlas() const { return SkToBool(-1 != fRow); }
SkScalar getYCoord() const { return fYCoord; };
SkScalar getYCoord() const { return fYCoord; }
SkGradientShaderBase::GpuColorType getColorType() const { return fColorType; }
enum ColorType {
kTwo_ColorType,
kThree_ColorType, // Symmetric three color
kTexture_ColorType,
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
kHardStopCentered_ColorType, // 0, 0.5, 0.5, 1
kHardStopLeftEdged_ColorType, // 0, 0, 1
kHardStopRightEdged_ColorType, // 0, 1, 1
#endif
};
ColorType getColorType() const { return fColorType; }
// Determines the type of gradient, one of:
// - Two-color
// - Symmetric three-color
// - Texture
// - Centered hard stop
// - Left-edged hard stop
// - Right-edged hard stop
ColorType determineColorTypeAndNumHardStops(const SkGradientShaderBase& shader);
enum PremulType {
kBeforeInterp_PremulType,
@ -348,8 +366,8 @@ public:
PremulType getPremulType() const { return fPremulType; }
const SkColor* getColors(int pos) const {
SkASSERT(fColorType != SkGradientShaderBase::kTexture_GpuColorType);
SkASSERT((pos-1) <= fColorType);
SkASSERT(fColorType != kTexture_ColorType);
SkASSERT(pos < fColors.count());
return &fColors[pos];
}
@ -358,8 +376,8 @@ protected:
The function decides whether stop values should be used or not. The return value indicates
the number of colors, which will be capped by kMaxRandomGradientColors. colors should be
sized to be at least kMaxRandomGradientColors. stops is a pointer to an array of at least
size kMaxRandomGradientColors. It may be updated to nullptr, indicating that nullptr should be
passed to the gradient factory rather than the array.
size kMaxRandomGradientColors. It may be updated to nullptr, indicating that nullptr should
be passed to the gradient factory rather than the array.
*/
static const int kMaxRandomGradientColors = 4;
static int RandomGradientParams(SkRandom* r,
@ -376,26 +394,31 @@ protected:
private:
static const GrCoordSet kCoordSet = kLocal_GrCoordSet;
SkTDArray<SkColor> fColors;
SkTDArray<SkScalar> fPositions;
SkShader::TileMode fTileMode;
GrCoordTransform fCoordTransform;
GrTextureAccess fTextureAccess;
SkScalar fYCoord;
GrTextureStripAtlas* fAtlas;
int fRow;
bool fIsOpaque;
SkGradientShaderBase::GpuColorType fColorType;
SkColor fColors[3]; // More than 3 colors we use texture
PremulType fPremulType; // This only changes behavior for two and three color special cases.
// It is already baked into to the table for texture gradients.
ColorType fColorType;
PremulType fPremulType; // This is already baked into the table for texture gradients, and
// only changes behavior for gradients that don't use a texture.
typedef GrFragmentProcessor INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
// Base class for GLSL gradient effects
// Base class for GL gradient effects
class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
public:
GLSLProcessor();
GLSLProcessor() {
fCachedYCoord = SK_ScalarMax;
}
protected:
void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
@ -412,10 +435,10 @@ protected:
// should call this method from their emitCode().
void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
// emit code that gets a fragment's color from an expression for t; Has branches for 3 separate
// control flows inside -- 2 color gradients, 3 color symmetric gradients (both using
// native GLSL mix), and 4+ color gradients that use the traditional texture lookup.
// Emit code that gets a fragment's color from an expression for t; has branches for
// several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+
// color gradients that use the traditional texture lookup, as well as several varieties
// of hard stop gradients
void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
GrGLSLUniformHandler* uniformHandler,
const GrGLSLCaps* caps,
@ -428,18 +451,30 @@ protected:
private:
enum {
// First bit for premul before/after interp
kPremulBeforeInterpKey = 1,
kPremulBeforeInterpKey = 1,
// Next two bits for 2/3 color type (neither means using texture atlas)
kTwoColorKey = 4,
kThreeColorKey = 6,
// Next three bits for 2/3 color type or different special
// hard stop cases (neither means using texture atlas)
kTwoColorKey = 2,
kThreeColorKey = 4,
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
kHardStopCenteredKey = 6,
kHardStopZeroZeroOneKey = 8,
kHardStopZeroOneOneKey = 10,
// Next two bits for tile mode
kClampTileMode = 16,
kRepeatTileMode = 32,
kMirrorTileMode = 48,
// Lower six bits for premul, 2/3 color type, and tile mode
kReservedBits = 6,
#endif
};
SkScalar fCachedYCoord;
GrGLSLProgramDataManager::UniformHandle fColorsUni;
GrGLSLProgramDataManager::UniformHandle fFSYUni;
GrGLSLProgramDataManager::UniformHandle fColorStartUni;
GrGLSLProgramDataManager::UniformHandle fColorMidUni;
GrGLSLProgramDataManager::UniformHandle fColorEndUni;
typedef GrGLSLFragmentProcessor INHERITED;
};