Update ConstColor FP to support an input FP.

In the "ignore input" mode, the input FP contributes nothing and is
never sampled. In the "modulate input" cases, the input FP is sampled
as one would expect.

Change-Id: I96717d63d8e3d7ef6aa4eaaf88154c6e5ce47e55
Bug: skia:10217
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/296299
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
This commit is contained in:
John Stiles 2020-06-15 13:58:48 -04:00 committed by Skia Commit-Bot
parent a4a132c2be
commit e3a39f7053
15 changed files with 144 additions and 89 deletions

View File

@ -119,7 +119,7 @@ protected:
GrConstColorProcessor::InputMode mode = (GrConstColorProcessor::InputMode) m;
SkPMColor4f color = SkPMColor4f::FromBytes_RGBA(kColors[procColor]);
auto fp = GrConstColorProcessor::Make(color, mode);
auto fp = GrConstColorProcessor::Make(/*inputFP=*/nullptr, color, mode);
grPaint.addColorFragmentProcessor(std::move(fp));
renderTargetContext->priv().testingOnly_addDrawOp(

View File

@ -94,7 +94,8 @@ std::unique_ptr<GrFragmentProcessor> SkModeColorFilter::asFragmentProcessor(
return nullptr;
}
auto constFP = GrConstColorProcessor::Make(SkColorToPMColor4f(fColor, dstColorInfo),
auto constFP = GrConstColorProcessor::Make(/*inputFP=*/nullptr,
SkColorToPMColor4f(fColor, dstColorInfo),
GrConstColorProcessor::InputMode::kIgnore);
auto fp = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(constFP), fMode);
if (!fp) {

View File

@ -362,7 +362,7 @@ sk_sp<SkSpecialImage> ArithmeticImageFilterImpl::filterImageGPU(
background->alphaType(),
ctx.colorSpace());
} else {
bgFP = GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
bgFP = GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT,
GrConstColorProcessor::InputMode::kIgnore);
}

View File

@ -272,7 +272,7 @@ sk_sp<SkSpecialImage> SkXfermodeImageFilterImpl::filterImageGPU(
background->alphaType(),
ctx.colorSpace());
} else {
bgFP = GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
bgFP = GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT,
GrConstColorProcessor::InputMode::kIgnore);
}

View File

