Revert of Exact Ganesh Gradients for Special Cases (patchset #9 id:160001 of https://codereview.chromium.org/2223203003/ )

Reason for revert:
specualtive revert to fix valgrind bot
Perf-Ubuntu-GCC-ShuttleA-GPU-GTX550Ti-x86_64-Release-Valgrind

Original issue's description:
> Remove generalized gradient code
>
> BUG=skia:
> GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2223203003
>
> Committed: https://skia.googlesource.com/skia/+/0c63006b88a16e3418d92852a62771615799839d
> Committed: https://skia.googlesource.com/skia/+/99818d69372d29a139935cfe5c379e491432931b
> Committed: https://skia.googlesource.com/skia/+/2a4959181fc98d5d7ee862e7cd1c7993b3343be6

TBR=bsalomon@google.com,fmenozzi@google.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:

Review-Url: https://codereview.chromium.org/2245533005
This commit is contained in:
halcanary 2016-08-12 12:35:51 -07:00 committed by Commit bot
parent 5b31f321fc
commit 8a822ba4a3
3 changed files with 233 additions and 485 deletions

View File

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

View File

@ -19,10 +19,6 @@
#include "SkShader.h" #include "SkShader.h"
#include "SkOnce.h" #include "SkOnce.h"
#if SK_SUPPORT_GPU
#define GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1
#endif
static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1, static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
int count) { int count) {
if (count > 0) { if (count > 0) {
@ -132,8 +128,7 @@ public:
bool getDither() const { return fCacheDither; } bool getDither() const { return fCacheDither; }
private: private:
// Working pointers. If either is nullptr, we need to recompute the corresponding // Working pointers. If either is nullptr, we need to recompute the corresponding cache values.
// cache values.
uint16_t* fCache16; uint16_t* fCache16;
SkPMColor* fCache32; SkPMColor* fCache32;
@ -202,6 +197,17 @@ public:
kDitherStride16 = kCache16Count, 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; } uint32_t getGradFlags() const { return fGradFlags; }
protected: protected:
@ -214,6 +220,7 @@ protected:
const SkMatrix fPtsToUnit; const SkMatrix fPtsToUnit;
TileMode fTileMode; TileMode fTileMode;
TileProc fTileProc; TileProc fTileProc;
int fColorCount;
uint8_t fGradFlags; uint8_t fGradFlags;
struct Rec { struct Rec {
@ -247,15 +254,9 @@ private:
public: public:
SkColor* fOrigColors; // original colors, before modulation by paint in context. SkColor* fOrigColors; // original colors, before modulation by paint in context.
SkScalar* fOrigPos; // original positions SkScalar* fOrigPos; // original positions
int fColorCount;
SkTArray<sk_sp<SkShader>> fSubGradients;
bool colorsAreOpaque() const { return fColorsAreOpaque; } bool colorsAreOpaque() const { return fColorsAreOpaque; }
TileMode getTileMode() const { return fTileMode; }
Rec* getRecs() const { return fRecs; }
private: private:
bool fColorsAreOpaque; bool fColorsAreOpaque;
@ -335,30 +336,9 @@ public:
virtual ~GrGradientEffect(); virtual ~GrGradientEffect();
bool useAtlas() const { return SkToBool(-1 != fRow); } bool useAtlas() const { return SkToBool(-1 != fRow); }
SkScalar getYCoord() const { return fYCoord; } SkScalar getYCoord() const { return fYCoord; };
enum ColorType { SkGradientShaderBase::GpuColorType getColorType() const { return fColorType; }
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 determineColorType(const SkGradientShaderBase& shader);
enum PremulType { enum PremulType {
kBeforeInterp_PremulType, kBeforeInterp_PremulType,
@ -368,8 +348,8 @@ public:
PremulType getPremulType() const { return fPremulType; } PremulType getPremulType() const { return fPremulType; }
const SkColor* getColors(int pos) const { const SkColor* getColors(int pos) const {
SkASSERT(fColorType != kTexture_ColorType); SkASSERT(fColorType != SkGradientShaderBase::kTexture_GpuColorType);
SkASSERT(pos < fColors.count()); SkASSERT((pos-1) <= fColorType);
return &fColors[pos]; return &fColors[pos];
} }
@ -378,8 +358,8 @@ protected:
The function decides whether stop values should be used or not. The return value indicates 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 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 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 size kMaxRandomGradientColors. It may be updated to nullptr, indicating that nullptr should be
be passed to the gradient factory rather than the array. passed to the gradient factory rather than the array.
*/ */
static const int kMaxRandomGradientColors = 4; static const int kMaxRandomGradientColors = 4;
static int RandomGradientParams(SkRandom* r, static int RandomGradientParams(SkRandom* r,
@ -396,31 +376,26 @@ protected:
private: private:
static const GrCoordSet kCoordSet = kLocal_GrCoordSet; static const GrCoordSet kCoordSet = kLocal_GrCoordSet;
SkTDArray<SkColor> fColors;
SkTDArray<SkScalar> fPositions;
SkShader::TileMode fTileMode;
GrCoordTransform fCoordTransform; GrCoordTransform fCoordTransform;
GrTextureAccess fTextureAccess; GrTextureAccess fTextureAccess;
SkScalar fYCoord; SkScalar fYCoord;
GrTextureStripAtlas* fAtlas; GrTextureStripAtlas* fAtlas;
int fRow; int fRow;
bool fIsOpaque; bool fIsOpaque;
ColorType fColorType; SkGradientShaderBase::GpuColorType fColorType;
PremulType fPremulType; // This is already baked into the table for texture gradients, and SkColor fColors[3]; // More than 3 colors we use texture
// only changes behavior for gradients that don't use a 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.
typedef GrFragmentProcessor INHERITED; typedef GrFragmentProcessor INHERITED;
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Base class for GL gradient effects // Base class for GLSL gradient effects
class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor { class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
public: public:
GLSLProcessor() { GLSLProcessor();
fCachedYCoord = SK_ScalarMax;
}
protected: protected:
void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
@ -437,10 +412,10 @@ protected:
// should call this method from their emitCode(). // should call this method from their emitCode().
void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&); void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
// 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+ // emit code that gets a fragment's color from an expression for t; Has branches for 3 separate
// color gradients that use the traditional texture lookup, as well as several varieties // control flows inside -- 2 color gradients, 3 color symmetric gradients (both using
// of hard stop gradients // native GLSL mix), and 4+ color gradients that use the traditional texture lookup.
void emitColor(GrGLSLFPFragmentBuilder* fragBuilder, void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
GrGLSLUniformHandler* uniformHandler, GrGLSLUniformHandler* uniformHandler,
const GrGLSLCaps* caps, const GrGLSLCaps* caps,
@ -453,30 +428,18 @@ protected:
private: private:
enum { enum {
// First bit for premul before/after interp // First bit for premul before/after interp
kPremulBeforeInterpKey = 1, kPremulBeforeInterpKey = 1,
// Next three bits for 2/3 color type or different special // Next two bits for 2/3 color type (neither means using texture atlas)
// hard stop cases (neither means using texture atlas) kTwoColorKey = 4,
kTwoColorKey = 2, kThreeColorKey = 6,
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; SkScalar fCachedYCoord;
GrGLSLProgramDataManager::UniformHandle fColorsUni;
GrGLSLProgramDataManager::UniformHandle fFSYUni; GrGLSLProgramDataManager::UniformHandle fFSYUni;
GrGLSLProgramDataManager::UniformHandle fColorStartUni;
GrGLSLProgramDataManager::UniformHandle fColorMidUni;
GrGLSLProgramDataManager::UniformHandle fColorEndUni;
typedef GrGLSLFragmentProcessor INHERITED; typedef GrGLSLFragmentProcessor INHERITED;
}; };

View File

@ -218,10 +218,10 @@ void GrSweepGradient::GLSLSweepProcessor::emitCode(EmitArgs& args) {
// On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int // On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int
// thus must us -1.0 * %s.x to work correctly // thus must us -1.0 * %s.x to work correctly
if (args.fGLSLCaps->mustForceNegatedAtanParamToFloat()){ if (args.fGLSLCaps->mustForceNegatedAtanParamToFloat()){
t.printf("(atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5)", t.printf("atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5",
coords2D.c_str(), coords2D.c_str()); coords2D.c_str(), coords2D.c_str());
} else { } else {
t.printf("(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5)", t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
coords2D.c_str(), coords2D.c_str()); coords2D.c_str(), coords2D.c_str());
} }
this->emitColor(args.fFragBuilder, this->emitColor(args.fFragBuilder,