diff options
author | Mike Reed <reed@google.com> | 2018-03-09 16:18:56 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-03-12 13:26:48 +0000 |
commit | 8e03f6930f8e033f3cabfda1a7fba9a6013e3d19 (patch) | |
tree | dafeb4bd8b680f06d4c099dfe6a2d5d44beef4b8 /src/effects | |
parent | 3be061cd8bc5405e03938eb03a7b3125fd9c81fe (diff) |
remove unused ConvertRadiusToSigma from SkBlurMaskFilter
Bug: skia:
Change-Id: I1726f22fc40ad61b1b0485bcda6d383614da1fdb
Reviewed-on: https://skia-review.googlesource.com/113463
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Mike Reed <reed@google.com>
Diffstat (limited to 'src/effects')
-rw-r--r-- | src/effects/SkBlurMask.cpp | 537 | ||||
-rw-r--r-- | src/effects/SkBlurMask.h | 88 | ||||
-rw-r--r-- | src/effects/SkBlurMaskFilter.cpp | 4 |
3 files changed, 0 insertions, 629 deletions
diff --git a/src/effects/SkBlurMask.cpp b/src/effects/SkBlurMask.cpp deleted file mode 100644 index 086977528b..0000000000 --- a/src/effects/SkBlurMask.cpp +++ /dev/null @@ -1,537 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkBlurMask.h" -#include "SkColorPriv.h" -#include "SkMaskBlurFilter.h" -#include "SkMath.h" -#include "SkTemplates.h" -#include "SkEndian.h" - - -// This constant approximates the scaling done in the software path's -// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). -// IMHO, it actually should be 1: we blur "less" than we should do -// according to the CSS and canvas specs, simply because Safari does the same. -// Firefox used to do the same too, until 4.0 where they fixed it. So at some -// point we should probably get rid of these scaling constants and rebaseline -// all the blur tests. -static const SkScalar kBLUR_SIGMA_SCALE = 0.57735f; - -SkScalar SkBlurMask::ConvertRadiusToSigma(SkScalar radius) { - return radius > 0 ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f; -} - -SkScalar SkBlurMask::ConvertSigmaToRadius(SkScalar sigma) { - return sigma > 0.5f ? (sigma - 0.5f) / kBLUR_SIGMA_SCALE : 0.0f; -} - - -static void merge_src_with_blur(uint8_t dst[], int dstRB, - const uint8_t src[], int srcRB, - const uint8_t blur[], int blurRB, - int sw, int sh) { - dstRB -= sw; - srcRB -= sw; - blurRB -= sw; - while (--sh >= 0) { - for (int x = sw - 1; x >= 0; --x) { - *dst = SkToU8(SkAlphaMul(*blur, SkAlpha255To256(*src))); - dst += 1; - src += 1; - blur += 1; - } - dst += dstRB; - src += srcRB; - blur += blurRB; - } -} - -static void clamp_with_orig(uint8_t dst[], int dstRowBytes, - const uint8_t src[], int srcRowBytes, - int sw, int sh, - SkBlurStyle style) { - int x; - while (--sh >= 0) { - switch (style) { - case kSolid_SkBlurStyle: - for (x = sw - 1; x >= 0; --x) { - int s = *src; - int d = *dst; - *dst = SkToU8(s + d - SkMulDiv255Round(s, d)); - dst += 1; - src += 1; - } - break; - case kOuter_SkBlurStyle: - for (x = sw - 1; x >= 0; --x) { - if (*src) { - *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - *src))); - } - dst += 1; - src += 1; - } - break; - default: - SkDEBUGFAIL("Unexpected blur style here"); - break; - } - dst += dstRowBytes - sw; - src += srcRowBytes - sw; - } -} - -/////////////////////////////////////////////////////////////////////////////// - -// we use a local function to wrap the class static method to work around -// a bug in gcc98 -void SkMask_FreeImage(uint8_t* image); -void SkMask_FreeImage(uint8_t* image) { - SkMask::FreeImage(image); -} - -bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, - SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, - SkIPoint* margin, bool force_quality) { - - if (src.fFormat != SkMask::kA8_Format) { - return false; - } - - SkIPoint border; - - SkMaskBlurFilter blurFilter{sigma, sigma}; - if (blurFilter.hasNoBlur()) { - return false; - } - border = blurFilter.blur(src, dst); - // If src.fImage is null, then this call is only to calculate the border. - if (src.fImage != nullptr && dst->fImage == nullptr) { - return false; - } - - if (src.fImage != nullptr) { - // if need be, alloc the "real" dst (same size as src) and copy/merge - // the blur into it (applying the src) - if (style == kInner_SkBlurStyle) { - // now we allocate the "real" dst, mirror the size of src - size_t srcSize = src.computeImageSize(); - if (0 == srcSize) { - return false; // too big to allocate, abort - } - auto blur = dst->fImage; - dst->fImage = SkMask::AllocImage(srcSize); - auto blurStart = &blur[border.x() + border.y() * dst->fRowBytes]; - merge_src_with_blur(dst->fImage, src.fRowBytes, - src.fImage, src.fRowBytes, - blurStart, - dst->fRowBytes, - src.fBounds.width(), src.fBounds.height()); - SkMask::FreeImage(blur); - } else if (style != kNormal_SkBlurStyle) { - auto dstStart = &dst->fImage[border.x() + border.y() * dst->fRowBytes]; - clamp_with_orig(dstStart, - dst->fRowBytes, src.fImage, src.fRowBytes, - src.fBounds.width(), src.fBounds.height(), style); - } - } - - if (style == kInner_SkBlurStyle) { - dst->fBounds = src.fBounds; // restore trimmed bounds - dst->fRowBytes = src.fRowBytes; - } - - if (margin != nullptr) { - *margin = border; - } - - return true; -} - -/* Convolving a box with itself three times results in a piecewise - quadratic function: - - 0 x <= -1.5 - 9/8 + 3/2 x + 1/2 x^2 -1.5 < x <= -.5 - 3/4 - x^2 -.5 < x <= .5 - 9/8 - 3/2 x + 1/2 x^2 0.5 < x <= 1.5 - 0 1.5 < x - - Mathematica: - - g[x_] := Piecewise [ { - {9/8 + 3/2 x + 1/2 x^2 , -1.5 < x <= -.5}, - {3/4 - x^2 , -.5 < x <= .5}, - {9/8 - 3/2 x + 1/2 x^2 , 0.5 < x <= 1.5} - }, 0] - - To get the profile curve of the blurred step function at the rectangle - edge, we evaluate the indefinite integral, which is piecewise cubic: - - 0 x <= -1.5 - 9/16 + 9/8 x + 3/4 x^2 + 1/6 x^3 -1.5 < x <= -0.5 - 1/2 + 3/4 x - 1/3 x^3 -.5 < x <= .5 - 7/16 + 9/8 x - 3/4 x^2 + 1/6 x^3 .5 < x <= 1.5 - 1 1.5 < x - - in Mathematica code: - - gi[x_] := Piecewise[ { - { 0 , x <= -1.5 }, - { 9/16 + 9/8 x + 3/4 x^2 + 1/6 x^3, -1.5 < x <= -0.5 }, - { 1/2 + 3/4 x - 1/3 x^3 , -.5 < x <= .5}, - { 7/16 + 9/8 x - 3/4 x^2 + 1/6 x^3, .5 < x <= 1.5} - },1] -*/ - -static float gaussianIntegral(float x) { - if (x > 1.5f) { - return 0.0f; - } - if (x < -1.5f) { - return 1.0f; - } - - float x2 = x*x; - float x3 = x2*x; - - if ( x > 0.5f ) { - return 0.5625f - (x3 / 6.0f - 3.0f * x2 * 0.25f + 1.125f * x); - } - if ( x > -0.5f ) { - return 0.5f - (0.75f * x - x3 / 3.0f); - } - return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x); -} - -/* ComputeBlurProfile fills in an array of floating - point values between 0 and 255 for the profile signature of - a blurred half-plane with the given blur radius. Since we're - going to be doing screened multiplications (i.e., 1 - (1-x)(1-y)) - all the time, we actually fill in the profile pre-inverted - (already done 255-x). -*/ - -void SkBlurMask::ComputeBlurProfile(uint8_t* profile, int size, SkScalar sigma) { - SkASSERT(SkScalarCeilToInt(6*sigma) == size); - - int center = size >> 1; - - float invr = 1.f/(2*sigma); - - profile[0] = 255; - for (int x = 1 ; x < size ; ++x) { - float scaled_x = (center - x - .5f) * invr; - float gi = gaussianIntegral(scaled_x); - profile[x] = 255 - (uint8_t) (255.f * gi); - } -} - -// TODO MAYBE: Maintain a profile cache to avoid recomputing this for -// commonly used radii. Consider baking some of the most common blur radii -// directly in as static data? - -// Implementation adapted from Michael Herf's approach: -// http://stereopsis.com/shadowrect/ - -uint8_t SkBlurMask::ProfileLookup(const uint8_t *profile, int loc, - int blurredWidth, int sharpWidth) { - // how far are we from the original edge? - int dx = SkAbs32(((loc << 1) + 1) - blurredWidth) - sharpWidth; - int ox = dx >> 1; - if (ox < 0) { - ox = 0; - } - - return profile[ox]; -} - -void SkBlurMask::ComputeBlurredScanline(uint8_t *pixels, const uint8_t *profile, - unsigned int width, SkScalar sigma) { - - unsigned int profile_size = SkScalarCeilToInt(6*sigma); - SkAutoTMalloc<uint8_t> horizontalScanline(width); - - unsigned int sw = width - profile_size; - // nearest odd number less than the profile size represents the center - // of the (2x scaled) profile - int center = ( profile_size & ~1 ) - 1; - - int w = sw - center; - - for (unsigned int x = 0 ; x < width ; ++x) { - if (profile_size <= sw) { - pixels[x] = ProfileLookup(profile, x, width, w); - } else { - float span = float(sw)/(2*sigma); - float giX = 1.5f - (x+.5f)/(2*sigma); - pixels[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span))); - } - } -} - -bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, - const SkRect &src, SkBlurStyle style, - SkIPoint *margin, SkMask::CreateMode createMode) { - int profileSize = SkScalarCeilToInt(6*sigma); - if (profileSize <= 0) { - return false; // no blur to compute - } - - int pad = profileSize/2; - if (margin) { - margin->set( pad, pad ); - } - - dst->fBounds.set(SkScalarRoundToInt(src.fLeft - pad), - SkScalarRoundToInt(src.fTop - pad), - SkScalarRoundToInt(src.fRight + pad), - SkScalarRoundToInt(src.fBottom + pad)); - - dst->fRowBytes = dst->fBounds.width(); - dst->fFormat = SkMask::kA8_Format; - dst->fImage = nullptr; - - int sw = SkScalarFloorToInt(src.width()); - int sh = SkScalarFloorToInt(src.height()); - - if (createMode == SkMask::kJustComputeBounds_CreateMode) { - if (style == kInner_SkBlurStyle) { - dst->fBounds.set(SkScalarRoundToInt(src.fLeft), - SkScalarRoundToInt(src.fTop), - SkScalarRoundToInt(src.fRight), - SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds - dst->fRowBytes = sw; - } - return true; - } - - SkAutoTMalloc<uint8_t> profile(profileSize); - - ComputeBlurProfile(profile, profileSize, sigma); - - size_t dstSize = dst->computeImageSize(); - if (0 == dstSize) { - return false; // too big to allocate, abort - } - - uint8_t* dp = SkMask::AllocImage(dstSize); - - dst->fImage = dp; - - int dstHeight = dst->fBounds.height(); - int dstWidth = dst->fBounds.width(); - - uint8_t *outptr = dp; - - SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); - SkAutoTMalloc<uint8_t> verticalScanline(dstHeight); - - ComputeBlurredScanline(horizontalScanline, profile, dstWidth, sigma); - ComputeBlurredScanline(verticalScanline, profile, dstHeight, sigma); - - for (int y = 0 ; y < dstHeight ; ++y) { - for (int x = 0 ; x < dstWidth ; x++) { - unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], verticalScanline[y]); - *(outptr++) = maskval; - } - } - - if (style == kInner_SkBlurStyle) { - // now we allocate the "real" dst, mirror the size of src - size_t srcSize = (size_t)(src.width() * src.height()); - if (0 == srcSize) { - return false; // too big to allocate, abort - } - dst->fImage = SkMask::AllocImage(srcSize); - for (int y = 0 ; y < sh ; y++) { - uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad; - uint8_t *inner_scanline = dst->fImage + y*sw; - memcpy(inner_scanline, blur_scanline, sw); - } - SkMask::FreeImage(dp); - - dst->fBounds.set(SkScalarRoundToInt(src.fLeft), - SkScalarRoundToInt(src.fTop), - SkScalarRoundToInt(src.fRight), - SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds - dst->fRowBytes = sw; - - } else if (style == kOuter_SkBlurStyle) { - for (int y = pad ; y < dstHeight-pad ; y++) { - uint8_t *dst_scanline = dp + y*dstWidth + pad; - memset(dst_scanline, 0, sw); - } - } else if (style == kSolid_SkBlurStyle) { - for (int y = pad ; y < dstHeight-pad ; y++) { - uint8_t *dst_scanline = dp + y*dstWidth + pad; - memset(dst_scanline, 0xff, sw); - } - } - // normal and solid styles are the same for analytic rect blurs, so don't - // need to handle solid specially. - - return true; -} - -bool SkBlurMask::BlurRRect(SkScalar sigma, SkMask *dst, - const SkRRect &src, SkBlurStyle style, - SkIPoint *margin, SkMask::CreateMode createMode) { - // Temporary for now -- always fail, should cause caller to fall back - // to old path. Plumbing just to land API and parallelize effort. - - return false; -} - -// The "simple" blur is a direct implementation of separable convolution with a discrete -// gaussian kernel. It's "ground truth" in a sense; too slow to be used, but very -// useful for correctness comparisons. - -bool SkBlurMask::BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src, - SkBlurStyle style, SkIPoint* margin) { - - if (src.fFormat != SkMask::kA8_Format) { - return false; - } - - float variance = sigma * sigma; - - int windowSize = SkScalarCeilToInt(sigma*6); - // round window size up to nearest odd number - windowSize |= 1; - - SkAutoTMalloc<float> gaussWindow(windowSize); - - int halfWindow = windowSize >> 1; - - gaussWindow[halfWindow] = 1; - - float windowSum = 1; - for (int x = 1 ; x <= halfWindow ; ++x) { - float gaussian = expf(-x*x / (2*variance)); - gaussWindow[halfWindow + x] = gaussWindow[halfWindow-x] = gaussian; - windowSum += 2*gaussian; - } - - // leave the filter un-normalized for now; we will divide by the normalization - // sum later; - - int pad = halfWindow; - if (margin) { - margin->set( pad, pad ); - } - - dst->fBounds = src.fBounds; - dst->fBounds.outset(pad, pad); - - dst->fRowBytes = dst->fBounds.width(); - dst->fFormat = SkMask::kA8_Format; - dst->fImage = nullptr; - - if (src.fImage) { - - size_t dstSize = dst->computeImageSize(); - if (0 == dstSize) { - return false; // too big to allocate, abort - } - - int srcWidth = src.fBounds.width(); - int srcHeight = src.fBounds.height(); - int dstWidth = dst->fBounds.width(); - - const uint8_t* srcPixels = src.fImage; - uint8_t* dstPixels = SkMask::AllocImage(dstSize); - SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dstPixels); - - // do the actual blur. First, make a padded copy of the source. - // use double pad so we never have to check if we're outside anything - - int padWidth = srcWidth + 4*pad; - int padHeight = srcHeight; - int padSize = padWidth * padHeight; - - SkAutoTMalloc<uint8_t> padPixels(padSize); - memset(padPixels, 0, padSize); - - for (int y = 0 ; y < srcHeight; ++y) { - uint8_t* padptr = padPixels + y * padWidth + 2*pad; - const uint8_t* srcptr = srcPixels + y * srcWidth; - memcpy(padptr, srcptr, srcWidth); - } - - // blur in X, transposing the result into a temporary floating point buffer. - // also double-pad the intermediate result so that the second blur doesn't - // have to do extra conditionals. - - int tmpWidth = padHeight + 4*pad; - int tmpHeight = padWidth - 2*pad; - int tmpSize = tmpWidth * tmpHeight; - - SkAutoTMalloc<float> tmpImage(tmpSize); - memset(tmpImage, 0, tmpSize*sizeof(tmpImage[0])); - - for (int y = 0 ; y < padHeight ; ++y) { - uint8_t *srcScanline = padPixels + y*padWidth; - for (int x = pad ; x < padWidth - pad ; ++x) { - float *outPixel = tmpImage + (x-pad)*tmpWidth + y + 2*pad; // transposed output - uint8_t *windowCenter = srcScanline + x; - for (int i = -pad ; i <= pad ; ++i) { - *outPixel += gaussWindow[pad+i]*windowCenter[i]; - } - *outPixel /= windowSum; - } - } - - // blur in Y; now filling in the actual desired destination. We have to do - // the transpose again; these transposes guarantee that we read memory in - // linear order. - - for (int y = 0 ; y < tmpHeight ; ++y) { - float *srcScanline = tmpImage + y*tmpWidth; - for (int x = pad ; x < tmpWidth - pad ; ++x) { - float *windowCenter = srcScanline + x; - float finalValue = 0; - for (int i = -pad ; i <= pad ; ++i) { - finalValue += gaussWindow[pad+i]*windowCenter[i]; - } - finalValue /= windowSum; - uint8_t *outPixel = dstPixels + (x-pad)*dstWidth + y; // transposed output - int integerPixel = int(finalValue + 0.5f); - *outPixel = SkClampMax( SkClampPos(integerPixel), 255 ); - } - } - - dst->fImage = dstPixels; - // if need be, alloc the "real" dst (same size as src) and copy/merge - // the blur into it (applying the src) - if (style == kInner_SkBlurStyle) { - // now we allocate the "real" dst, mirror the size of src - size_t srcSize = src.computeImageSize(); - if (0 == srcSize) { - return false; // too big to allocate, abort - } - dst->fImage = SkMask::AllocImage(srcSize); - merge_src_with_blur(dst->fImage, src.fRowBytes, - srcPixels, src.fRowBytes, - dstPixels + pad*dst->fRowBytes + pad, - dst->fRowBytes, srcWidth, srcHeight); - SkMask::FreeImage(dstPixels); - } else if (style != kNormal_SkBlurStyle) { - clamp_with_orig(dstPixels + pad*dst->fRowBytes + pad, - dst->fRowBytes, srcPixels, src.fRowBytes, srcWidth, srcHeight, style); - } - (void)autoCall.release(); - } - - if (style == kInner_SkBlurStyle) { - dst->fBounds = src.fBounds; // restore trimmed bounds - dst->fRowBytes = src.fRowBytes; - } - - return true; -} diff --git a/src/effects/SkBlurMask.h b/src/effects/SkBlurMask.h deleted file mode 100644 index 67009b0bb5..0000000000 --- a/src/effects/SkBlurMask.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkBlurMask_DEFINED -#define SkBlurMask_DEFINED - -#include "SkBlurTypes.h" -#include "SkShader.h" -#include "SkMask.h" -#include "SkRRect.h" - -class SkBlurMask { -public: - static bool SK_WARN_UNUSED_RESULT BlurRect(SkScalar sigma, SkMask *dst, const SkRect &src, - SkBlurStyle, SkIPoint *margin = nullptr, - SkMask::CreateMode createMode = - SkMask::kComputeBoundsAndRenderImage_CreateMode); - static bool SK_WARN_UNUSED_RESULT BlurRRect(SkScalar sigma, SkMask *dst, const SkRRect &src, - SkBlurStyle, SkIPoint *margin = nullptr, - SkMask::CreateMode createMode = - SkMask::kComputeBoundsAndRenderImage_CreateMode); - - // forceQuality will prevent BoxBlur from falling back to the low quality approach when sigma - // is very small -- this can be used predict the margin bump ahead of time without completely - // replicating the internal logic. This permits not only simpler caching of blurred results, - // but also being able to predict precisely at what pixels the blurred profile of e.g. a - // rectangle will lie. - // - // Calling details: - // * calculate margin - if src.fImage is null, then this call only calculates the border. - // * failure - if src.fImage is not null, failure is signal with dst->fImage being - // null. - - static bool SK_WARN_UNUSED_RESULT BoxBlur(SkMask* dst, const SkMask& src, - SkScalar sigma, SkBlurStyle style, SkBlurQuality, - SkIPoint* margin = nullptr, - bool forceQuality = false); - - // the "ground truth" blur does a gaussian convolution; it's slow - // but useful for comparison purposes. - static bool SK_WARN_UNUSED_RESULT BlurGroundTruth(SkScalar sigma, SkMask* dst, - const SkMask& src, - SkBlurStyle, SkIPoint* margin = nullptr); - - // If radius > 0, return the corresponding sigma, else return 0 - static SkScalar SK_API ConvertRadiusToSigma(SkScalar radius); - // If sigma > 0.5, return the corresponding radius, else return 0 - static SkScalar SK_API ConvertSigmaToRadius(SkScalar sigma); - - /* Helper functions for analytic rectangle blurs */ - - /** Look up the intensity of the (one dimnensional) blurred half-plane. - @param profile The precomputed 1D blur profile; initialized by ComputeBlurProfile below. - @param loc the location to look up; The lookup will clamp invalid inputs, but - meaningful data are available between 0 and blurred_width - @param blurred_width The width of the final, blurred rectangle - @param sharp_width The width of the original, unblurred rectangle. - */ - static uint8_t ProfileLookup(const uint8_t* profile, int loc, int blurredWidth, int sharpWidth); - - /** Populate the profile of a 1D blurred halfplane. - @param profile The 1D table to fill in - @param size Should be 6*sigma bytes - @param sigma The standard deviation of the gaussian blur kernel - */ - static void ComputeBlurProfile(uint8_t* profile, int size, SkScalar sigma); - - /** Compute an entire scanline of a blurred step function. This is a 1D helper that - will produce both the horizontal and vertical profiles of the blurry rectangle. - @param pixels Location to store the resulting pixel data; allocated and managed by caller - @param profile Precomputed blur profile computed by ComputeBlurProfile above. - @param width Size of the pixels array. - @param sigma Standard deviation of the gaussian blur kernel used to compute the profile; - this implicitly gives the size of the pixels array. - */ - - static void ComputeBlurredScanline(uint8_t* pixels, const uint8_t* profile, - unsigned int width, SkScalar sigma); - - - -}; - -#endif diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index 302d16e67b..c71cbc6491 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -39,10 +39,6 @@ #include "glsl/GrGLSLUniformHandler.h" #endif -SkScalar SkBlurMaskFilter::ConvertRadiusToSigma(SkScalar radius) { - return SkBlurMask::ConvertRadiusToSigma(radius); -} - class SkBlurMaskFilterImpl : public SkMaskFilterBase { public: SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle, const SkRect& occluder, uint32_t flags); |