@ -420,8 +420,8 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::RunInSeries(
SkPMColor4f knownColor;
int leadingFPsToEliminate = info.initialProcessorsToEliminate(&knownColor);
if (leadingFPsToEliminate) {
std::unique_ptr<GrFragmentProcessor> colorFP(
GrConstColorProcessor::Make(knownColor, GrConstColorProcessor::InputMode::kIgnore));
std::unique_ptr<GrFragmentProcessor> colorFP = GrConstColorProcessor::Make(
/*inputFP=*/nullptr, knownColor, GrConstColorProcessor::InputMode::kIgnore);
if (leadingFPsToEliminate == cnt) {
return colorFP;
}

View File

@ -293,19 +293,19 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context,
shaderFP = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(shaderFP),
*primColorMode);
// The above may return null if compose results in a pass through of the prim color.
if (shaderFP) {
grPaint->addColorFragmentProcessor(std::move(shaderFP));
}
// We can ignore origColor here - alpha is unchanged by gamma
float paintAlpha = skPaint.getColor4f().fA;
if (1.0f != paintAlpha) {
// No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
// color channels. It's value should be treated as the same in ANY color space.
grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make(
{ paintAlpha, paintAlpha, paintAlpha, paintAlpha },
GrConstColorProcessor::InputMode::kModulateRGBA));
shaderFP = GrConstColorProcessor::Make(
std::move(shaderFP), { paintAlpha, paintAlpha, paintAlpha, paintAlpha },
GrConstColorProcessor::InputMode::kModulateRGBA);
}
// The above may return null if compose results in a pass through of the prim color.
if (shaderFP) {
grPaint->addColorFragmentProcessor(std::move(shaderFP));
}
} else {
// The shader's FP sees the paint *unpremul* color
@ -318,14 +318,10 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context,
// There is a blend between the primitive color and the paint color. The blend considers
// the opaque paint color. The paint's alpha is applied to the post-blended color.
SkPMColor4f opaqueColor = origColor.makeOpaque().premul();
auto processor = GrConstColorProcessor::Make(opaqueColor,
auto processor = GrConstColorProcessor::Make(/*inputFP=*/nullptr, opaqueColor,
GrConstColorProcessor::InputMode::kIgnore);
processor = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(processor),
*primColorMode);
if (processor) {
grPaint->addColorFragmentProcessor(std::move(processor));
}
grPaint->setColor4f(opaqueColor);
// We can ignore origColor here - alpha is unchanged by gamma
@ -333,9 +329,13 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context,
if (1.0f != paintAlpha) {
// No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
// color channels. It's value should be treated as the same in ANY color space.
grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make(
{ paintAlpha, paintAlpha, paintAlpha, paintAlpha },
GrConstColorProcessor::InputMode::kModulateRGBA));
processor = GrConstColorProcessor::Make(
std::move(processor), { paintAlpha, paintAlpha, paintAlpha, paintAlpha },
GrConstColorProcessor::InputMode::kModulateRGBA);
}
if (processor) {
grPaint->addColorFragmentProcessor(std::move(processor));
}
} else {
// No shader, no primitive color.

View File

@ -13,51 +13,60 @@ enum class InputMode {
kLast = kModulateA
};
in fragmentProcessor? inputFP;
layout(ctype=SkPMColor4f, tracked) in uniform half4 color;
layout(key) in InputMode mode;
@optimizationFlags {
OptFlags(color, mode)
(inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) &
(kConstantOutputForConstantInput_OptimizationFlag |
((mode != InputMode::kIgnore) ? kCompatibleWithCoverageAsAlpha_OptimizationFlag
: kNone_OptimizationFlags) |
((color.isOpaque()) ? kPreservesOpaqueInput_OptimizationFlag
: kNone_OptimizationFlags))
}
void main() {
@switch (mode) {
case InputMode::kIgnore:
case InputMode::kIgnore: {
sk_OutColor = color;
break;
case InputMode::kModulateRGBA:
sk_OutColor = sk_InColor * color;
}
case InputMode::kModulateRGBA: {
half4 inputColor = sample(inputFP, sk_InColor);
sk_OutColor = inputColor * color;
break;
case InputMode::kModulateA:
sk_OutColor = sk_InColor.a * color;
}
case InputMode::kModulateA: {
half inputAlpha = sample(inputFP, sk_InColor).a;
sk_OutColor = inputAlpha * color;
break;
}
}
}
@class {
static const int kInputModeCnt = (int) InputMode::kLast + 1;
static OptimizationFlags OptFlags(const SkPMColor4f& color, InputMode mode) {
OptimizationFlags flags = kConstantOutputForConstantInput_OptimizationFlag;
if (mode != InputMode::kIgnore) {
flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
}
if (color.isOpaque()) {
flags |= kPreservesOpaqueInput_OptimizationFlag;
}
return flags;
}
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override {
switch (mode) {
case InputMode::kIgnore:
case InputMode::kIgnore: {
return color;
case InputMode::kModulateA:
}
case InputMode::kModulateA: {
SkPMColor4f input = this->numChildProcessors()
? ConstantOutputForConstantInput(this->childProcessor(inputFP_index), inColor)
: inColor;
return color * input.fA;
case InputMode::kModulateRGBA:
}
case InputMode::kModulateRGBA: {
SkPMColor4f input = this->numChildProcessors()
? ConstantOutputForConstantInput(this->childProcessor(inputFP_index), inColor)
: inColor;
return color * input;
}
}
SK_ABORT("Unexpected mode");
SkUNREACHABLE;
}
}
@ -82,5 +91,5 @@ void main() {
break;
}
InputMode mode = static_cast<InputMode>(d->fRandom->nextULessThan(kInputModeCnt));
return GrConstColorProcessor::Make(color, mode);
return GrConstColorProcessor::Make(/*inputFP=*/nullptr, color, mode);
}

