centralize runtime effect caching
Relative runtimes for creating luma color filter: - cached SkColorFilter --> 1x - cached SkRuntimeEffect --> 12x - no caching --> 186x - this CL --> 24x Added insert_or_update() to SkLRUCache because I keep falling into this trap using insert()... Change-Id: Ic3dad32d38fc001701d8e1ad5662ad382503418f Reviewed-on: https://skia-review.googlesource.com/c/skia/+/376776 Commit-Queue: Mike Klein <mtklein@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
6706c9fa14
commit
ef7a28e26a
@ -443,16 +443,13 @@ sk_sp<SkColorFilter> SkColorFilters::Lerp(float weight, sk_sp<SkColorFilter> cf0
|
|||||||
return cf1;
|
return cf1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SkRuntimeEffect* effect = [&]{
|
auto [effect,err] = SkRuntimeEffect::Make(SkString{
|
||||||
auto [effect,err] = SkRuntimeEffect::Make(SkString{
|
"uniform shader cf0;"
|
||||||
"uniform shader cf0;"
|
"uniform shader cf1;"
|
||||||
"uniform shader cf1;"
|
"uniform half weight;"
|
||||||
"uniform half weight;"
|
"half4 main() { return mix(sample(cf0), sample(cf1), weight); }"
|
||||||
"half4 main() { return mix(sample(cf0), sample(cf1), weight); }"
|
});
|
||||||
});
|
SkASSERT(effect && err.isEmpty());
|
||||||
SkASSERT(effect && err.isEmpty());
|
|
||||||
return effect.release();
|
|
||||||
}();
|
|
||||||
|
|
||||||
sk_sp<SkColorFilter> inputs[] = {cf0,cf1};
|
sk_sp<SkColorFilter> inputs[] = {cf0,cf1};
|
||||||
return effect->makeColorFilter(SkData::MakeWithCopy(&weight, sizeof(weight)),
|
return effect->makeColorFilter(SkData::MakeWithCopy(&weight, sizeof(weight)),
|
||||||
|
@ -56,6 +56,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
V* insert(const K& key, V value) {
|
V* insert(const K& key, V value) {
|
||||||
|
SkASSERT(!this->find(key));
|
||||||
|
|
||||||
Entry* entry = new Entry(key, std::move(value));
|
Entry* entry = new Entry(key, std::move(value));
|
||||||
fMap.set(entry);
|
fMap.set(entry);
|
||||||
fLRU.addToHead(entry);
|
fLRU.addToHead(entry);
|
||||||
@ -65,6 +67,15 @@ public:
|
|||||||
return &entry->fValue;
|
return &entry->fValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
V* insert_or_update(const K& key, V value) {
|
||||||
|
if (V* found = this->find(key)) {
|
||||||
|
*found = std::move(value);
|
||||||
|
return found;
|
||||||
|
} else {
|
||||||
|
return this->insert(key, std::move(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int count() {
|
int count() {
|
||||||
return fMap.count();
|
return fMap.count();
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,9 @@
|
|||||||
#include "src/core/SkColorFilterBase.h"
|
#include "src/core/SkColorFilterBase.h"
|
||||||
#include "src/core/SkColorSpacePriv.h"
|
#include "src/core/SkColorSpacePriv.h"
|
||||||
#include "src/core/SkColorSpaceXformSteps.h"
|
#include "src/core/SkColorSpaceXformSteps.h"
|
||||||
|
#include "src/core/SkLRUCache.h"
|
||||||
#include "src/core/SkMatrixProvider.h"
|
#include "src/core/SkMatrixProvider.h"
|
||||||
|
#include "src/core/SkOpts.h"
|
||||||
#include "src/core/SkRasterPipeline.h"
|
#include "src/core/SkRasterPipeline.h"
|
||||||
#include "src/core/SkReadBuffer.h"
|
#include "src/core/SkReadBuffer.h"
|
||||||
#include "src/core/SkUtils.h"
|
#include "src/core/SkUtils.h"
|
||||||
@ -125,7 +127,42 @@ static bool init_uniform_type(const SkSL::Context& ctx,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SK_BEGIN_REQUIRE_DENSE;
|
||||||
|
struct Key {
|
||||||
|
uint32_t skslHashA;
|
||||||
|
uint32_t skslHashB;
|
||||||
|
int inlineThreshold;
|
||||||
|
|
||||||
|
bool operator==(const Key& that) const {
|
||||||
|
return this->skslHashA == that.skslHashA
|
||||||
|
&& this->skslHashB == that.skslHashB
|
||||||
|
&& this->inlineThreshold == that.inlineThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key(const SkString& sksl, const SkRuntimeEffect::Options& options)
|
||||||
|
: skslHashA(SkOpts::hash(sksl.c_str(), sksl.size(), 0))
|
||||||
|
, skslHashB(SkOpts::hash(sksl.c_str(), sksl.size(), 1))
|
||||||
|
, inlineThreshold(options.inlineThreshold) {}
|
||||||
|
};
|
||||||
|
SK_END_REQUIRE_DENSE;
|
||||||
|
|
||||||
|
static SkMutex gCacheLock;
|
||||||
|
|
||||||
|
static SkLRUCache<Key, sk_sp<SkRuntimeEffect>>* cache() {
|
||||||
|
gCacheLock.assertHeld();
|
||||||
|
static auto* cache = new SkLRUCache<Key, sk_sp<SkRuntimeEffect>>(11/*totally arbitrary*/);
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
SkRuntimeEffect::Result SkRuntimeEffect::Make(SkString sksl, const Options& options) {
|
SkRuntimeEffect::Result SkRuntimeEffect::Make(SkString sksl, const Options& options) {
|
||||||
|
Key key(sksl, options);
|
||||||
|
{
|
||||||
|
SkAutoMutexExclusive _(gCacheLock);
|
||||||
|
if (sk_sp<SkRuntimeEffect>* found = cache()->find(key)) {
|
||||||
|
return Result{*found, SkString()};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SkSL::SharedCompiler compiler;
|
SkSL::SharedCompiler compiler;
|
||||||
SkSL::Program::Settings settings;
|
SkSL::Program::Settings settings;
|
||||||
settings.fInlineThreshold = options.inlineThreshold;
|
settings.fInlineThreshold = options.inlineThreshold;
|
||||||
@ -246,6 +283,10 @@ SkRuntimeEffect::Result SkRuntimeEffect::Make(SkString sksl, const Options& opti
|
|||||||
std::move(varyings),
|
std::move(varyings),
|
||||||
usesSampleCoords,
|
usesSampleCoords,
|
||||||
allowColorFilter));
|
allowColorFilter));
|
||||||
|
{
|
||||||
|
SkAutoMutexExclusive _(gCacheLock);
|
||||||
|
cache()->insert_or_update(key, effect);
|
||||||
|
}
|
||||||
return Result{std::move(effect), SkString()};
|
return Result{std::move(effect), SkString()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,12 +563,7 @@ namespace {
|
|||||||
if (SkLRUCache<Key, skvm::Program>* cache = try_acquire_program_cache()) {
|
if (SkLRUCache<Key, skvm::Program>* cache = try_acquire_program_cache()) {
|
||||||
auto cache_program = [&](skvm::Program&& program, Coverage coverage) {
|
auto cache_program = [&](skvm::Program&& program, Coverage coverage) {
|
||||||
if (!program.empty()) {
|
if (!program.empty()) {
|
||||||
Key key = fKey.withCoverage(coverage);
|
cache->insert_or_update(fKey.withCoverage(coverage), std::move(program));
|
||||||
if (skvm::Program* found = cache->find(key)) {
|
|
||||||
*found = std::move(program);
|
|
||||||
} else {
|
|
||||||
cache->insert(key, std::move(program));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
cache_program(std::move(fBlitH), Coverage::Full);
|
cache_program(std::move(fBlitH), Coverage::Full);
|
||||||
|
@ -18,38 +18,35 @@ sk_sp<SkColorFilter> SkHighContrastFilter::Make(const SkHighContrastConfig& conf
|
|||||||
|
|
||||||
struct Uniforms { float grayscale, invertStyle, contrast; };
|
struct Uniforms { float grayscale, invertStyle, contrast; };
|
||||||
|
|
||||||
static SkRuntimeEffect* effect = []{
|
SkString code{R"(
|
||||||
SkString code{R"(
|
uniform shader input;
|
||||||
uniform shader input;
|
uniform half grayscale, invertStyle, contrast;
|
||||||
uniform half grayscale, invertStyle, contrast;
|
)"};
|
||||||
)"};
|
code += kRGB_to_HSL_sksl;
|
||||||
code += kRGB_to_HSL_sksl;
|
code += kHSL_to_RGB_sksl;
|
||||||
code += kHSL_to_RGB_sksl;
|
code += R"(
|
||||||
code += R"(
|
half4 main() {
|
||||||
half4 main() {
|
half4 c = sample(input); // linear unpremul RGBA in dst gamut.
|
||||||
half4 c = sample(input); // linear unpremul RGBA in dst gamut.
|
if (grayscale == 1) {
|
||||||
if (grayscale == 1) {
|
c.rgb = dot(half3(0.2126, 0.7152, 0.0722), c.rgb).rrr;
|
||||||
c.rgb = dot(half3(0.2126, 0.7152, 0.0722), c.rgb).rrr;
|
|
||||||
}
|
|
||||||
if (invertStyle == 1/*brightness*/) {
|
|
||||||
c.rgb = 1 - c.rgb;
|
|
||||||
} else if (invertStyle == 2/*lightness*/) {
|
|
||||||
c.rgb = rgb_to_hsl(c.rgb);
|
|
||||||
c.b = 1 - c.b;
|
|
||||||
c.rgb = hsl_to_rgb(c.rgb);
|
|
||||||
}
|
|
||||||
c.rgb = mix(half3(0.5), c.rgb, contrast);
|
|
||||||
return half4(saturate(c.rgb), c.a);
|
|
||||||
}
|
}
|
||||||
)";
|
if (invertStyle == 1/*brightness*/) {
|
||||||
|
c.rgb = 1 - c.rgb;
|
||||||
auto [effect, err] = SkRuntimeEffect::Make(code);
|
} else if (invertStyle == 2/*lightness*/) {
|
||||||
if (!err.isEmpty()) {
|
c.rgb = rgb_to_hsl(c.rgb);
|
||||||
SkDebugf("%s\n%s\n", code.c_str(), err.c_str());
|
c.b = 1 - c.b;
|
||||||
|
c.rgb = hsl_to_rgb(c.rgb);
|
||||||
|
}
|
||||||
|
c.rgb = mix(half3(0.5), c.rgb, contrast);
|
||||||
|
return half4(saturate(c.rgb), c.a);
|
||||||
}
|
}
|
||||||
SkASSERT(effect && err.isEmpty());
|
)";
|
||||||
return effect.release();
|
|
||||||
}();
|
auto [effect, err] = SkRuntimeEffect::Make(code);
|
||||||
|
if (!err.isEmpty()) {
|
||||||
|
SkDebugf("%s\n%s\n", code.c_str(), err.c_str());
|
||||||
|
}
|
||||||
|
SkASSERT(effect && err.isEmpty());
|
||||||
|
|
||||||
// A contrast setting of exactly +1 would divide by zero (1+c)/(1-c), so pull in to +1-ε.
|
// A contrast setting of exactly +1 would divide by zero (1+c)/(1-c), so pull in to +1-ε.
|
||||||
// I'm not exactly sure why we've historically pinned -1 up to -1+ε, maybe just symmetry?
|
// I'm not exactly sure why we've historically pinned -1 up to -1+ε, maybe just symmetry?
|
||||||
|
@ -10,17 +10,14 @@
|
|||||||
#include "include/effects/SkRuntimeEffect.h"
|
#include "include/effects/SkRuntimeEffect.h"
|
||||||
|
|
||||||
sk_sp<SkColorFilter> SkLumaColorFilter::Make() {
|
sk_sp<SkColorFilter> SkLumaColorFilter::Make() {
|
||||||
static SkColorFilter* filter = []{
|
const char* code =
|
||||||
const char* code =
|
"uniform shader input;"
|
||||||
"uniform shader input;"
|
"half4 main() {"
|
||||||
"half4 main() {"
|
"return saturate(dot(half3(0.2126, 0.7152, 0.0722), sample(input).rgb)).000r;"
|
||||||
"return saturate(dot(half3(0.2126, 0.7152, 0.0722), sample(input).rgb)).000r;"
|
"}";
|
||||||
"}";
|
auto [effect, err] = SkRuntimeEffect::Make(SkString{code});
|
||||||
auto [effect, err] = SkRuntimeEffect::Make(SkString{code}, SkRuntimeEffect::Options{});
|
SkASSERT(effect && err.isEmpty());
|
||||||
SkASSERT(effect && err.isEmpty());
|
|
||||||
|
|
||||||
sk_sp<SkColorFilter> input = nullptr;
|
sk_sp<SkColorFilter> input = nullptr;
|
||||||
return effect->makeColorFilter(SkData::MakeEmpty(), &input, 1).release();
|
return effect->makeColorFilter(SkData::MakeEmpty(), &input, 1);
|
||||||
}();
|
|
||||||
return sk_ref_sp(filter);
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user