Line data Source code
1 : /*
2 : * Copyright 2015 Google Inc.
3 : *
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 : #include "GrBlurUtils.h"
9 : #include "GrRenderTargetContext.h"
10 : #include "GrCaps.h"
11 : #include "GrContext.h"
12 : #include "GrContextPriv.h"
13 : #include "GrFixedClip.h"
14 : #include "GrRenderTargetContextPriv.h"
15 : #include "GrResourceProvider.h"
16 : #include "effects/GrSimpleTextureEffect.h"
17 : #include "GrStyle.h"
18 : #include "GrTexture.h"
19 : #include "GrTextureProxy.h"
20 : #include "SkDraw.h"
21 : #include "SkGr.h"
22 : #include "SkMaskFilter.h"
23 : #include "SkPaint.h"
24 : #include "SkTLazy.h"
25 :
26 0 : static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& rect) {
27 0 : return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBounds, rect);
28 : }
29 :
30 : // Draw a mask using the supplied paint. Since the coverage/geometry
31 : // is already burnt into the mask this boils down to a rect draw.
32 : // Return true if the mask was successfully drawn.
33 0 : static bool draw_mask(GrRenderTargetContext* renderTargetContext,
34 : const GrClip& clip,
35 : const SkMatrix& viewMatrix,
36 : const SkIRect& maskRect,
37 : GrPaint&& paint,
38 : sk_sp<GrTextureProxy> mask) {
39 : SkMatrix inverse;
40 0 : if (!viewMatrix.invert(&inverse)) {
41 0 : return false;
42 : }
43 :
44 0 : GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider();
45 :
46 0 : SkMatrix matrix = SkMatrix::MakeTrans(-SkIntToScalar(maskRect.fLeft),
47 0 : -SkIntToScalar(maskRect.fTop));
48 0 : matrix.preConcat(viewMatrix);
49 0 : paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(resourceProvider,
50 0 : std::move(mask),
51 0 : nullptr, matrix));
52 :
53 0 : renderTargetContext->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(),
54 0 : SkRect::Make(maskRect), inverse);
55 0 : return true;
56 : }
57 :
58 0 : static bool sw_draw_with_mask_filter(GrContext* context,
59 : GrRenderTargetContext* renderTargetContext,
60 : const GrClip& clipData,
61 : const SkMatrix& viewMatrix,
62 : const SkPath& devPath,
63 : const SkMaskFilter* filter,
64 : const SkIRect& clipBounds,
65 : GrPaint&& paint,
66 : SkStrokeRec::InitStyle fillOrHairline) {
67 0 : SkMask srcM, dstM;
68 0 : if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM,
69 : SkMask::kComputeBoundsAndRenderImage_CreateMode, fillOrHairline)) {
70 0 : return false;
71 : }
72 0 : SkAutoMaskFreeImage autoSrc(srcM.fImage);
73 :
74 0 : if (!filter->filterMask(&dstM, srcM, viewMatrix, nullptr)) {
75 0 : return false;
76 : }
77 : // this will free-up dstM when we're done (allocated in filterMask())
78 0 : SkAutoMaskFreeImage autoDst(dstM.fImage);
79 :
80 0 : if (clip_bounds_quick_reject(clipBounds, dstM.fBounds)) {
81 0 : return false;
82 : }
83 :
84 : // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
85 : // the current clip (and identity matrix) and GrPaint settings
86 0 : GrSurfaceDesc desc;
87 0 : desc.fOrigin = kTopLeft_GrSurfaceOrigin;
88 0 : desc.fWidth = dstM.fBounds.width();
89 0 : desc.fHeight = dstM.fBounds.height();
90 0 : desc.fConfig = kAlpha_8_GrPixelConfig;
91 :
92 0 : sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeDeferredSurfaceContext(
93 : desc,
94 : SkBackingFit::kApprox,
95 0 : SkBudgeted::kYes);
96 0 : if (!sContext) {
97 0 : return false;
98 : }
99 :
100 0 : SkImageInfo ii = SkImageInfo::MakeA8(desc.fWidth, desc.fHeight);
101 0 : if (!sContext->writePixels(ii, dstM.fImage, dstM.fRowBytes, 0, 0)) {
102 0 : return false;
103 : }
104 :
105 : return draw_mask(renderTargetContext, clipData, viewMatrix,
106 0 : dstM.fBounds, std::move(paint), sContext->asTextureProxyRef());
107 : }
108 :
109 : // Create a mask of 'devPath' and place the result in 'mask'.
110 0 : static sk_sp<GrTextureProxy> create_mask_GPU(GrContext* context,
111 : const SkIRect& maskRect,
112 : const SkPath& devPath,
113 : SkStrokeRec::InitStyle fillOrHairline,
114 : GrAA aa,
115 : int sampleCnt) {
116 0 : if (GrAA::kNo == aa) {
117 : // Don't need MSAA if mask isn't AA
118 0 : sampleCnt = 0;
119 : }
120 :
121 : sk_sp<GrRenderTargetContext> rtContext(context->makeDeferredRenderTargetContextWithFallback(
122 : SkBackingFit::kApprox, maskRect.width(), maskRect.height(), kAlpha_8_GrPixelConfig, nullptr,
123 0 : sampleCnt));
124 0 : if (!rtContext) {
125 0 : return nullptr;
126 : }
127 :
128 0 : rtContext->priv().absClear(nullptr, 0x0);
129 :
130 0 : GrPaint maskPaint;
131 0 : maskPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
132 :
133 : // setup new clip
134 0 : const SkIRect clipRect = SkIRect::MakeWH(maskRect.width(), maskRect.height());
135 0 : GrFixedClip clip(clipRect);
136 :
137 : // Draw the mask into maskTexture with the path's integerized top-left at
138 : // the origin using maskPaint.
139 : SkMatrix translate;
140 0 : translate.setTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop));
141 0 : rtContext->drawPath(clip, std::move(maskPaint), aa, translate, devPath,
142 0 : GrStyle(fillOrHairline));
143 0 : return rtContext->asTextureProxyRef();
144 : }
145 :
146 0 : static void draw_path_with_mask_filter(GrContext* context,
147 : GrRenderTargetContext* renderTargetContext,
148 : const GrClip& clip,
149 : GrPaint&& paint,
150 : GrAA aa,
151 : const SkMatrix& viewMatrix,
152 : const SkMaskFilter* maskFilter,
153 : const GrStyle& style,
154 : const SkPath* path,
155 : bool pathIsMutable) {
156 0 : SkASSERT(maskFilter);
157 :
158 : SkIRect clipBounds;
159 0 : clip.getConservativeBounds(renderTargetContext->width(),
160 : renderTargetContext->height(),
161 0 : &clipBounds);
162 0 : SkTLazy<SkPath> tmpPath;
163 : SkStrokeRec::InitStyle fillOrHairline;
164 :
165 : // We just fully apply the style here.
166 0 : if (style.applies()) {
167 0 : SkScalar scale = GrStyle::MatrixToScaleFactor(viewMatrix);
168 0 : if (0 == scale || !style.applyToPath(tmpPath.init(), &fillOrHairline, *path, scale)) {
169 0 : return;
170 : }
171 0 : pathIsMutable = true;
172 0 : path = tmpPath.get();
173 0 : } else if (style.isSimpleHairline()) {
174 0 : fillOrHairline = SkStrokeRec::kHairline_InitStyle;
175 : } else {
176 0 : SkASSERT(style.isSimpleFill());
177 0 : fillOrHairline = SkStrokeRec::kFill_InitStyle;
178 : }
179 :
180 : // transform the path into device space
181 0 : if (!viewMatrix.isIdentity()) {
182 : SkPath* result;
183 0 : if (pathIsMutable) {
184 0 : result = const_cast<SkPath*>(path);
185 : } else {
186 0 : if (!tmpPath.isValid()) {
187 0 : tmpPath.init();
188 : }
189 0 : result = tmpPath.get();
190 : }
191 0 : path->transform(viewMatrix, result);
192 0 : path = result;
193 0 : result->setIsVolatile(true);
194 0 : pathIsMutable = true;
195 : }
196 :
197 : SkRect maskRect;
198 0 : if (maskFilter->canFilterMaskGPU(SkRRect::MakeRect(path->getBounds()),
199 : clipBounds,
200 : viewMatrix,
201 0 : &maskRect)) {
202 : // This mask will ultimately be drawn as a non-AA rect (see draw_mask).
203 : // Non-AA rects have a bad habit of snapping arbitrarily. Integerize here
204 : // so the mask draws in a reproducible manner.
205 : SkIRect finalIRect;
206 0 : maskRect.roundOut(&finalIRect);
207 0 : if (clip_bounds_quick_reject(clipBounds, finalIRect)) {
208 : // clipped out
209 0 : return;
210 : }
211 :
212 0 : if (maskFilter->directFilterMaskGPU(context,
213 : renderTargetContext,
214 0 : std::move(paint),
215 : clip,
216 : viewMatrix,
217 0 : SkStrokeRec(fillOrHairline),
218 0 : *path)) {
219 : // the mask filter was able to draw itself directly, so there's nothing
220 : // left to do.
221 0 : return;
222 : }
223 :
224 : sk_sp<GrTextureProxy> maskProxy(create_mask_GPU(context,
225 : finalIRect,
226 : *path,
227 : fillOrHairline,
228 : aa,
229 0 : renderTargetContext->numColorSamples()));
230 0 : if (maskProxy) {
231 : sk_sp<GrTextureProxy> filtered = maskFilter->filterMaskGPU(context,
232 0 : std::move(maskProxy),
233 : viewMatrix,
234 0 : finalIRect);
235 0 : if (filtered) {
236 0 : if (draw_mask(renderTargetContext, clip, viewMatrix,
237 0 : finalIRect, std::move(paint), std::move(filtered))) {
238 : // This path is completely drawn
239 0 : return;
240 : }
241 : }
242 : }
243 : }
244 :
245 : sw_draw_with_mask_filter(context, renderTargetContext, clip, viewMatrix, *path, maskFilter,
246 0 : clipBounds, std::move(paint), fillOrHairline);
247 : }
248 :
249 0 : void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
250 : GrRenderTargetContext* renderTargetContext,
251 : const GrClip& clip,
252 : const SkPath& path,
253 : GrPaint&& paint,
254 : GrAA aa,
255 : const SkMatrix& viewMatrix,
256 : const SkMaskFilter* mf,
257 : const GrStyle& style,
258 : bool pathIsMutable) {
259 0 : draw_path_with_mask_filter(context, renderTargetContext, clip, std::move(paint), aa, viewMatrix,
260 0 : mf, style, &path, pathIsMutable);
261 0 : }
262 :
263 0 : void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
264 : GrRenderTargetContext* renderTargetContext,
265 : const GrClip& clip,
266 : const SkPath& origPath,
267 : const SkPaint& paint,
268 : const SkMatrix& origViewMatrix,
269 : const SkMatrix* prePathMatrix,
270 : const SkIRect& clipBounds,
271 : bool pathIsMutable) {
272 0 : SkASSERT(!pathIsMutable || origPath.isVolatile());
273 :
274 0 : GrStyle style(paint);
275 : // If we have a prematrix, apply it to the path, optimizing for the case
276 : // where the original path can in fact be modified in place (even though
277 : // its parameter type is const).
278 :
279 0 : const SkPath* path = &origPath;
280 0 : SkTLazy<SkPath> tmpPath;
281 :
282 0 : SkMatrix viewMatrix = origViewMatrix;
283 :
284 0 : if (prePathMatrix) {
285 : // Styling, blurs, and shading are supposed to be applied *after* the prePathMatrix.
286 0 : if (!paint.getMaskFilter() && !paint.getShader() && !style.applies()) {
287 0 : viewMatrix.preConcat(*prePathMatrix);
288 : } else {
289 0 : SkPath* result = pathIsMutable ? const_cast<SkPath*>(path) : tmpPath.init();
290 0 : pathIsMutable = true;
291 0 : path->transform(*prePathMatrix, result);
292 0 : path = result;
293 0 : result->setIsVolatile(true);
294 : }
295 : }
296 : // at this point we're done with prePathMatrix
297 0 : SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
298 :
299 0 : GrPaint grPaint;
300 0 : if (!SkPaintToGrPaint(context, renderTargetContext, paint, viewMatrix, &grPaint)) {
301 0 : return;
302 : }
303 0 : GrAA aa = GrBoolToAA(paint.isAntiAlias());
304 0 : SkMaskFilter* mf = paint.getMaskFilter();
305 0 : if (mf && !mf->asFragmentProcessor(nullptr, nullptr, viewMatrix)) {
306 : // The MaskFilter wasn't already handled in SkPaintToGrPaint
307 0 : draw_path_with_mask_filter(context, renderTargetContext, clip, std::move(grPaint), aa,
308 0 : viewMatrix, mf, style, path, pathIsMutable);
309 : } else {
310 0 : renderTargetContext->drawPath(clip, std::move(grPaint), aa, viewMatrix, *path, style);
311 : }
312 : }
|