View File

@ -105,14 +105,14 @@ std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::Make(GrClipEdgeType typ
// skip the draw or omit the clip element.
if (!SkPathPriv::CheapComputeFirstDirection(path, &dir)) {
if (GrProcessorEdgeTypeIsInverseFill(type)) {
return GrConstColorProcessor::Make(SK_PMColor4fWHITE,
return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fWHITE,
GrConstColorProcessor::InputMode::kModulateRGBA);
}
// This could use kIgnore instead of kModulateRGBA but it would trigger a debug print
// about a coverage processor not being compatible with the alpha-as-coverage optimization.
// We don't really care about this unlikely case so we just use kModulateRGBA to suppress
// the print.
return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT,
GrConstColorProcessor::InputMode::kModulateRGBA);
}

View File

@ -284,7 +284,7 @@ std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d
auto result = GrSkSLFP::Make(d->context(), effect, "Arithmetic",
SkData::MakeWithCopy(&inputs, sizeof(inputs)));
result->addChild(GrConstColorProcessor::Make(
SK_PMColor4fWHITE, GrConstColorProcessor::InputMode::kIgnore));
/*inputFP=*/nullptr, SK_PMColor4fWHITE, GrConstColorProcessor::InputMode::kIgnore));
return std::unique_ptr<GrFragmentProcessor>(result.release());
}
case 2: {

View File

@ -245,7 +245,7 @@ std::unique_ptr<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromTwoPro
SkBlendMode mode) {
switch (mode) {
case SkBlendMode::kClear:
return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT,
GrConstColorProcessor::InputMode::kIgnore);
case SkBlendMode::kSrc:
return src;
@ -496,7 +496,7 @@ std::unique_ptr<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromDstPro
std::unique_ptr<GrFragmentProcessor> dst, SkBlendMode mode) {
switch (mode) {
case SkBlendMode::kClear:
return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT,
GrConstColorProcessor::InputMode::kIgnore);
case SkBlendMode::kSrc:
return nullptr;
@ -510,7 +510,7 @@ std::unique_ptr<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromSrcPro
std::unique_ptr<GrFragmentProcessor> src, SkBlendMode mode) {
switch (mode) {
case SkBlendMode::kClear:
return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT,
GrConstColorProcessor::InputMode::kIgnore);
case SkBlendMode::kDst:
return nullptr;

View File

@ -30,12 +30,33 @@ public:
colorVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag,
kHalf4_GrSLType, "color");
fragBuilder->codeAppendf(
"@switch (%d) {\n case 0:\n %s = %s;\n break;\n case 1:\n "
" %s = %s * %s;\n break;\n case 2:\n %s = %s.w * %s;\n "
"break;\n}\n",
(int)_outer.mode, args.fOutputColor, args.fUniformHandler->getUniformCStr(colorVar),
args.fOutputColor, args.fInputColor, args.fUniformHandler->getUniformCStr(colorVar),
args.fOutputColor, args.fInputColor,
"@switch (%d) {\n case 0:\n {\n %s = %s;\n "
"break;\n }\n case 1:\n {",
(int)_outer.mode, args.fOutputColor,
args.fUniformHandler->getUniformCStr(colorVar));
SkString _input1009 = SkStringPrintf("%s", args.fInputColor);
SkString _sample1009;
if (_outer.inputFP_index >= 0) {
_sample1009 = this->invokeChild(_outer.inputFP_index, _input1009.c_str(), args);
} else {
_sample1009 = _input1009;
}
fragBuilder->codeAppendf(
"\n half4 inputColor = %s;\n %s = inputColor * %s;\n "
" break;\n }\n case 2:\n {",
_sample1009.c_str(), args.fOutputColor,
args.fUniformHandler->getUniformCStr(colorVar));
SkString _input1181 = SkStringPrintf("%s", args.fInputColor);
SkString _sample1181;
if (_outer.inputFP_index >= 0) {
_sample1181 = this->invokeChild(_outer.inputFP_index, _input1181.c_str(), args);
} else {
_sample1181 = _input1181;
}
fragBuilder->codeAppendf(
"\n half inputAlpha = %s.w;\n %s = inputAlpha * %s;\n "
" break;\n }\n}\n",
_sample1181.c_str(), args.fOutputColor,
args.fUniformHandler->getUniformCStr(colorVar));
}
@ -71,7 +92,11 @@ bool GrConstColorProcessor::onIsEqual(const GrFragmentProcessor& other) const {
GrConstColorProcessor::GrConstColorProcessor(const GrConstColorProcessor& src)
: INHERITED(kGrConstColorProcessor_ClassID, src.optimizationFlags())
, color(src.color)
, mode(src.mode) {}
, mode(src.mode) {
if (src.inputFP_index >= 0) {
inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index));
}
}
std::unique_ptr<GrFragmentProcessor> GrConstColorProcessor::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrConstColorProcessor(*this));
}
@ -98,6 +123,6 @@ std::unique_ptr<GrFragmentProcessor> GrConstColorProcessor::TestCreate(GrProcess
break;
}
InputMode mode = static_cast<InputMode>(d->fRandom->nextULessThan(kInputModeCnt));
return GrConstColorProcessor::Make(color, mode);
return GrConstColorProcessor::Make(/*inputFP=*/nullptr, color, mode);
}
#endif

