Add GrRuntimeFPBuilder

Like SkRuntimeShaderBuilder but for internal use for creating FPs.

Currently it requires that the code be a static string so it can
easily make a static SkRuntimeEffect instance for each effect.

Bug: skia:11771

Change-Id: I18148eb33e7d28c804e4a13bcef88c89c06b2c9b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/386889
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Salomon 2021-03-22 09:21:25 -04:00 committed by Skia Commit-Bot
parent 4a3bae335f
commit 4b39aaf2cb
11 changed files with 172 additions and 208 deletions

View File

@ -342,8 +342,6 @@ skia_gpu_sources = [
"$_src/gpu/effects/generated/GrClampFragmentProcessor.h",
"$_src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp",
"$_src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h",
"$_src/gpu/effects/generated/GrComposeLerpEffect.cpp",
"$_src/gpu/effects/generated/GrComposeLerpEffect.h",
"$_src/gpu/effects/generated/GrConfigConversionEffect.cpp",
"$_src/gpu/effects/generated/GrConfigConversionEffect.h",
"$_src/gpu/effects/generated/GrConstColorProcessor.cpp",

View File

@ -187,7 +187,6 @@ skia_gpu_processor_sources = [
"$_src/gpu/effects/GrCircleEffect.fp",
"$_src/gpu/effects/GrClampFragmentProcessor.fp",
"$_src/gpu/effects/GrColorMatrixFragmentProcessor.fp",
"$_src/gpu/effects/GrComposeLerpEffect.fp",
"$_src/gpu/effects/GrConfigConversionEffect.fp",
"$_src/gpu/effects/GrConstColorProcessor.fp",
"$_src/gpu/effects/GrDeviceSpaceEffect.fp",

View File

@ -17,6 +17,7 @@
#include <vector>
class GrFragmentProcessor;
class GrRecordingContext;
class SkColorFilter;
class SkImage;
@ -96,7 +97,7 @@ public:
sk_sp<SkShader> children[],
size_t childCount,
const SkMatrix* localMatrix,
bool isOpaque);
bool isOpaque) const;
sk_sp<SkImage> makeImage(GrRecordingContext*,
sk_sp<SkData> uniforms,
@ -104,12 +105,12 @@ public:
size_t childCount,
const SkMatrix* localMatrix,
SkImageInfo resultInfo,
bool mipmapped);
bool mipmapped) const;
sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms);
sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms) const;
sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms,
sk_sp<SkColorFilter> children[],
size_t childCount);
size_t childCount) const;
const SkString& source() const { return fSkSL; }
@ -145,6 +146,14 @@ public:
static void RegisterFlattenables();
~SkRuntimeEffect() override;
#if SK_SUPPORT_GPU
// For internal use.
std::unique_ptr<GrFragmentProcessor> makeFP(GrRecordingContext*,
sk_sp<SkData> uniforms,
std::unique_ptr<GrFragmentProcessor> children[],
size_t childCount) const;
#endif
private:
SkRuntimeEffect(SkString sksl,
std::unique_ptr<SkSL::Program> baseProgram,
@ -184,31 +193,9 @@ private:
bool fAllowColorFilter;
};
/**
* SkRuntimeShaderBuilder is a utility to simplify creating SkShader objects from SkRuntimeEffects.
*
* NOTE: Like SkRuntimeEffect, this API is experimental and subject to change!
*
* Given an SkRuntimeEffect, the SkRuntimeShaderBuilder manages creating an input data block and
* provides named access to the 'uniform' variables in that block, as well as named access
* to a list of child shader slots. Usage:
*
* sk_sp<SkRuntimeEffect> effect = ...;
* SkRuntimeShaderBuilder builder(effect);
* builder.uniform("some_uniform_float") = 3.14f;
* builder.uniform("some_uniform_matrix") = SkM44::Rotate(...);
* builder.child("some_child_effect") = mySkImage->makeShader(...);
* ...
* sk_sp<SkShader> shader = builder.makeShader(nullptr, false);
*
* Note that SkRuntimeShaderBuilder is built entirely on the public API of SkRuntimeEffect,
* so can be used as-is or serve as inspiration for other interfaces or binding techniques.
*/
class SkRuntimeShaderBuilder {
/** Base class for SkRuntimeShaderBuilder, defined below. */
template <typename Child> class SkRuntimeEffectBuilder {
public:
SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect>);
~SkRuntimeShaderBuilder();
struct BuilderUniform {
// Copy 'val' to this variable. No type conversion is performed - 'val' must be same
// size as expected by the effect. Information about the variable can be queried by
@ -259,14 +246,21 @@ public:
return true;
}
SkRuntimeShaderBuilder* fOwner;
SkRuntimeEffectBuilder* fOwner;
const SkRuntimeEffect::Uniform* fVar; // nullptr if the variable was not found
};
struct BuilderChild {
BuilderChild& operator=(const sk_sp<SkShader>& val);
template <typename C> BuilderChild& operator=(C&& val) {
if (fIndex < 0) {
SkDEBUGFAIL("Assigning to missing child");
} else {
fOwner->fChildren[fIndex] = std::forward<C>(val);
}
return *this;
}
SkRuntimeShaderBuilder* fOwner;
SkRuntimeEffectBuilder* fOwner;
int fIndex; // -1 if the child was not found
};
@ -275,6 +269,60 @@ public:
BuilderUniform uniform(const char* name) { return { this, fEffect->findUniform(name) }; }
BuilderChild child(const char* name) { return { this, fEffect->findChild(name) }; }
protected:
explicit SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect)
: fEffect(std::move(effect))
, fUniforms(SkData::MakeUninitialized(fEffect->uniformSize()))
, fChildren(fEffect->children().count()) {}
SkRuntimeEffectBuilder(SkRuntimeEffectBuilder&&) = default;
SkRuntimeEffectBuilder(const SkRuntimeEffectBuilder&) = delete;
SkRuntimeEffectBuilder& operator=(SkRuntimeEffectBuilder&&) = default;
SkRuntimeEffectBuilder& operator=(const SkRuntimeEffectBuilder&) = delete;
sk_sp<SkData> uniforms() { return fUniforms; }
Child* children() { return fChildren.data(); }
size_t numChildren() { return fChildren.size(); }
private:
void* writableUniformData() {
if (!fUniforms->unique()) {
fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size());
}
return fUniforms->writable_data();
}
sk_sp<SkRuntimeEffect> fEffect;
sk_sp<SkData> fUniforms;
std::vector<Child> fChildren;
};
/**
* SkRuntimeShaderBuilder is a utility to simplify creating SkShader objects from SkRuntimeEffects.
*
* NOTE: Like SkRuntimeEffect, this API is experimental and subject to change!
*
* Given an SkRuntimeEffect, the SkRuntimeShaderBuilder manages creating an input data block and
* provides named access to the 'uniform' variables in that block, as well as named access
* to a list of child shader slots. Usage:
*
* sk_sp<SkRuntimeEffect> effect = ...;
* SkRuntimeShaderBuilder builder(effect);
* builder.uniform("some_uniform_float") = 3.14f;
* builder.uniform("some_uniform_matrix") = SkM44::Rotate(...);
* builder.child("some_child_effect") = mySkImage->makeShader(...);
* ...
* sk_sp<SkShader> shader = builder.makeShader(nullptr, false);
*
* Note that SkRuntimeShaderBuilder is built entirely on the public API of SkRuntimeEffect,
* so can be used as-is or serve as inspiration for other interfaces or binding techniques.
*/
class SK_API SkRuntimeShaderBuilder : public SkRuntimeEffectBuilder<sk_sp<SkShader>> {
public:
explicit SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect>);
~SkRuntimeShaderBuilder();
sk_sp<SkShader> makeShader(const SkMatrix* localMatrix, bool isOpaque);
sk_sp<SkImage> makeImage(GrRecordingContext*,
const SkMatrix* localMatrix,
@ -282,11 +330,7 @@ public:
bool mipmapped);
private:
void* writableUniformData();
sk_sp<SkRuntimeEffect> fEffect;
sk_sp<SkData> fUniforms;
std::vector<sk_sp<SkShader>> fChildren;
using INHERITED = SkRuntimeEffectBuilder<sk_sp<SkShader>>;
};
#endif

