std::unique_ptr<GrFragmentProcessor> SkColor4Shader::asFragmentProcessor( const GrFPArgs& args) const { // Construct an xform assuming float inputs. The color space can have a transfer function on // it, which will be applied below. auto colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(), kRGBA_float_GrPixelConfig, args.fDstColorSpaceInfo->colorSpace()); GrColor4f color = GrColor4f::FromSkColor4f(fColor4); if (colorSpaceXform) { color = colorSpaceXform->clampedXform(color); } return GrConstColorProcessor::Make(color.premul(), GrConstColorProcessor::InputMode::kModulateA); }
static inline bool skpaint_to_grpaint_impl(GrContext* context, const GrColorSpaceInfo& colorSpaceInfo, const SkPaint& skPaint, const SkMatrix& viewM, std::unique_ptr<GrFragmentProcessor>* shaderProcessor, SkBlendMode* primColorMode, GrPaint* grPaint) { grPaint->setAllowSRGBInputs(colorSpaceInfo.isGammaCorrect()); // Convert SkPaint color to 4f format, including optional linearizing and gamut conversion. GrColor4f origColor = SkColorToUnpremulGrColor4f(skPaint.getColor(), colorSpaceInfo); const GrFPArgs fpArgs(context, &viewM, skPaint.getFilterQuality(), &colorSpaceInfo); // Setup the initial color considering the shader, the SkPaint color, and the presence or not // of per-vertex colors. std::unique_ptr<GrFragmentProcessor> shaderFP; if (!primColorMode || blend_requires_shader(*primColorMode)) { if (shaderProcessor) { shaderFP = std::move(*shaderProcessor); } else if (const auto* shader = as_SB(skPaint.getShader())) { shaderFP = shader->asFragmentProcessor(fpArgs); if (!shaderFP) { return false; } } } // Set this in below cases if the output of the shader/paint-color/paint-alpha/primXfermode is // a known constant value. In that case we can simply apply a color filter during this // conversion without converting the color filter to a GrFragmentProcessor. bool applyColorFilterToPaintColor = false; if (shaderFP) { if (primColorMode) { // There is a blend between the primitive color and the shader color. The shader sees // the opaque paint color. The shader's output is blended using the provided mode by // the primitive color. The blended color is then modulated by the paint's alpha. // The geometry processor will insert the primitive color to start the color chain, so // the GrPaint color will be ignored. GrColor4f shaderInput = origColor.opaque(); shaderFP = GrFragmentProcessor::OverrideInput(std::move(shaderFP), shaderInput); 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 GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor()); if (GrColor_WHITE != 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( GrColor4f::FromGrColor(paintAlpha), GrConstColorProcessor::InputMode::kModulateRGBA)); } } else { // The shader's FP sees the paint unpremul color grPaint->setColor4f(origColor); grPaint->addColorFragmentProcessor(std::move(shaderFP)); } } else { if (primColorMode) { // 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. auto processor = GrConstColorProcessor::Make(origColor.opaque(), GrConstColorProcessor::InputMode::kIgnore); processor = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(processor), *primColorMode); if (processor) { grPaint->addColorFragmentProcessor(std::move(processor)); } grPaint->setColor4f(origColor.opaque()); // We can ignore origColor here - alpha is unchanged by gamma GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor()); if (GrColor_WHITE != 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( GrColor4f::FromGrColor(paintAlpha), GrConstColorProcessor::InputMode::kModulateRGBA)); } } else { // No shader, no primitive color. grPaint->setColor4f(origColor.premul()); applyColorFilterToPaintColor = true; } } SkColorFilter* colorFilter = skPaint.getColorFilter(); if (colorFilter) { if (applyColorFilterToPaintColor) { // If we're in legacy mode, we *must* avoid using the 4f version of the color filter, // because that will combine with the linearized version of the stored color. if (colorSpaceInfo.isGammaCorrect()) { grPaint->setColor4f(GrColor4f::FromSkColor4f( colorFilter->filterColor4f(origColor.toSkColor4f())).premul()); } else { grPaint->setColor4f(SkColorToPremulGrColor4fLegacy( colorFilter->filterColor(skPaint.getColor()))); } } else { auto cfFP = colorFilter->asFragmentProcessor(context, colorSpaceInfo); if (cfFP) { grPaint->addColorFragmentProcessor(std::move(cfFP)); } else { return false; } } } SkMaskFilterBase* maskFilter = as_MFB(skPaint.getMaskFilter()); if (maskFilter) { if (auto mfFP = maskFilter->asFragmentProcessor(fpArgs)) { grPaint->addCoverageFragmentProcessor(std::move(mfFP)); } } // When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field on // the GrPaint to also be null (also kSrcOver). SkASSERT(!grPaint->getXPFactory()); if (!skPaint.isSrcOver()) { grPaint->setXPFactory(SkBlendMode_AsXPFactory(skPaint.getBlendMode())); } #ifndef SK_IGNORE_GPU_DITHER // Conservative default, in case GrPixelConfigToColorType() fails. SkColorType ct = SkColorType::kRGB_565_SkColorType; GrPixelConfigToColorType(colorSpaceInfo.config(), &ct); if (SkPaintPriv::ShouldDither(skPaint, ct) && grPaint->numColorFragmentProcessors() > 0 && !colorSpaceInfo.isGammaCorrect()) { auto ditherFP = GrDitherEffect::Make(colorSpaceInfo.config()); if (ditherFP) { grPaint->addColorFragmentProcessor(std::move(ditherFP)); } } #endif return true; }