View File

@ -23,42 +23,60 @@ public:
static const int kInputModeCnt = (int)InputMode::kLast + 1;
static OptimizationFlags OptFlags(const SkPMColor4f& color, InputMode mode) {
OptimizationFlags flags = kConstantOutputForConstantInput_OptimizationFlag;
if (mode != InputMode::kIgnore) {
flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
}
if (color.isOpaque()) {
flags |= kPreservesOpaqueInput_OptimizationFlag;
}
return flags;
}
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override {
switch (mode) {
case InputMode::kIgnore:
case InputMode::kIgnore: {
return color;
case InputMode::kModulateA:
}
case InputMode::kModulateA: {
SkPMColor4f input = this->numChildProcessors()
? ConstantOutputForConstantInput(
this->childProcessor(inputFP_index), inColor)
: inColor;
return color * input.fA;
case InputMode::kModulateRGBA:
}
case InputMode::kModulateRGBA: {
SkPMColor4f input = this->numChildProcessors()
? ConstantOutputForConstantInput(
this->childProcessor(inputFP_index), inColor)
: inColor;
return color * input;
}
}
SK_ABORT("Unexpected mode");
SkUNREACHABLE;
}
static std::unique_ptr<GrFragmentProcessor> Make(SkPMColor4f color, InputMode mode) {
return std::unique_ptr<GrFragmentProcessor>(new GrConstColorProcessor(color, mode));
static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP,
SkPMColor4f color,
InputMode mode) {
return std::unique_ptr<GrFragmentProcessor>(
new GrConstColorProcessor(std::move(inputFP), color, mode));
}
GrConstColorProcessor(const GrConstColorProcessor& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "ConstColorProcessor"; }
int inputFP_index = -1;
SkPMColor4f color;
InputMode mode;
private:
GrConstColorProcessor(SkPMColor4f color, InputMode mode)
: INHERITED(kGrConstColorProcessor_ClassID, (OptimizationFlags)OptFlags(color, mode))
GrConstColorProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
SkPMColor4f color,
InputMode mode)
: INHERITED(kGrConstColorProcessor_ClassID,
(OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get())
: kAll_OptimizationFlags) &
(kConstantOutputForConstantInput_OptimizationFlag |
((mode != InputMode::kIgnore)
? kCompatibleWithCoverageAsAlpha_OptimizationFlag
: kNone_OptimizationFlags) |
((color.isOpaque()) ? kPreservesOpaqueInput_OptimizationFlag
: kNone_OptimizationFlags)))
, color(color)
, mode(mode) {}
, mode(mode) {
if (inputFP) {
inputFP_index = this->registerChildProcessor(std::move(inputFP));
}
}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;