View File

@ -799,9 +799,28 @@ sk_sp<SkFlattenable> SkRTShader::CreateProc(SkReadBuffer& buffer) {
///////////////////////////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> SkRuntimeEffect::makeFP(
GrRecordingContext* recordingContext,
sk_sp<SkData> uniforms,
std::unique_ptr<GrFragmentProcessor> children[],
size_t childCount) const {
if (!uniforms) {
uniforms = SkData::MakeEmpty();
}
auto fp = GrSkSLFP::Make(recordingContext, sk_ref_sp(this), "make_fp", std::move(uniforms));
for (size_t i = 0; i < childCount; ++i) {
fp->addChild(std::move(children[i]));
}
return std::move(fp);
}
#endif
sk_sp<SkShader> SkRuntimeEffect::makeShader(sk_sp<SkData> uniforms,
sk_sp<SkShader> children[], size_t childCount,
const SkMatrix* localMatrix, bool isOpaque) {
sk_sp<SkShader> children[],
size_t childCount,
const SkMatrix* localMatrix,
bool isOpaque) const {
if (!uniforms) {
uniforms = SkData::MakeEmpty();
}
@ -817,7 +836,7 @@ sk_sp<SkImage> SkRuntimeEffect::makeImage(GrRecordingContext* recordingContext,
size_t childCount,
const SkMatrix* localMatrix,
SkImageInfo resultInfo,
bool mipmapped) {
bool mipmapped) const {
if (recordingContext) {
#if SK_SUPPORT_GPU
if (!recordingContext->priv().caps()->mipmapSupport()) {
@ -897,7 +916,7 @@ sk_sp<SkImage> SkRuntimeEffect::makeImage(GrRecordingContext* recordingContext,
sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> uniforms,
sk_sp<SkColorFilter> children[],
size_t childCount) {
size_t childCount) const {
if (!fAllowColorFilter) {
return nullptr;
}
@ -910,7 +929,7 @@ sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> uniforms,
: nullptr;
}
sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> uniforms) {
sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> uniforms) const {
return this->makeColorFilter(std::move(uniforms), nullptr, 0);
}
@ -922,42 +941,27 @@ void SkRuntimeEffect::RegisterFlattenables() {
}
SkRuntimeShaderBuilder::SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect> effect)
: fEffect(std::move(effect))
, fUniforms(SkData::MakeUninitialized(fEffect->uniformSize()))
, fChildren(fEffect->children().count()) {}
: INHERITED(std::move(effect)) {}
SkRuntimeShaderBuilder::~SkRuntimeShaderBuilder() = default;
void* SkRuntimeShaderBuilder::writableUniformData() {
if (!fUniforms->unique()) {
fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size());
}
return fUniforms->writable_data();
}
sk_sp<SkShader> SkRuntimeShaderBuilder::makeShader(const SkMatrix* localMatrix, bool isOpaque) {
return fEffect->makeShader(fUniforms, fChildren.data(), fChildren.size(), localMatrix, isOpaque);
}
sk_sp<SkImage> SkRuntimeShaderBuilder::makeImage(GrRecordingContext* recordingContext,
const SkMatrix* localMatrix,
SkImageInfo resultInfo,
bool mipmapped) {
return fEffect->makeImage(recordingContext,
fUniforms,
fChildren.data(),
fChildren.size(),
localMatrix,
resultInfo,
mipmapped);
return this->effect()->makeImage(recordingContext,
this->uniforms(),
this->children(),
this->numChildren(),
localMatrix,
resultInfo,
mipmapped);
}
SkRuntimeShaderBuilder::BuilderChild&
SkRuntimeShaderBuilder::BuilderChild::operator=(const sk_sp<SkShader>& val) {
if (fIndex < 0) {
SkDEBUGFAIL("Assigning to missing child");
} else {
fOwner->fChildren[fIndex] = val;
}
return *this;
sk_sp<SkShader> SkRuntimeShaderBuilder::makeShader(const SkMatrix* localMatrix, bool isOpaque) {
return this->effect()->makeShader(this->uniforms(),
this->children(),
this->numChildren(),
localMatrix,
isOpaque);
}

View File

@ -67,7 +67,6 @@ public:
kGrClampFragmentProcessor_ClassID,
kGrColorMatrixFragmentProcessor_ClassID,
kGrColorSpaceXformEffect_ClassID,
kGrComposeLerpEffect_ClassID,
kGrConfigConversionEffect_ClassID,
kGrConicEffect_ClassID,
kGrConstColorProcessor_ClassID,

View File

@ -1,14 +0,0 @@
/*
* Copyright 2019 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
in fragmentProcessor child1;
in fragmentProcessor child2;
in uniform float weight;
half4 main() {
return mix(sample(child1), sample(child2), half(weight));
}

View File

@ -254,3 +254,18 @@ std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d
}
#endif
/**************************************************************************************************/
GrRuntimeFPBuilder::GrRuntimeFPBuilder(sk_sp<SkRuntimeEffect> effect)
: INHERITED(std::move(effect)) {}
GrRuntimeFPBuilder::~GrRuntimeFPBuilder() = default;
std::unique_ptr<GrFragmentProcessor> GrRuntimeFPBuilder::makeFP(
GrRecordingContext* recordingContext) {
return this->effect()->makeFP(recordingContext,
this->uniforms(),
this->children(),
this->numChildren());
}

View File

@ -9,6 +9,7 @@
#define GrSkSLFP_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/effects/SkRuntimeEffect.h"
#include "include/gpu/GrContextOptions.h"
#include "src/gpu/GrFragmentProcessor.h"
#include <atomic>
@ -65,4 +66,27 @@ private:
friend class GrSkSLFPFactory;
};
class GrRuntimeFPBuilder : public SkRuntimeEffectBuilder<std::unique_ptr<GrFragmentProcessor>> {
public:
~GrRuntimeFPBuilder();
template <const char* CODE> static GrRuntimeFPBuilder Make() {
static const SkRuntimeEffect::Result gResult = SkRuntimeEffect::Make(SkString(CODE));
#ifdef SK_DEBUG
if (!gResult.effect) {
SK_ABORT("Code failed: %s", gResult.errorText.c_str());
}
#endif
return GrRuntimeFPBuilder(gResult.effect);
}
std::unique_ptr<GrFragmentProcessor> makeFP(GrRecordingContext*);
private:
explicit GrRuntimeFPBuilder(sk_sp<SkRuntimeEffect>);
GrRuntimeFPBuilder(GrRuntimeFPBuilder&& that) = default;
using INHERITED = SkRuntimeEffectBuilder<std::unique_ptr<GrFragmentProcessor>>;
};
#endif

View File

@ -1,69 +0,0 @@
/*
* Copyright 2019 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**************************************************************************************************
*** This file was autogenerated from GrComposeLerpEffect.fp; do not modify.
**************************************************************************************************/
#include "GrComposeLerpEffect.h"
#include "src/core/SkUtils.h"
#include "src/gpu/GrTexture.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
#include "src/sksl/SkSLCPP.h"
#include "src/sksl/SkSLUtil.h"
class GrGLSLComposeLerpEffect : public GrGLSLFragmentProcessor {
public:
GrGLSLComposeLerpEffect() {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
const GrComposeLerpEffect& _outer = args.fFp.cast<GrComposeLerpEffect>();
(void)_outer;
auto weight = _outer.weight;
(void)weight;
weightVar = args.fUniformHandler->addUniform(
&_outer, kFragment_GrShaderFlag, kFloat_GrSLType, "weight");
SkString _sample0 = this->invokeChild(0, args);
SkString _sample1 = this->invokeChild(1, args);
fragBuilder->codeAppendf(
R"SkSL(return mix(%s, %s, half(%s));
)SkSL",
_sample0.c_str(),
_sample1.c_str(),
args.fUniformHandler->getUniformCStr(weightVar));
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {
const GrComposeLerpEffect& _outer = _proc.cast<GrComposeLerpEffect>();
{ pdman.set1f(weightVar, (_outer.weight)); }
}
UniformHandle weightVar;
};
std::unique_ptr<GrGLSLFragmentProcessor> GrComposeLerpEffect::onMakeProgramImpl() const {
return std::make_unique<GrGLSLComposeLerpEffect>();
}
void GrComposeLerpEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {}
bool GrComposeLerpEffect::onIsEqual(const GrFragmentProcessor& other) const {
const GrComposeLerpEffect& that = other.cast<GrComposeLerpEffect>();
(void)that;
if (weight != that.weight) return false;
return true;
}
GrComposeLerpEffect::GrComposeLerpEffect(const GrComposeLerpEffect& src)
: INHERITED(kGrComposeLerpEffect_ClassID, src.optimizationFlags()), weight(src.weight) {
this->cloneAndRegisterAllChildProcessors(src);
}
std::unique_ptr<GrFragmentProcessor> GrComposeLerpEffect::clone() const {
return std::make_unique<GrComposeLerpEffect>(*this);
}
#if GR_TEST_UTILS
SkString GrComposeLerpEffect::onDumpInfo() const { return SkStringPrintf("(weight=%f)", weight); }
#endif

View File

@ -1,49 +0,0 @@
/*
* Copyright 2019 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**************************************************************************************************
*** This file was autogenerated from GrComposeLerpEffect.fp; do not modify.
**************************************************************************************************/
#ifndef GrComposeLerpEffect_DEFINED
#define GrComposeLerpEffect_DEFINED
#include "include/core/SkM44.h"
#include "include/core/SkTypes.h"
#include "src/gpu/GrFragmentProcessor.h"
class GrComposeLerpEffect : public GrFragmentProcessor {
public:
static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child1,
std::unique_ptr<GrFragmentProcessor> child2,
float weight) {
return std::unique_ptr<GrFragmentProcessor>(
new GrComposeLerpEffect(std::move(child1), std::move(child2), weight));
}
GrComposeLerpEffect(const GrComposeLerpEffect& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "ComposeLerpEffect"; }
float weight;
private:
GrComposeLerpEffect(std::unique_ptr<GrFragmentProcessor> child1,
std::unique_ptr<GrFragmentProcessor> child2,
float weight)
: INHERITED(kGrComposeLerpEffect_ClassID, kNone_OptimizationFlags), weight(weight) {
this->registerChild(std::move(child1), SkSL::SampleUsage::PassThrough());
this->registerChild(std::move(child2), SkSL::SampleUsage::PassThrough());
}
std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
#if GR_TEST_UTILS
SkString onDumpInfo() const override;
#endif
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
using INHERITED = GrFragmentProcessor;
};
#endif

