1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "src/core/SkSDFFilter.h"
17 #include "src/gpu/SkGr.h"
18 #include "src/gpu/effects/GrBlendFragmentProcessor.h"
19
20 #ifdef SK_ENABLE_SDF_BLUR_SWITCH
21 #include <parameters.h>
22 #endif
23
24 namespace SDFBlur {
25
GetSDFBlurEnabled()26 static bool GetSDFBlurEnabled()
27 {
28 #ifdef SK_ENABLE_SDF_BLUR_SWITCH
29 constexpr int enableFlag = 1;
30 static bool enabled = std::atoi(
31 (OHOS::system::GetParameter("persist.sys.graphic.SDFBlurEnabled", "1")).c_str()) == enableFlag;
32 return enabled;
33 #else
34 return false;
35 #endif
36 }
37
GetSDFBlurDebugTraceEnabled()38 bool GetSDFBlurDebugTraceEnabled()
39 {
40 #ifdef SK_ENABLE_SDF_BLUR_SWITCH
41 constexpr int enableFlag = 1;
42 static bool enabled = std::atoi(
43 (OHOS::system::GetParameter("persist.sys.graphic.SDFBlurDebugTraceEnabled", "0")).c_str()) == enableFlag;
44 return enabled;
45 #else
46 return false;
47 #endif
48 }
49
50 // Only the equal Radii RRect use SDFblur.
isSDFBlur(const GrStyledShape & shape)51 bool isSDFBlur(const GrStyledShape& shape)
52 {
53 SkRRect srcRRect;
54 bool inverted;
55 if (!GetSDFBlurEnabled() || !shape.asRRect(&srcRRect, nullptr, nullptr, &inverted) || inverted ||
56 (!(srcRRect.getType() == SkRRect::kSimple_Type) && !(srcRRect.getType() == SkRRect::kNinePatch_Type))) {
57 return false;
58 }
59 return true;
60 }
61
GetSDFBlurScaleFactor(const SkRRect srcRRect,const SkMatrix & viewMatrix,SkScalar & sx,SkScalar & sy)62 void GetSDFBlurScaleFactor(const SkRRect srcRRect, const SkMatrix& viewMatrix, SkScalar& sx, SkScalar& sy)
63 {
64 if (viewMatrix.getScaleX() >= 1.f || viewMatrix.getScaleY() >= 1.f) {
65 return;
66 }
67 constexpr float minScaleFactor = 1.f;
68 constexpr float maxScaleFactor = 2.f;
69 constexpr float sizeThreshold = 500.f;
70 int srcRRectW = srcRRect.rect().width();
71 int srcRRectH = srcRRect.rect().height();
72 // When the input size is greater than the threshold, it needs to be scaled.
73 // scale factor will be clamped in [1.0, 2.0].
74 int scaleX = std::max(minScaleFactor, std::min(std::ceil(srcRRectW / sizeThreshold), maxScaleFactor));
75 int scaleY = std::max(minScaleFactor, std::min(std::ceil(srcRRectH / sizeThreshold), maxScaleFactor));
76 sx = SK_Scalar1 / scaleX;
77 sy = SK_Scalar1 / scaleY;
78 }
79
drawMaskSDFBlur(GrRecordingContext * rContext,skgpu::v1::SurfaceDrawContext * sdc,const GrClip * clip,const SkMatrix & viewMatrix,const SkIRect & maskBounds,GrPaint && paint,GrSurfaceProxyView mask,const SkMaskFilterBase * maskFilter,const SkScalar sx,const SkScalar sy)80 bool drawMaskSDFBlur(GrRecordingContext* rContext, skgpu::v1::SurfaceDrawContext* sdc, const GrClip* clip,
81 const SkMatrix& viewMatrix, const SkIRect& maskBounds, GrPaint&& paint, GrSurfaceProxyView mask,
82 const SkMaskFilterBase* maskFilter, const SkScalar sx, const SkScalar sy)
83 {
84 float noxFormedSigma3 = maskFilter->getNoxFormedSigma3();
85 mask.concatSwizzle(GrSwizzle("aaaa"));
86
87 SkMatrix matrixTrans =
88 SkMatrix::Translate(-SkIntToScalar(noxFormedSigma3), -SkIntToScalar(noxFormedSigma3));
89 SkMatrix matrixInverseScale = SkMatrix::Scale(1 / sx, 1 / sy);
90 SkMatrix matrix;
91 matrix.preConcat(viewMatrix);
92 matrix.preConcat(matrixTrans);
93 matrix.preConcat(matrixInverseScale);
94 // add dither effect to reduce color discontinuity
95 constexpr float ditherRange = 1.f / 255.f;
96 auto inputFp = GrTextureEffect::Make(std::move(mask), kUnknown_SkAlphaType);
97 SkPMColor4f origColor = paint.getColor4f();
98
99 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, R"(
100 uniform shader fp;
101 uniform half4 colorPaint;
102 half4 main(float2 pos) {
103
104 half4 colorMask = fp.eval(pos);
105 return colorMask * colorPaint;
106 }
107 )");
108 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
109 auto inputFP = GrSkSLFP::Make(effect, "OverrideInput", nullptr,
110 origColor.isOpaque() ? GrSkSLFP::OptFlags::kPreservesOpaqueInput : GrSkSLFP::OptFlags::kNone,
111 "fp", std::move(inputFp), "colorPaint", origColor);
112
113 auto paintFP = GrBlendFragmentProcessor::Make(std::move(inputFP), nullptr, SkBlendMode::kSrc);
114
115 #ifndef SK_IGNORE_GPU_DITHER
116 paintFP = make_dither_effect(rContext, std::move(paintFP), ditherRange, rContext->priv().caps());
117 #endif
118 paint.setColorFragmentProcessor(std::move(paintFP));
119 sdc->drawRect(clip, std::move(paint), GrAA::kYes, matrix,
120 SkRect::MakeXYWH(0, 0, maskBounds.width(), maskBounds.height()));
121 return true;
122 }
123
sdf_2d(GrRecordingContext * rContext,GrSurfaceProxyView srcView,GrColorType srcColorType,const SkIRect & srcBounds,const SkIRect & dstBounds,float noxFormedSigma,SkTileMode mode,sk_sp<SkColorSpace> finalCS,SkBackingFit dstFit,const SkMatrix & viewMatrix,const SkRRect & srcRRect)124 static std::unique_ptr<skgpu::v1::SurfaceDrawContext> sdf_2d(GrRecordingContext* rContext,
125 GrSurfaceProxyView srcView, GrColorType srcColorType, const SkIRect& srcBounds, const SkIRect& dstBounds,
126 float noxFormedSigma, SkTileMode mode, sk_sp<SkColorSpace> finalCS, SkBackingFit dstFit,
127 const SkMatrix& viewMatrix, const SkRRect& srcRRect)
128 {
129 auto sdc = skgpu::v1::SurfaceDrawContext::Make(
130 rContext, srcColorType, std::move(finalCS), dstFit, dstBounds.size(), SkSurfaceProps(),
131 1, GrMipmapped::kNo, srcView.proxy()->isProtected(), srcView.origin());
132 if (!sdc) {
133 return nullptr;
134 }
135
136 GrPaint paint;
137 auto sdfFp = GrSDFBlurEffect::Make(rContext, noxFormedSigma, srcRRect);
138 if (!sdfFp) {
139 return nullptr;
140 }
141
142 paint.setColorFragmentProcessor(std::move(sdfFp));
143 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
144
145 SkScalar sx = viewMatrix.getScaleX();
146 SkScalar sy = viewMatrix.getScaleY();
147 sdc->drawPaint(nullptr, std::move(paint), SkMatrix::I().Scale(sx, sy));
148
149 return sdc;
150 }
151
SDFBlur(GrRecordingContext * rContext,GrSurfaceProxyView srcView,GrColorType srcColorType,SkAlphaType srcAlphaType,sk_sp<SkColorSpace> colorSpace,SkIRect dstBounds,SkIRect srcBounds,float noxFormedSigma,SkTileMode mode,const SkMatrix & viewMatrix,const SkRRect & srcRRect,SkBackingFit fit)152 std::unique_ptr<skgpu::v1::SurfaceDrawContext> SDFBlur(GrRecordingContext* rContext,
153 GrSurfaceProxyView srcView, GrColorType srcColorType, SkAlphaType srcAlphaType,
154 sk_sp<SkColorSpace> colorSpace, SkIRect dstBounds, SkIRect srcBounds, float noxFormedSigma,
155 SkTileMode mode, const SkMatrix& viewMatrix, const SkRRect& srcRRect, SkBackingFit fit)
156 {
157 SkASSERT(rContext);
158 TRACE_EVENT0("skia.gpu", "SDFBlur");
159
160 if (!srcView.asTextureProxy()) {
161 return nullptr;
162 }
163
164 int maxRenderTargetSize = rContext->priv().caps()->maxRenderTargetSize();
165 if (dstBounds.width() > maxRenderTargetSize || dstBounds.height() > maxRenderTargetSize) {
166 return nullptr;
167 }
168
169 return sdf_2d(rContext, std::move(srcView), srcColorType, srcBounds, dstBounds, noxFormedSigma, mode,
170 std::move(colorSpace), fit, viewMatrix, srcRRect);
171 }
172 } // SDFBlur
173