blob: 6be7343398b3932467771676c0285c4f0e7a35c1 [file] [log] [blame]
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/ganesh/GrFragmentProcessors.h"
#include "include/core/SkColorSpace.h" // IWYU pragma: keep
#include "include/core/SkData.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkRefCnt.h"
#include "include/effects/SkRuntimeEffect.h"
#include "include/gpu/GrRecordingContext.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkTArray.h"
#include "src/core/SkBlendModeBlender.h"
#include "src/core/SkBlenderBase.h"
#include "src/core/SkColorFilterBase.h"
#include "src/core/SkMaskFilterBase.h"
#include "src/core/SkRuntimeBlender.h"
#include "src/core/SkRuntimeEffectPriv.h"
#include "src/effects/SkShaderMaskFilterImpl.h"
#include "src/gpu/ganesh/GrCaps.h"
#include "src/gpu/ganesh/GrColorInfo.h"
#include "src/gpu/ganesh/GrFPArgs.h"
#include "src/gpu/ganesh/GrFragmentProcessor.h"
#include "src/gpu/ganesh/GrRecordingContextPriv.h"
#include "src/gpu/ganesh/effects/GrBlendFragmentProcessor.h"
#include "src/gpu/ganesh/effects/GrSkSLFP.h"
#include "src/shaders/SkShaderBase.h"
#include <memory>
#include <optional>
#include <utility>
#include <vector>
namespace GrFragmentProcessors {
static std::unique_ptr<GrFragmentProcessor>
make_fp_from_shader_mask_filter(const SkMaskFilterBase* maskfilter,
const GrFPArgs& args,
const SkMatrix& ctm) {
SkASSERT(maskfilter);
auto shaderMF = static_cast<const SkShaderMaskFilterImpl*>(maskfilter);
auto fp = as_SB(shaderMF->shader())->asFragmentProcessor(args, SkShaderBase::MatrixRec(ctm));
return GrFragmentProcessor::MulInputByChildAlpha(std::move(fp));
}
std::unique_ptr<GrFragmentProcessor> Make(const SkMaskFilter* maskfilter,
const GrFPArgs& args,
const SkMatrix& ctm) {
if (!maskfilter) {
return nullptr;
}
auto mfb = as_MFB(maskfilter);
switch (mfb->type()) {
case SkMaskFilterBase::Type::kShader:
return make_fp_from_shader_mask_filter(mfb, args, ctm);
case SkMaskFilterBase::Type::kBlur:
case SkMaskFilterBase::Type::kEmboss:
case SkMaskFilterBase::Type::kSDF:
case SkMaskFilterBase::Type::kTable:
return nullptr;
}
SkUNREACHABLE;
}
using ChildType = SkRuntimeEffect::ChildType;
GrFPResult make_effect_fp(sk_sp<SkRuntimeEffect> effect,
const char* name,
sk_sp<const SkData> uniforms,
std::unique_ptr<GrFragmentProcessor> inputFP,
std::unique_ptr<GrFragmentProcessor> destColorFP,
SkSpan<const SkRuntimeEffect::ChildPtr> children,
const GrFPArgs& childArgs) {
skia_private::STArray<8, std::unique_ptr<GrFragmentProcessor>> childFPs;
for (const auto& child : children) {
std::optional<ChildType> type = child.type();
if (type == ChildType::kShader) {
// Convert a SkShader into a child FP.
SkShaderBase::MatrixRec mRec(SkMatrix::I());
mRec.markTotalMatrixInvalid();
auto childFP = as_SB(child.shader())->asFragmentProcessor(childArgs, mRec);
if (!childFP) {
return GrFPFailure(std::move(inputFP));
}
childFPs.push_back(std::move(childFP));
} else if (type == ChildType::kColorFilter) {
// Convert a SkColorFilter into a child FP.
auto [success, childFP] = as_CFB(child.colorFilter())
->asFragmentProcessor(/*inputFP=*/nullptr,
childArgs.fContext,
*childArgs.fDstColorInfo,
childArgs.fSurfaceProps);
if (!success) {
return GrFPFailure(std::move(inputFP));
}
childFPs.push_back(std::move(childFP));
} else if (type == ChildType::kBlender) {
// Convert a SkBlender into a child FP.
auto childFP = GrFragmentProcessors::Make(as_BB(child.blender()),
/*srcFP=*/nullptr,
GrFragmentProcessor::DestColor(),
childArgs);
if (!childFP) {
return GrFPFailure(std::move(inputFP));
}
childFPs.push_back(std::move(childFP));
} else {
// We have a null child effect.
childFPs.push_back(nullptr);
}
}
auto fp = GrSkSLFP::MakeWithData(std::move(effect),
name,
childArgs.fDstColorInfo->refColorSpace(),
std::move(inputFP),
std::move(destColorFP),
std::move(uniforms),
SkSpan(childFPs));
SkASSERT(fp);
return GrFPSuccess(std::move(fp));
}
static std::unique_ptr<GrFragmentProcessor> make_blender_fp(
const SkRuntimeBlender* rtb,
std::unique_ptr<GrFragmentProcessor> srcFP,
std::unique_ptr<GrFragmentProcessor> dstFP,
const GrFPArgs& fpArgs) {
SkASSERT(rtb);
if (!SkRuntimeEffectPriv::CanDraw(fpArgs.fContext->priv().caps(), rtb->effect().get())) {
return nullptr;
}
sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
rtb->effect()->uniforms(),
rtb->uniforms(),
fpArgs.fDstColorInfo->colorSpace());
SkASSERT(uniforms);
auto children = rtb->children();
auto [success, fp] = make_effect_fp(rtb->effect(),
"runtime_blender",
std::move(uniforms),
std::move(srcFP),
std::move(dstFP),
SkSpan(children),
fpArgs);
return success ? std::move(fp) : nullptr;
}
static std::unique_ptr<GrFragmentProcessor> make_blender_fp(
const SkBlendModeBlender* blender,
std::unique_ptr<GrFragmentProcessor> srcFP,
std::unique_ptr<GrFragmentProcessor> dstFP,
const GrFPArgs& fpArgs) {
SkASSERT(blender);
return GrBlendFragmentProcessor::Make(std::move(srcFP), std::move(dstFP), blender->mode());
}
std::unique_ptr<GrFragmentProcessor> Make(const SkBlenderBase* blender,
std::unique_ptr<GrFragmentProcessor> srcFP,
std::unique_ptr<GrFragmentProcessor> dstFP,
const GrFPArgs& fpArgs) {
if (!blender) {
return nullptr;
}
switch (blender->type()) {
#define M(type) \
case SkBlenderBase::BlenderType::k##type: \
return make_blender_fp(static_cast<const Sk##type##Blender*>(blender), \
std::move(srcFP), \
std::move(dstFP), \
fpArgs);
SK_ALL_BLENDERS(M)
#undef M
}
SkUNREACHABLE;
}
bool IsSupported(const SkMaskFilter* maskfilter) {
if (!maskfilter) {
return false;
}
auto mfb = as_MFB(maskfilter);
switch (mfb->type()) {
case SkMaskFilterBase::Type::kShader:
return true;
case SkMaskFilterBase::Type::kBlur:
case SkMaskFilterBase::Type::kEmboss:
case SkMaskFilterBase::Type::kSDF:
case SkMaskFilterBase::Type::kTable:
return false;
}
SkUNREACHABLE;
}
} // namespace GrFragmentProcessors