Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Functions
SkMatrixConvolutionImageFilter.cpp File Reference
#include "include/effects/SkImageFilters.h"
#include "include/core/SkAlphaType.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkColorType.h"
#include "include/core/SkFlattenable.h"
#include "include/core/SkImage.h"
#include "include/core/SkImageFilter.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkM44.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSamplingOptions.h"
#include "include/core/SkScalar.h"
#include "include/core/SkShader.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkTileMode.h"
#include "include/core/SkTypes.h"
#include "include/effects/SkRuntimeEffect.h"
#include "include/private/base/SkMath.h"
#include "include/private/base/SkMutex.h"
#include "include/private/base/SkSpan_impl.h"
#include "include/private/base/SkTArray.h"
#include "include/private/base/SkTemplates.h"
#include "include/private/base/SkThreadAnnotations.h"
#include "src/base/SkMathPriv.h"
#include "src/base/SkSafeMath.h"
#include "src/core/SkImageFilterTypes.h"
#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkLRUCache.h"
#include "src/core/SkPicturePriv.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkRectPriv.h"
#include "src/core/SkRuntimeEffectPriv.h"
#include "src/core/SkWriteBuffer.h"
#include <cstdint>
#include <cstring>
#include <optional>
#include <utility>

Go to the source code of this file.

Functions

void SkRegisterMatrixConvolutionImageFilterFlattenable ()
 
static sk_sp< SkRuntimeEffectget_runtime_effect (int texWidth, int texHeight)
 

Function Documentation

◆ get_runtime_effect()

static sk_sp< SkRuntimeEffect > get_runtime_effect ( int  texWidth,
int  texHeight 
)
static

Definition at line 355 of file SkMatrixConvolutionImageFilter.cpp.