View File

@ -118,7 +118,8 @@ skvm::Color SkColor4Shader::onProgram(skvm::Builder* p,
std::unique_ptr<GrFragmentProcessor> SkColorShader::asFragmentProcessor(
const GrFPArgs& args) const {
SkPMColor4f color = SkColorToPMColor4f(fColor, *args.fDstColorInfo);
return GrConstColorProcessor::Make(color, GrConstColorProcessor::InputMode::kModulateA);
return GrConstColorProcessor::Make(/*inputFP=*/nullptr, color,
GrConstColorProcessor::InputMode::kModulateA);
}
std::unique_ptr<GrFragmentProcessor> SkColor4Shader::asFragmentProcessor(
@ -127,7 +128,7 @@ std::unique_ptr<GrFragmentProcessor> SkColor4Shader::asFragmentProcessor(
args.fDstColorInfo->colorSpace(), kUnpremul_SkAlphaType };
SkColor4f color = fColor;
steps.apply(color.vec());
return GrConstColorProcessor::Make(color.premul(),
return GrConstColorProcessor::Make(/*inputFP=*/nullptr, color.premul(),
GrConstColorProcessor::InputMode::kModulateA);
}

View File

@ -1443,13 +1443,13 @@ std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcesso
// TODO: Either treat the output of this shader as sRGB or allow client to specify a
// color space of the noise. Either way, this case (and the GLSL) need to convert to
// the destination.
auto inner =
GrConstColorProcessor::Make(SkPMColor4f::FromBytes_RGBA(0x80404040),
GrConstColorProcessor::InputMode::kModulateRGBA);
auto inner = GrConstColorProcessor::Make(
/*inputFP=*/nullptr, SkPMColor4f::FromBytes_RGBA(0x80404040),
GrConstColorProcessor::InputMode::kModulateRGBA);
return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
}
// Emit zero.
return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT,
GrConstColorProcessor::InputMode::kIgnore);
}

View File

@ -92,7 +92,8 @@ static void run_test(GrContext* ctx, skiatest::Reporter* reporter) {
GrPaint paint;
const SkPMColor4f color = { 1.0f, 0.0f, 0.0f, 1.0f };
auto fp = GrConstColorProcessor::Make(color, GrConstColorProcessor::InputMode::kIgnore);
auto fp = GrConstColorProcessor::Make(/*inputFP=*/nullptr, color,
GrConstColorProcessor::InputMode::kIgnore);
paint.addColorFragmentProcessor(std::move(fp));
rtc->drawPath(nullptr, std::move(paint), GrAA::kNo,
@ -110,7 +111,8 @@ static void run_test(GrContext* ctx, skiatest::Reporter* reporter) {
GrPaint paint;
const SkPMColor4f color = { 0.0f, 1.0f, 0.0f, 1.0f };
auto fp = GrConstColorProcessor::Make(color, GrConstColorProcessor::InputMode::kIgnore);
auto fp = GrConstColorProcessor::Make(/*inputFP=*/nullptr, color,
GrConstColorProcessor::InputMode::kIgnore);
paint.addColorFragmentProcessor(std::move(fp));
rtc->drawPath(nullptr, std::move(paint), GrAA::kNo,
@ -126,7 +128,6 @@ static void run_test(GrContext* ctx, skiatest::Reporter* reporter) {
}
}
}
}
DEF_GPUTEST_FOR_CONTEXTS(GrDefaultPathRendererTest,