View File

@ -201,7 +201,7 @@ skvm::Color SkShader_Lerp::onProgram(skvm::Builder* p,
#include "include/gpu/GrRecordingContext.h"
#include "src/gpu/effects/GrBlendFragmentProcessor.h"
#include "src/gpu/effects/generated/GrComposeLerpEffect.h"
#include "src/gpu/effects/GrSkSLFP.h"
#include "src/gpu/effects/generated/GrConstColorProcessor.h"
static std::unique_ptr<GrFragmentProcessor> as_fp(const GrFPArgs& args, SkShader* shader) {
@ -221,6 +221,19 @@ std::unique_ptr<GrFragmentProcessor> SkShader_Lerp::asFragmentProcessor(
const GrFPArgs::WithPreLocalMatrix args(orig_args, this->getLocalMatrix());
auto fpA = as_fp(args, fDst.get());
auto fpB = as_fp(args, fSrc.get());
return GrComposeLerpEffect::Make(std::move(fpA), std::move(fpB), fWeight);
static constexpr char kCode[] = R"(
uniform shader a;
uniform shader b;
uniform half w;
half4 main() { return mix(sample(a), sample(b), w); }
)";
auto builder = GrRuntimeFPBuilder::Make<kCode>();
builder.uniform("w") = fWeight;
builder.child("a") = std::move(fpA);
builder.child("b") = std::move(fpB);
return builder.makeFP(args.fContext);
}
#endif