355 {
356 // While the loop structure and uniforms are different, pieces of the algorithm are common and
357 // defined statically for re-use in the two shaders:
358 static const char* kHeaderSkSL =
359 "uniform int2 size;"
360 "uniform int2 offset;"
361 "uniform half2 gainAndBias;"
362 "uniform int convolveAlpha;" // FIXME not a full int?
363
364 "uniform shader child;"
365
366 "half4 main(float2 coord) {"
367 "half4 sum = half4(0);"
368 "half origAlpha = 0;";
369
370 // Used in the inner loop to accumulate convolution sum
371 static const char* kAccumulateSkSL =
372 "half4 c = child.eval(coord + half2(kernelPos) - half2(offset));"
373 "if (convolveAlpha == 0) {"
374 // When not convolving alpha, remember the original alpha for actual sample
375 // coord, and perform accumulation on unpremul colors.
376 "if (kernelPos == offset) {"
377 "origAlpha = c.a;"
378 "}"
379 "c = unpremul(c);"
380 "}"
381 "sum += c*k;";
382
383 // Used after the loop to calculate final color
384 static const char* kFooterSkSL =
385 "half4 color = sum*gainAndBias.x + gainAndBias.y;"
386 "if (convolveAlpha == 0) {"
387 // Reset the alpha to the original and convert to premul RGB
388 "color = half4(color.rgb*origAlpha, origAlpha);"
389 "} else {"
390 // Ensure convolved alpha is within [0, 1]
391 "color.a = saturate(color.a);"
392 "}"
393 // Make RGB valid premul w/ respect to the alpha (either original or convolved)
394 "color.rgb = clamp(color.rgb, 0, color.a);"
395 "return color;"
396 "}";
397
398 // The uniform array storing the kernel is packed into half4's so that we don't waste space
399 // forcing array elements out to 16-byte alignment when using std140.
400 static_assert(kMaxUniformKernelSize % 4 == 0, "Must be a multiple of 4");
402 SkStringPrintf("const int kMaxUniformKernelSize = %d / 4;"
403 "uniform half4 kernel[kMaxUniformKernelSize];"
404 "%s" // kHeaderSkSL
405 "int2 kernelPos = int2(0);"
406 "for (int i = 0; i < kMaxUniformKernelSize; ++i) {"
407 "if (kernelPos.y >= size.y) { break; }"
408
409 "half4 k4 = kernel[i];"
410 "for (int j = 0; j < 4; ++j) {"
411 "if (kernelPos.y >= size.y) { break; }"
412 "half k = k4[j];"
413 "%s" // kAccumulateSkSL
414
415 // The 1D index has to be "constant", so reconstruct 2D coords
416 // instead of a more conventional double for-loop and i=y*w+x
417 "kernelPos.x += 1;"
418 "if (kernelPos.x >= size.x) {"
419 "kernelPos.x = 0;"
420 "kernelPos.y += 1;"
421 "}"
422 "}"
423 "}"
424 "%s", // kFooterSkSL
425 kMaxUniformKernelSize, kHeaderSkSL, kAccumulateSkSL, kFooterSkSL).c_str());
426
427 // The texture-backed kernel creates shaders with quantized upper bounds on the kernel size and
428 // then stored in a thread-safe LRU cache.
429 static SkMutex cacheLock;
431 textureShaderCache SK_GUARDED_BY(cacheLock) {/*maxCount=*/5};
432 static const auto makeTextureEffect = [](SkISize maxKernelSize) {
434 SkStringPrintf("const int kMaxKernelWidth = %d;"
435 "const int kMaxKernelHeight = %d;"
436 "uniform shader kernel;"
437 "uniform half2 innerGainAndBias;"
438 "%s" // kHeaderSkSL
439 "for (int y = 0; y < kMaxKernelHeight; ++y) {"
440 "if (y >= size.y) { break; }"
441 "for (int x = 0; x < kMaxKernelWidth; ++x) {"
442 "if (x >= size.x) { break; }"
443
444 "int2 kernelPos = int2(x,y);"
445 "half k = kernel.eval(half2(kernelPos) + 0.5).a;"
446 "k = k * innerGainAndBias.x + innerGainAndBias.y;"
447 "%s" // kAccumulateSkSL
448 "}"
449 "}"
450 "%s", // kFooterSkSL
451 maxKernelSize.fWidth, maxKernelSize.fHeight,
452 kHeaderSkSL, kAccumulateSkSL, kFooterSkSL).c_str());
453 };
454
455
456 if (texWidth == 0 && texHeight == 0) {
457 return sk_ref_sp(uniformEffect);
458 } else {
459 static_assert(kMaxKernelSize % 4 == 0, "Must be a multiple of 4");
460 SkASSERT(SkSafeMath::Mul(texWidth, texHeight) <= kMaxKernelSize);
461 const SkISize key = {SkNextPow2(texWidth), SkNextPow2(texHeight)};
462
463 SkAutoMutexExclusive acquire{cacheLock};
464 sk_sp<SkRuntimeEffect>* effect = textureShaderCache.find(key);
465 if (!effect) {
466 // Adopt the raw pointer returned by makeTextureEffect so that it will be deleted if
467 // it's removed from the LRU cache.
468 sk_sp<SkRuntimeEffect> newEffect{makeTextureEffect(key)};
469 effect = textureShaderCache.insert(key, std::move(newEffect));
470 }
471
472 return *effect;
473 }
474}
#define SkASSERT(cond)
Definition SkAssert.h:116
static int SkNextPow2(int value)
Definition SkMathPriv.h:272
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
SkRuntimeEffect * SkMakeRuntimeEffect(SkRuntimeEffect::Result(*make)(SkString, const SkRuntimeEffect::Options &), const char *sksl, SkRuntimeEffect::Options options=SkRuntimeEffect::Options{})
SK_API SkString static SkString SkStringPrintf()
Definition SkString.h:287
#define SK_GUARDED_BY(x)
static Result MakeForShader(SkString sksl, const Options &)
static size_t Mul(size_t x, size_t y)
const char * c_str() const
Definition SkString.h:133

◆ SkRegisterMatrixConvolutionImageFilterFlattenable()

void SkRegisterMatrixConvolutionImageFilterFlattenable ( )

Definition at line 268 of file SkMatrixConvolutionImageFilter.cpp.

268 {
269 SK_REGISTER_FLATTENABLE(SkMatrixConvolutionImageFilter);
270 // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
271 SkFlattenable::Register("SkMatrixConvolutionImageFilterImpl",
272 SkMatrixConvolutionImageFilter::CreateProc);
273}
#define SK_REGISTER_FLATTENABLE(type)
static void Register(const char name[], Factory)