Line data Source code
1 : /*
2 : * Copyright 2011 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 "SkGpuDevice.h"
9 :
10 : #include "GrBitmapTextureMaker.h"
11 : #include "GrBlurUtils.h"
12 : #include "GrContext.h"
13 : #include "GrGpu.h"
14 : #include "GrImageTextureMaker.h"
15 : #include "GrRenderTargetContextPriv.h"
16 : #include "GrStyle.h"
17 : #include "GrSurfaceProxyPriv.h"
18 : #include "GrTextureAdjuster.h"
19 : #include "GrTextureProxy.h"
20 : #include "GrTracing.h"
21 : #include "SkCanvasPriv.h"
22 : #include "SkDraw.h"
23 : #include "SkGlyphCache.h"
24 : #include "SkGr.h"
25 : #include "SkImageCacherator.h"
26 : #include "SkImageFilter.h"
27 : #include "SkImageFilterCache.h"
28 : #include "SkImageInfoPriv.h"
29 : #include "SkImage_Base.h"
30 : #include "SkLatticeIter.h"
31 : #include "SkMaskFilter.h"
32 : #include "SkPathEffect.h"
33 : #include "SkPicture.h"
34 : #include "SkPictureData.h"
35 : #include "SkRRect.h"
36 : #include "SkRasterClip.h"
37 : #include "SkReadPixelsRec.h"
38 : #include "SkRecord.h"
39 : #include "SkSpecialImage.h"
40 : #include "SkStroke.h"
41 : #include "SkSurface.h"
42 : #include "SkSurface_Gpu.h"
43 : #include "SkTLazy.h"
44 : #include "SkUtils.h"
45 : #include "SkVertState.h"
46 : #include "SkVertices.h"
47 : #include "SkWritePixelsRec.h"
48 : #include "effects/GrBicubicEffect.h"
49 : #include "effects/GrSimpleTextureEffect.h"
50 : #include "effects/GrTextureDomain.h"
51 : #include "text/GrTextUtils.h"
52 :
53 : #if SK_SUPPORT_GPU
54 :
55 : #define ASSERT_SINGLE_OWNER \
56 : SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fContext->debugSingleOwner());)
57 :
58 : #if 0
59 : extern bool (*gShouldDrawProc)();
60 : #define CHECK_SHOULD_DRAW() \
61 : do { \
62 : if (gShouldDrawProc && !gShouldDrawProc()) return; \
63 : } while (0)
64 : #else
65 : #define CHECK_SHOULD_DRAW()
66 : #endif
67 :
68 : ///////////////////////////////////////////////////////////////////////////////
69 :
70 : /** Checks that the alpha type is legal and gets constructor flags. Returns false if device creation
71 : should fail. */
72 0 : bool SkGpuDevice::CheckAlphaTypeAndGetFlags(
73 : const SkImageInfo* info, SkGpuDevice::InitContents init, unsigned* flags) {
74 0 : *flags = 0;
75 0 : if (info) {
76 0 : switch (info->alphaType()) {
77 : case kPremul_SkAlphaType:
78 0 : break;
79 : case kOpaque_SkAlphaType:
80 0 : *flags |= SkGpuDevice::kIsOpaque_Flag;
81 0 : break;
82 : default: // If it is unpremul or unknown don't try to render
83 0 : return false;
84 : }
85 : }
86 0 : if (kClear_InitContents == init) {
87 0 : *flags |= kNeedClear_Flag;
88 : }
89 0 : return true;
90 : }
91 :
92 0 : sk_sp<SkGpuDevice> SkGpuDevice::Make(GrContext* context,
93 : sk_sp<GrRenderTargetContext> renderTargetContext,
94 : int width, int height,
95 : InitContents init) {
96 0 : if (!renderTargetContext || renderTargetContext->wasAbandoned()) {
97 0 : return nullptr;
98 : }
99 : unsigned flags;
100 0 : if (!CheckAlphaTypeAndGetFlags(nullptr, init, &flags)) {
101 0 : return nullptr;
102 : }
103 0 : return sk_sp<SkGpuDevice>(new SkGpuDevice(context, std::move(renderTargetContext),
104 0 : width, height, flags));
105 : }
106 :
107 0 : sk_sp<SkGpuDevice> SkGpuDevice::Make(GrContext* context, SkBudgeted budgeted,
108 : const SkImageInfo& info, int sampleCount,
109 : GrSurfaceOrigin origin,
110 : const SkSurfaceProps* props, InitContents init) {
111 : unsigned flags;
112 0 : if (!CheckAlphaTypeAndGetFlags(&info, init, &flags)) {
113 0 : return nullptr;
114 : }
115 :
116 : sk_sp<GrRenderTargetContext> renderTargetContext(MakeRenderTargetContext(context, budgeted,
117 : info, sampleCount,
118 0 : origin, props));
119 0 : if (!renderTargetContext) {
120 0 : return nullptr;
121 : }
122 :
123 0 : return sk_sp<SkGpuDevice>(new SkGpuDevice(context, std::move(renderTargetContext),
124 0 : info.width(), info.height(), flags));
125 : }
126 :
127 0 : static SkImageInfo make_info(GrRenderTargetContext* context, int w, int h, bool opaque) {
128 : SkColorType colorType;
129 0 : if (!GrPixelConfigToColorType(context->config(), &colorType)) {
130 0 : colorType = kUnknown_SkColorType;
131 : }
132 : return SkImageInfo::Make(w, h, colorType,
133 : opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
134 0 : context->refColorSpace());
135 : }
136 :
137 0 : SkGpuDevice::SkGpuDevice(GrContext* context, sk_sp<GrRenderTargetContext> renderTargetContext,
138 0 : int width, int height, unsigned flags)
139 0 : : INHERITED(make_info(renderTargetContext.get(), width, height,
140 0 : SkToBool(flags & kIsOpaque_Flag)), renderTargetContext->surfaceProps())
141 : , fContext(SkRef(context))
142 0 : , fRenderTargetContext(std::move(renderTargetContext))
143 : {
144 0 : fSize.set(width, height);
145 0 : fOpaque = SkToBool(flags & kIsOpaque_Flag);
146 :
147 0 : if (flags & kNeedClear_Flag) {
148 0 : this->clearAll();
149 : }
150 0 : }
151 :
152 0 : sk_sp<GrRenderTargetContext> SkGpuDevice::MakeRenderTargetContext(
153 : GrContext* context,
154 : SkBudgeted budgeted,
155 : const SkImageInfo& origInfo,
156 : int sampleCount,
157 : GrSurfaceOrigin origin,
158 : const SkSurfaceProps* surfaceProps) {
159 0 : if (kUnknown_SkColorType == origInfo.colorType() ||
160 0 : origInfo.width() < 0 || origInfo.height() < 0) {
161 0 : return nullptr;
162 : }
163 :
164 0 : if (!context) {
165 0 : return nullptr;
166 : }
167 :
168 0 : GrPixelConfig config = SkImageInfo2GrPixelConfig(origInfo, *context->caps());
169 : // This method is used to create SkGpuDevice's for SkSurface_Gpus. In this case
170 : // they need to be exact.
171 : return context->makeRenderTargetContext(SkBackingFit::kExact,
172 : origInfo.width(), origInfo.height(),
173 0 : config, origInfo.refColorSpace(), sampleCount,
174 0 : origin, surfaceProps, budgeted);
175 : }
176 :
177 0 : sk_sp<SkSpecialImage> SkGpuDevice::filterTexture(SkSpecialImage* srcImg,
178 : int left, int top,
179 : SkIPoint* offset,
180 : const SkImageFilter* filter) {
181 0 : SkASSERT(srcImg->isTextureBacked());
182 0 : SkASSERT(filter);
183 :
184 0 : SkMatrix matrix = this->ctm();
185 0 : matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
186 0 : const SkIRect clipBounds = this->devClipBounds().makeOffset(-left, -top);
187 0 : sk_sp<SkImageFilterCache> cache(this->getImageFilterCache());
188 0 : SkImageFilter::OutputProperties outputProperties(fRenderTargetContext->getColorSpace());
189 0 : SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
190 :
191 0 : return filter->filterImage(srcImg, ctx, offset);
192 : }
193 :
194 : ///////////////////////////////////////////////////////////////////////////////
195 :
196 0 : bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
197 : int x, int y) {
198 0 : ASSERT_SINGLE_OWNER
199 :
200 0 : if (!SkImageInfoValidConversion(dstInfo, this->imageInfo())) {
201 0 : return false;
202 : }
203 :
204 0 : SkReadPixelsRec rec(dstInfo, dstPixels, dstRowBytes, x, y);
205 0 : if (!rec.trim(this->width(), this->height())) {
206 0 : return false;
207 : }
208 :
209 0 : return fRenderTargetContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
210 : }
211 :
212 0 : bool SkGpuDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
213 : size_t srcRowBytes, int x, int y) {
214 0 : ASSERT_SINGLE_OWNER
215 :
216 0 : if (!SkImageInfoValidConversion(this->imageInfo(), srcInfo)) {
217 0 : return false;
218 : }
219 :
220 0 : SkWritePixelsRec rec(srcInfo, srcPixels, srcRowBytes, x, y);
221 0 : if (!rec.trim(this->width(), this->height())) {
222 0 : return false;
223 : }
224 :
225 0 : return fRenderTargetContext->writePixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
226 : }
227 :
228 0 : bool SkGpuDevice::onAccessPixels(SkPixmap* pmap) {
229 0 : ASSERT_SINGLE_OWNER
230 0 : return false;
231 : }
232 :
233 0 : GrRenderTargetContext* SkGpuDevice::accessRenderTargetContext() {
234 0 : ASSERT_SINGLE_OWNER
235 0 : return fRenderTargetContext.get();
236 : }
237 :
238 0 : void SkGpuDevice::clearAll() {
239 0 : ASSERT_SINGLE_OWNER
240 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "clearAll", fContext.get());
241 :
242 0 : SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
243 0 : fRenderTargetContext->clear(&rect, 0x0, true);
244 0 : }
245 :
246 0 : void SkGpuDevice::replaceRenderTargetContext(bool shouldRetainContent) {
247 0 : ASSERT_SINGLE_OWNER
248 :
249 0 : SkBudgeted budgeted = fRenderTargetContext->priv().isBudgeted();
250 :
251 : // This entry point is used by SkSurface_Gpu::onCopyOnWrite so it must create a
252 : // kExact-backed render target context.
253 : sk_sp<GrRenderTargetContext> newRTC(MakeRenderTargetContext(
254 0 : this->context(),
255 : budgeted,
256 : this->imageInfo(),
257 : fRenderTargetContext->numColorSamples(),
258 : fRenderTargetContext->origin(),
259 0 : &this->surfaceProps()));
260 0 : if (!newRTC) {
261 0 : return;
262 : }
263 0 : SkASSERT(newRTC->asSurfaceProxy()->priv().isExact());
264 :
265 0 : if (shouldRetainContent) {
266 0 : if (fRenderTargetContext->wasAbandoned()) {
267 0 : return;
268 : }
269 0 : newRTC->copy(fRenderTargetContext->asSurfaceProxy());
270 : }
271 :
272 0 : fRenderTargetContext = newRTC;
273 : }
274 :
275 : ///////////////////////////////////////////////////////////////////////////////
276 :
277 0 : void SkGpuDevice::drawPaint(const SkPaint& paint) {
278 0 : ASSERT_SINGLE_OWNER
279 : CHECK_SHOULD_DRAW();
280 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPaint", fContext.get());
281 :
282 0 : GrPaint grPaint;
283 0 : if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
284 : &grPaint)) {
285 0 : return;
286 : }
287 :
288 0 : fRenderTargetContext->drawPaint(this->clip(), std::move(grPaint), this->ctm());
289 : }
290 :
291 : // must be in SkCanvas::PointMode order
292 : static const GrPrimitiveType gPointMode2PrimitiveType[] = {
293 : kPoints_GrPrimitiveType,
294 : kLines_GrPrimitiveType,
295 : kLineStrip_GrPrimitiveType
296 : };
297 :
298 0 : static inline bool is_int(float x) { return x == (float) sk_float_round2int(x); }
299 :
300 : // suppress antialiasing on axis-aligned integer-coordinate lines
301 0 : static bool needs_antialiasing(SkCanvas::PointMode mode, size_t count, const SkPoint pts[],
302 : const SkMatrix& matrix) {
303 0 : if (mode == SkCanvas::PointMode::kPoints_PointMode) {
304 0 : return false;
305 : }
306 0 : if (count == 2) {
307 : // We do not antialias horizontal or vertical lines along pixel centers, even when the ends
308 : // of the line do not fully cover the first and last pixel of the line, which is slightly
309 : // wrong.
310 0 : if (!matrix.isScaleTranslate()) {
311 0 : return true;
312 : }
313 0 : if (pts[0].fX == pts[1].fX) {
314 0 : SkScalar x = matrix.getScaleX() * pts[0].fX + matrix.getTranslateX();
315 0 : return !is_int(x + 0.5f);
316 : }
317 0 : if (pts[0].fY == pts[1].fY) {
318 0 : SkScalar y = matrix.getScaleY() * pts[0].fY + matrix.getTranslateY();
319 0 : return !is_int(y + 0.5f);
320 : }
321 : }
322 0 : return true;
323 : }
324 :
325 0 : void SkGpuDevice::drawPoints(SkCanvas::PointMode mode,
326 : size_t count, const SkPoint pts[], const SkPaint& paint) {
327 0 : ASSERT_SINGLE_OWNER
328 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPoints", fContext.get());
329 : CHECK_SHOULD_DRAW();
330 :
331 0 : SkScalar width = paint.getStrokeWidth();
332 0 : if (width < 0) {
333 0 : return;
334 : }
335 :
336 0 : if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
337 0 : GrStyle style(paint, SkPaint::kStroke_Style);
338 0 : GrPaint grPaint;
339 0 : if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
340 : &grPaint)) {
341 0 : return;
342 : }
343 0 : SkPath path;
344 0 : path.setIsVolatile(true);
345 0 : path.moveTo(pts[0]);
346 0 : path.lineTo(pts[1]);
347 0 : fRenderTargetContext->drawPath(this->clip(), std::move(grPaint),
348 0 : GrBoolToAA(paint.isAntiAlias()), this->ctm(), path, style);
349 0 : return;
350 : }
351 :
352 : SkScalar scales[2];
353 0 : bool isHairline = (0 == width) || (1 == width && this->ctm().getMinMaxScales(scales) &&
354 0 : SkScalarNearlyEqual(scales[0], 1.f) &&
355 0 : SkScalarNearlyEqual(scales[1], 1.f));
356 : // we only handle non-antialiased hairlines and paints without path effects or mask filters,
357 : // else we let the SkDraw call our drawPath()
358 0 : if (!isHairline || paint.getPathEffect() || paint.getMaskFilter() ||
359 0 : (paint.isAntiAlias() && needs_antialiasing(mode, count, pts, this->ctm())))
360 : {
361 0 : SkRasterClip rc(this->devClipBounds());
362 0 : SkDraw draw;
363 0 : draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0);
364 0 : draw.fMatrix = &this->ctm();
365 0 : draw.fRC = &rc;
366 0 : draw.drawPoints(mode, count, pts, paint, this);
367 0 : return;
368 : }
369 :
370 0 : GrPrimitiveType primitiveType = gPointMode2PrimitiveType[mode];
371 :
372 0 : const SkMatrix* viewMatrix = &this->ctm();
373 : #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
374 : // This offsetting in device space matches the expectations of the Android framework for non-AA
375 : // points and lines.
376 : SkMatrix tempMatrix;
377 : if (GrIsPrimTypeLines(primitiveType) || kPoints_GrPrimitiveType == primitiveType) {
378 : tempMatrix = *viewMatrix;
379 : static const SkScalar kOffset = 0.063f; // Just greater than 1/16.
380 : tempMatrix.postTranslate(kOffset, kOffset);
381 : viewMatrix = &tempMatrix;
382 : }
383 : #endif
384 :
385 0 : GrPaint grPaint;
386 0 : if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, *viewMatrix,
387 : &grPaint)) {
388 0 : return;
389 : }
390 :
391 0 : fRenderTargetContext->drawVertices(this->clip(),
392 0 : std::move(grPaint),
393 : *viewMatrix,
394 : primitiveType,
395 : SkToS32(count),
396 : (SkPoint*)pts,
397 : nullptr,
398 : nullptr,
399 : nullptr,
400 0 : 0);
401 : }
402 :
403 : ///////////////////////////////////////////////////////////////////////////////
404 :
405 0 : void SkGpuDevice::drawRect(const SkRect& rect, const SkPaint& paint) {
406 0 : ASSERT_SINGLE_OWNER
407 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRect", fContext.get());
408 : CHECK_SHOULD_DRAW();
409 :
410 :
411 : // A couple reasons we might need to call drawPath.
412 0 : if (paint.getMaskFilter() || paint.getPathEffect()) {
413 0 : SkPath path;
414 0 : path.setIsVolatile(true);
415 0 : path.addRect(rect);
416 0 : GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(),
417 0 : this->clip(), path, paint, this->ctm(), nullptr,
418 0 : this->devClipBounds(), true);
419 0 : return;
420 : }
421 :
422 0 : GrPaint grPaint;
423 0 : if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
424 : &grPaint)) {
425 0 : return;
426 : }
427 :
428 0 : GrStyle style(paint);
429 0 : fRenderTargetContext->drawRect(this->clip(), std::move(grPaint),
430 0 : GrBoolToAA(paint.isAntiAlias()), this->ctm(), rect, &style);
431 : }
432 :
433 : ///////////////////////////////////////////////////////////////////////////////
434 :
435 0 : void SkGpuDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
436 0 : ASSERT_SINGLE_OWNER
437 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext.get());
438 : CHECK_SHOULD_DRAW();
439 :
440 0 : GrPaint grPaint;
441 0 : if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
442 : &grPaint)) {
443 0 : return;
444 : }
445 :
446 0 : SkMaskFilter* mf = paint.getMaskFilter();
447 0 : if (mf && mf->asFragmentProcessor(nullptr, nullptr, this->ctm())) {
448 0 : mf = nullptr; // already handled in SkPaintToGrPaint
449 : }
450 :
451 0 : GrStyle style(paint);
452 0 : if (mf) {
453 : // try to hit the fast path for drawing filtered round rects
454 :
455 0 : SkRRect devRRect;
456 0 : if (rrect.transform(this->ctm(), &devRRect)) {
457 0 : if (devRRect.allCornersCircular()) {
458 : SkRect maskRect;
459 0 : if (mf->canFilterMaskGPU(devRRect, this->devClipBounds(),
460 0 : this->ctm(), &maskRect)) {
461 : SkIRect finalIRect;
462 0 : maskRect.roundOut(&finalIRect);
463 :
464 : // we used to test finalIRect for quickReject, but that seems unlikely
465 : // given that the original shape was not rejected...
466 :
467 0 : if (mf->directFilterRRectMaskGPU(this->context(), fRenderTargetContext.get(),
468 0 : std::move(grPaint), this->clip(), this->ctm(),
469 0 : style.strokeRec(), rrect, devRRect)) {
470 0 : return;
471 : }
472 : }
473 :
474 : }
475 : }
476 : }
477 :
478 0 : if (mf || style.pathEffect()) {
479 : // The only mask filter the native rrect drawing code could've handle was taken
480 : // care of above.
481 : // A path effect will presumably transform this rrect into something else.
482 0 : SkPath path;
483 0 : path.setIsVolatile(true);
484 0 : path.addRRect(rrect);
485 0 : GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(),
486 0 : this->clip(), path, paint, this->ctm(), nullptr,
487 0 : this->devClipBounds(), true);
488 0 : return;
489 : }
490 :
491 0 : SkASSERT(!style.pathEffect());
492 :
493 0 : fRenderTargetContext->drawRRect(this->clip(), std::move(grPaint),
494 0 : GrBoolToAA(paint.isAntiAlias()), this->ctm(), rrect, style);
495 : }
496 :
497 :
498 0 : void SkGpuDevice::drawDRRect(const SkRRect& outer,
499 : const SkRRect& inner, const SkPaint& paint) {
500 0 : ASSERT_SINGLE_OWNER
501 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDRRect", fContext.get());
502 : CHECK_SHOULD_DRAW();
503 :
504 0 : if (outer.isEmpty()) {
505 0 : return;
506 : }
507 :
508 0 : if (inner.isEmpty()) {
509 0 : return this->drawRRect(outer, paint);
510 : }
511 :
512 0 : SkStrokeRec stroke(paint);
513 :
514 0 : if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) {
515 0 : GrPaint grPaint;
516 0 : if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
517 : &grPaint)) {
518 0 : return;
519 : }
520 :
521 0 : fRenderTargetContext->drawDRRect(this->clip(), std::move(grPaint),
522 0 : GrBoolToAA(paint.isAntiAlias()), this->ctm(), outer,
523 0 : inner);
524 0 : return;
525 : }
526 :
527 0 : SkPath path;
528 0 : path.setIsVolatile(true);
529 0 : path.addRRect(outer);
530 0 : path.addRRect(inner);
531 0 : path.setFillType(SkPath::kEvenOdd_FillType);
532 :
533 0 : GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(), this->clip(),
534 0 : path, paint, this->ctm(), nullptr, this->devClipBounds(),
535 0 : true);
536 : }
537 :
538 :
539 : /////////////////////////////////////////////////////////////////////////////
540 :
541 0 : void SkGpuDevice::drawRegion(const SkRegion& region, const SkPaint& paint) {
542 0 : if (paint.getMaskFilter()) {
543 0 : SkPath path;
544 0 : region.getBoundaryPath(&path);
545 0 : return this->drawPath(path, paint, nullptr, false);
546 : }
547 :
548 0 : GrPaint grPaint;
549 0 : if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
550 : &grPaint)) {
551 0 : return;
552 : }
553 :
554 0 : fRenderTargetContext->drawRegion(this->clip(), std::move(grPaint),
555 0 : GrBoolToAA(paint.isAntiAlias()), this->ctm(), region,
556 0 : GrStyle(paint));
557 : }
558 :
559 0 : void SkGpuDevice::drawOval(const SkRect& oval, const SkPaint& paint) {
560 0 : ASSERT_SINGLE_OWNER
561 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawOval", fContext.get());
562 : CHECK_SHOULD_DRAW();
563 :
564 : // Presumably the path effect warps this to something other than an oval
565 0 : if (paint.getPathEffect()) {
566 0 : SkPath path;
567 0 : path.setIsVolatile(true);
568 0 : path.addOval(oval);
569 0 : this->drawPath(path, paint, nullptr, true);
570 0 : return;
571 : }
572 :
573 0 : if (paint.getMaskFilter()) {
574 : // The RRect path can handle special case blurring
575 0 : SkRRect rr = SkRRect::MakeOval(oval);
576 0 : return this->drawRRect(rr, paint);
577 : }
578 :
579 0 : GrPaint grPaint;
580 0 : if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
581 : &grPaint)) {
582 0 : return;
583 : }
584 :
585 0 : fRenderTargetContext->drawOval(this->clip(), std::move(grPaint),
586 0 : GrBoolToAA(paint.isAntiAlias()), this->ctm(), oval,
587 0 : GrStyle(paint));
588 : }
589 :
590 0 : void SkGpuDevice::drawArc(const SkRect& oval, SkScalar startAngle,
591 : SkScalar sweepAngle, bool useCenter, const SkPaint& paint) {
592 0 : ASSERT_SINGLE_OWNER
593 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawArc", fContext.get());
594 : CHECK_SHOULD_DRAW();
595 :
596 0 : if (paint.getMaskFilter()) {
597 0 : this->INHERITED::drawArc(oval, startAngle, sweepAngle, useCenter, paint);
598 0 : return;
599 : }
600 0 : GrPaint grPaint;
601 0 : if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
602 : &grPaint)) {
603 0 : return;
604 : }
605 :
606 0 : fRenderTargetContext->drawArc(this->clip(), std::move(grPaint), GrBoolToAA(paint.isAntiAlias()),
607 : this->ctm(), oval, startAngle, sweepAngle, useCenter,
608 0 : GrStyle(paint));
609 : }
610 :
611 : #include "SkMaskFilter.h"
612 :
613 : ///////////////////////////////////////////////////////////////////////////////
614 0 : void SkGpuDevice::drawStrokedLine(const SkPoint points[2],
615 : const SkPaint& origPaint) {
616 0 : ASSERT_SINGLE_OWNER
617 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawStrokedLine", fContext.get());
618 : CHECK_SHOULD_DRAW();
619 :
620 : // Adding support for round capping would require a
621 : // GrRenderTargetContext::fillRRectWithLocalMatrix entry point
622 0 : SkASSERT(SkPaint::kRound_Cap != origPaint.getStrokeCap());
623 0 : SkASSERT(SkPaint::kStroke_Style == origPaint.getStyle());
624 0 : SkASSERT(!origPaint.getPathEffect());
625 0 : SkASSERT(!origPaint.getMaskFilter());
626 :
627 0 : const SkScalar halfWidth = 0.5f * origPaint.getStrokeWidth();
628 0 : SkASSERT(halfWidth > 0);
629 :
630 0 : SkVector v = points[1] - points[0];
631 :
632 0 : SkScalar length = SkPoint::Normalize(&v);
633 0 : if (!length) {
634 0 : v.fX = 1.0f;
635 0 : v.fY = 0.0f;
636 : }
637 :
638 0 : SkPaint newPaint(origPaint);
639 0 : newPaint.setStyle(SkPaint::kFill_Style);
640 :
641 0 : SkScalar xtraLength = 0.0f;
642 0 : if (SkPaint::kButt_Cap != origPaint.getStrokeCap()) {
643 0 : xtraLength = halfWidth;
644 : }
645 :
646 0 : SkPoint mid = points[0] + points[1];
647 0 : mid.scale(0.5f);
648 :
649 0 : SkRect rect = SkRect::MakeLTRB(mid.fX-halfWidth, mid.fY - 0.5f*length - xtraLength,
650 0 : mid.fX+halfWidth, mid.fY + 0.5f*length + xtraLength);
651 : SkMatrix m;
652 0 : m.setSinCos(v.fX, -v.fY, mid.fX, mid.fY);
653 :
654 0 : SkMatrix local = m;
655 :
656 0 : m.postConcat(this->ctm());
657 :
658 0 : GrPaint grPaint;
659 0 : if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), newPaint, m, &grPaint)) {
660 0 : return;
661 : }
662 :
663 0 : fRenderTargetContext->fillRectWithLocalMatrix(
664 0 : this->clip(), std::move(grPaint), GrBoolToAA(newPaint.isAntiAlias()), m, rect, local);
665 : }
666 :
667 0 : void SkGpuDevice::drawPath(const SkPath& origSrcPath,
668 : const SkPaint& paint, const SkMatrix* prePathMatrix,
669 : bool pathIsMutable) {
670 0 : ASSERT_SINGLE_OWNER
671 0 : if (!origSrcPath.isInverseFillType() && !paint.getPathEffect() && !prePathMatrix) {
672 : SkPoint points[2];
673 0 : if (SkPaint::kStroke_Style == paint.getStyle() && paint.getStrokeWidth() > 0 &&
674 0 : !paint.getMaskFilter() && SkPaint::kRound_Cap != paint.getStrokeCap() &&
675 0 : this->ctm().preservesRightAngles() && origSrcPath.isLine(points)) {
676 : // Path-based stroking looks better for thin rects
677 0 : SkScalar strokeWidth = this->ctm().getMaxScale() * paint.getStrokeWidth();
678 0 : if (strokeWidth >= 1.0f) {
679 : // Round capping support is currently disabled b.c. it would require a RRect
680 : // GrDrawOp that takes a localMatrix.
681 0 : this->drawStrokedLine(points, paint);
682 0 : return;
683 : }
684 : }
685 : bool isClosed;
686 : SkRect rect;
687 0 : if (origSrcPath.isRect(&rect, &isClosed) && isClosed) {
688 0 : this->drawRect(rect, paint);
689 0 : return;
690 : }
691 0 : if (origSrcPath.isOval(&rect)) {
692 0 : this->drawOval(rect, paint);
693 0 : return;
694 : }
695 0 : SkRRect rrect;
696 0 : if (origSrcPath.isRRect(&rrect)) {
697 0 : this->drawRRect(rrect, paint);
698 0 : return;
699 : }
700 : }
701 :
702 : CHECK_SHOULD_DRAW();
703 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext.get());
704 :
705 0 : GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(), this->clip(),
706 : origSrcPath, paint, this->ctm(), prePathMatrix,
707 0 : this->devClipBounds(), pathIsMutable);
708 : }
709 :
710 : static const int kBmpSmallTileSize = 1 << 10;
711 :
712 0 : static inline int get_tile_count(const SkIRect& srcRect, int tileSize) {
713 0 : int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1;
714 0 : int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1;
715 0 : return tilesX * tilesY;
716 : }
717 :
718 0 : static int determine_tile_size(const SkIRect& src, int maxTileSize) {
719 0 : if (maxTileSize <= kBmpSmallTileSize) {
720 0 : return maxTileSize;
721 : }
722 :
723 0 : size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize);
724 0 : size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize);
725 :
726 0 : maxTileTotalTileSize *= maxTileSize * maxTileSize;
727 0 : smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize;
728 :
729 0 : if (maxTileTotalTileSize > 2 * smallTotalTileSize) {
730 0 : return kBmpSmallTileSize;
731 : } else {
732 0 : return maxTileSize;
733 : }
734 : }
735 :
736 : // Given a bitmap, an optional src rect, and a context with a clip and matrix determine what
737 : // pixels from the bitmap are necessary.
738 0 : static void determine_clipped_src_rect(int width, int height,
739 : const GrClip& clip,
740 : const SkMatrix& viewMatrix,
741 : const SkMatrix& srcToDstRect,
742 : const SkISize& imageSize,
743 : const SkRect* srcRectPtr,
744 : SkIRect* clippedSrcIRect) {
745 0 : clip.getConservativeBounds(width, height, clippedSrcIRect, nullptr);
746 0 : SkMatrix inv = SkMatrix::Concat(viewMatrix, srcToDstRect);
747 0 : if (!inv.invert(&inv)) {
748 0 : clippedSrcIRect->setEmpty();
749 0 : return;
750 : }
751 0 : SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect);
752 0 : inv.mapRect(&clippedSrcRect);
753 0 : if (srcRectPtr) {
754 0 : if (!clippedSrcRect.intersect(*srcRectPtr)) {
755 0 : clippedSrcIRect->setEmpty();
756 0 : return;
757 : }
758 : }
759 0 : clippedSrcRect.roundOut(clippedSrcIRect);
760 0 : SkIRect bmpBounds = SkIRect::MakeSize(imageSize);
761 0 : if (!clippedSrcIRect->intersect(bmpBounds)) {
762 0 : clippedSrcIRect->setEmpty();
763 : }
764 : }
765 :
766 0 : bool SkGpuDevice::shouldTileImageID(uint32_t imageID, const SkIRect& imageRect,
767 : const SkMatrix& viewMatrix,
768 : const SkMatrix& srcToDstRect,
769 : const GrSamplerParams& params,
770 : const SkRect* srcRectPtr,
771 : int maxTileSize,
772 : int* tileSize,
773 : SkIRect* clippedSubset) const {
774 0 : ASSERT_SINGLE_OWNER
775 : // if it's larger than the max tile size, then we have no choice but tiling.
776 0 : if (imageRect.width() > maxTileSize || imageRect.height() > maxTileSize) {
777 0 : determine_clipped_src_rect(fRenderTargetContext->width(), fRenderTargetContext->height(),
778 0 : this->clip(), viewMatrix, srcToDstRect, imageRect.size(),
779 0 : srcRectPtr, clippedSubset);
780 0 : *tileSize = determine_tile_size(*clippedSubset, maxTileSize);
781 0 : return true;
782 : }
783 :
784 : // If the image would only produce 4 tiles of the smaller size, don't bother tiling it.
785 0 : const size_t area = imageRect.width() * imageRect.height();
786 0 : if (area < 4 * kBmpSmallTileSize * kBmpSmallTileSize) {
787 0 : return false;
788 : }
789 :
790 : // At this point we know we could do the draw by uploading the entire bitmap
791 : // as a texture. However, if the texture would be large compared to the
792 : // cache size and we don't require most of it for this draw then tile to
793 : // reduce the amount of upload and cache spill.
794 :
795 : // assumption here is that sw bitmap size is a good proxy for its size as
796 : // a texture
797 0 : size_t bmpSize = area * sizeof(SkPMColor); // assume 32bit pixels
798 : size_t cacheSize;
799 0 : fContext->getResourceCacheLimits(nullptr, &cacheSize);
800 0 : if (bmpSize < cacheSize / 2) {
801 0 : return false;
802 : }
803 :
804 : // Figure out how much of the src we will need based on the src rect and clipping. Reject if
805 : // tiling memory savings would be < 50%.
806 0 : determine_clipped_src_rect(fRenderTargetContext->width(), fRenderTargetContext->height(),
807 0 : this->clip(), viewMatrix, srcToDstRect, imageRect.size(), srcRectPtr,
808 0 : clippedSubset);
809 0 : *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
810 0 : size_t usedTileBytes = get_tile_count(*clippedSubset, kBmpSmallTileSize) *
811 : kBmpSmallTileSize * kBmpSmallTileSize *
812 0 : sizeof(SkPMColor); // assume 32bit pixels;
813 :
814 0 : return usedTileBytes * 2 < bmpSize;
815 : }
816 :
817 0 : bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr,
818 : SkCanvas::SrcRectConstraint constraint, SkFilterQuality quality,
819 : const SkMatrix& viewMatrix,
820 : const SkMatrix& srcToDstRect) const {
821 0 : ASSERT_SINGLE_OWNER
822 : // if image is explictly texture backed then just use the texture
823 0 : if (image->isTextureBacked()) {
824 0 : return false;
825 : }
826 :
827 0 : GrSamplerParams params;
828 : bool doBicubic;
829 : GrSamplerParams::FilterMode textureFilterMode =
830 0 : GrSkFilterQualityToGrFilterMode(quality, viewMatrix, srcToDstRect, &doBicubic);
831 :
832 : int tileFilterPad;
833 0 : if (doBicubic) {
834 0 : tileFilterPad = GrBicubicEffect::kFilterTexelPad;
835 0 : } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) {
836 0 : tileFilterPad = 0;
837 : } else {
838 0 : tileFilterPad = 1;
839 : }
840 0 : params.setFilterMode(textureFilterMode);
841 :
842 0 : int maxTileSize = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
843 :
844 : // these are output, which we safely ignore, as we just want to know the predicate
845 : int outTileSize;
846 : SkIRect outClippedSrcRect;
847 :
848 0 : return this->shouldTileImageID(image->unique(), image->bounds(), viewMatrix, srcToDstRect,
849 : params, srcRectPtr, maxTileSize, &outTileSize,
850 0 : &outClippedSrcRect);
851 : }
852 :
853 0 : void SkGpuDevice::drawBitmap(const SkBitmap& bitmap,
854 : const SkMatrix& m,
855 : const SkPaint& paint) {
856 0 : ASSERT_SINGLE_OWNER
857 : CHECK_SHOULD_DRAW();
858 : SkMatrix viewMatrix;
859 0 : viewMatrix.setConcat(this->ctm(), m);
860 :
861 0 : int maxTileSize = fContext->caps()->maxTileSize();
862 :
863 : // The tile code path doesn't currently support AA, so if the paint asked for aa and we could
864 : // draw untiled, then we bypass checking for tiling purely for optimization reasons.
865 0 : bool drawAA = !fRenderTargetContext->isUnifiedMultisampled() &&
866 0 : paint.isAntiAlias() &&
867 0 : bitmap.width() <= maxTileSize &&
868 0 : bitmap.height() <= maxTileSize;
869 :
870 0 : bool skipTileCheck = drawAA || paint.getMaskFilter();
871 :
872 0 : if (!skipTileCheck) {
873 0 : SkRect srcRect = SkRect::MakeIWH(bitmap.width(), bitmap.height());
874 : int tileSize;
875 : SkIRect clippedSrcRect;
876 :
877 0 : GrSamplerParams params;
878 : bool doBicubic;
879 : GrSamplerParams::FilterMode textureFilterMode =
880 0 : GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, SkMatrix::I(),
881 0 : &doBicubic);
882 :
883 : int tileFilterPad;
884 :
885 0 : if (doBicubic) {
886 0 : tileFilterPad = GrBicubicEffect::kFilterTexelPad;
887 0 : } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) {
888 0 : tileFilterPad = 0;
889 : } else {
890 0 : tileFilterPad = 1;
891 : }
892 0 : params.setFilterMode(textureFilterMode);
893 :
894 0 : int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
895 0 : if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), viewMatrix,
896 : SkMatrix::I(), params, &srcRect, maxTileSizeForFilter,
897 : &tileSize, &clippedSrcRect)) {
898 0 : this->drawTiledBitmap(bitmap, viewMatrix, SkMatrix::I(), srcRect, clippedSrcRect,
899 : params, paint, SkCanvas::kStrict_SrcRectConstraint, tileSize,
900 0 : doBicubic);
901 0 : return;
902 : }
903 : }
904 0 : GrBitmapTextureMaker maker(fContext.get(), bitmap);
905 : this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kStrict_SrcRectConstraint,
906 0 : viewMatrix, this->clip(), paint);
907 : }
908 :
909 : // This method outsets 'iRect' by 'outset' all around and then clamps its extents to
910 : // 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner
911 : // of 'iRect' for all possible outsets/clamps.
912 0 : static inline void clamped_outset_with_offset(SkIRect* iRect,
913 : int outset,
914 : SkPoint* offset,
915 : const SkIRect& clamp) {
916 0 : iRect->outset(outset, outset);
917 :
918 0 : int leftClampDelta = clamp.fLeft - iRect->fLeft;
919 0 : if (leftClampDelta > 0) {
920 0 : offset->fX -= outset - leftClampDelta;
921 0 : iRect->fLeft = clamp.fLeft;
922 : } else {
923 0 : offset->fX -= outset;
924 : }
925 :
926 0 : int topClampDelta = clamp.fTop - iRect->fTop;
927 0 : if (topClampDelta > 0) {
928 0 : offset->fY -= outset - topClampDelta;
929 0 : iRect->fTop = clamp.fTop;
930 : } else {
931 0 : offset->fY -= outset;
932 : }
933 :
934 0 : if (iRect->fRight > clamp.fRight) {
935 0 : iRect->fRight = clamp.fRight;
936 : }
937 0 : if (iRect->fBottom > clamp.fBottom) {
938 0 : iRect->fBottom = clamp.fBottom;
939 : }
940 0 : }
941 :
942 : // Break 'bitmap' into several tiles to draw it since it has already
943 : // been determined to be too large to fit in VRAM
944 0 : void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
945 : const SkMatrix& viewMatrix,
946 : const SkMatrix& dstMatrix,
947 : const SkRect& srcRect,
948 : const SkIRect& clippedSrcIRect,
949 : const GrSamplerParams& params,
950 : const SkPaint& origPaint,
951 : SkCanvas::SrcRectConstraint constraint,
952 : int tileSize,
953 : bool bicubic) {
954 0 : ASSERT_SINGLE_OWNER
955 :
956 : // This is the funnel for all paths that draw tiled bitmaps/images. Log histogram entries.
957 : SK_HISTOGRAM_BOOLEAN("DrawTiled", true);
958 0 : LogDrawScaleFactor(viewMatrix, origPaint.getFilterQuality());
959 :
960 : // The following pixel lock is technically redundant, but it is desirable
961 : // to lock outside of the tile loop to prevent redecoding the whole image
962 : // at each tile in cases where 'bitmap' holds an SkDiscardablePixelRef that
963 : // is larger than the limit of the discardable memory pool.
964 0 : SkAutoLockPixels alp(bitmap);
965 :
966 0 : const SkPaint* paint = &origPaint;
967 0 : SkPaint tempPaint;
968 0 : if (origPaint.isAntiAlias() && !fRenderTargetContext->isUnifiedMultisampled()) {
969 : // Drop antialiasing to avoid seams at tile boundaries.
970 0 : tempPaint = origPaint;
971 0 : tempPaint.setAntiAlias(false);
972 0 : paint = &tempPaint;
973 : }
974 0 : SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
975 :
976 0 : int nx = bitmap.width() / tileSize;
977 0 : int ny = bitmap.height() / tileSize;
978 0 : for (int x = 0; x <= nx; x++) {
979 0 : for (int y = 0; y <= ny; y++) {
980 : SkRect tileR;
981 0 : tileR.set(SkIntToScalar(x * tileSize),
982 0 : SkIntToScalar(y * tileSize),
983 0 : SkIntToScalar((x + 1) * tileSize),
984 0 : SkIntToScalar((y + 1) * tileSize));
985 :
986 0 : if (!SkRect::Intersects(tileR, clippedSrcRect)) {
987 0 : continue;
988 : }
989 :
990 0 : if (!tileR.intersect(srcRect)) {
991 0 : continue;
992 : }
993 :
994 : SkIRect iTileR;
995 0 : tileR.roundOut(&iTileR);
996 0 : SkVector offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft),
997 0 : SkIntToScalar(iTileR.fTop));
998 0 : SkRect rectToDraw = tileR;
999 0 : dstMatrix.mapRect(&rectToDraw);
1000 0 : if (GrSamplerParams::kNone_FilterMode != params.filterMode() || bicubic) {
1001 : SkIRect iClampRect;
1002 :
1003 0 : if (SkCanvas::kFast_SrcRectConstraint == constraint) {
1004 : // In bleed mode we want to always expand the tile on all edges
1005 : // but stay within the bitmap bounds
1006 0 : iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1007 : } else {
1008 : // In texture-domain/clamp mode we only want to expand the
1009 : // tile on edges interior to "srcRect" (i.e., we want to
1010 : // not bleed across the original clamped edges)
1011 0 : srcRect.roundOut(&iClampRect);
1012 : }
1013 0 : int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1;
1014 0 : clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect);
1015 : }
1016 :
1017 0 : SkBitmap tmpB;
1018 0 : if (bitmap.extractSubset(&tmpB, iTileR)) {
1019 : // now offset it to make it "local" to our tmp bitmap
1020 0 : tileR.offset(-offset.fX, -offset.fY);
1021 : // de-optimized this determination
1022 0 : bool needsTextureDomain = true;
1023 0 : this->drawBitmapTile(tmpB,
1024 : viewMatrix,
1025 : rectToDraw,
1026 : tileR,
1027 : params,
1028 : *paint,
1029 : constraint,
1030 : bicubic,
1031 0 : needsTextureDomain);
1032 : }
1033 : }
1034 : }
1035 0 : }
1036 :
1037 0 : void SkGpuDevice::drawBitmapTile(const SkBitmap& bitmap,
1038 : const SkMatrix& viewMatrix,
1039 : const SkRect& dstRect,
1040 : const SkRect& srcRect,
1041 : const GrSamplerParams& params,
1042 : const SkPaint& paint,
1043 : SkCanvas::SrcRectConstraint constraint,
1044 : bool bicubic,
1045 : bool needsTextureDomain) {
1046 : // We should have already handled bitmaps larger than the max texture size.
1047 0 : SkASSERT(bitmap.width() <= fContext->caps()->maxTextureSize() &&
1048 : bitmap.height() <= fContext->caps()->maxTextureSize());
1049 : // We should be respecting the max tile size by the time we get here.
1050 0 : SkASSERT(bitmap.width() <= fContext->caps()->maxTileSize() &&
1051 : bitmap.height() <= fContext->caps()->maxTileSize());
1052 :
1053 0 : SkASSERT(SkShader::kClamp_TileMode == params.getTileModeX() &&
1054 : SkShader::kClamp_TileMode == params.getTileModeY());
1055 :
1056 : sk_sp<GrTextureProxy> proxy = GrRefCachedBitmapTextureProxy(fContext.get(), bitmap,
1057 0 : params, nullptr);
1058 0 : if (!proxy) {
1059 0 : return;
1060 : }
1061 : sk_sp<GrColorSpaceXform> colorSpaceXform =
1062 0 : GrColorSpaceXform::Make(bitmap.colorSpace(), fRenderTargetContext->getColorSpace());
1063 :
1064 : // Compute a matrix that maps the rect we will draw to the src rect.
1065 : const SkMatrix texMatrix = SkMatrix::MakeRectToRect(dstRect, srcRect,
1066 0 : SkMatrix::kFill_ScaleToFit);
1067 :
1068 : // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring
1069 : // the rest from the SkPaint.
1070 0 : sk_sp<GrFragmentProcessor> fp;
1071 :
1072 0 : if (needsTextureDomain && (SkCanvas::kStrict_SrcRectConstraint == constraint)) {
1073 : // Use a constrained texture domain to avoid color bleeding
1074 : SkRect domain;
1075 0 : if (srcRect.width() > SK_Scalar1) {
1076 0 : domain.fLeft = srcRect.fLeft + 0.5f;
1077 0 : domain.fRight = srcRect.fRight - 0.5f;
1078 : } else {
1079 0 : domain.fLeft = domain.fRight = srcRect.centerX();
1080 : }
1081 0 : if (srcRect.height() > SK_Scalar1) {
1082 0 : domain.fTop = srcRect.fTop + 0.5f;
1083 0 : domain.fBottom = srcRect.fBottom - 0.5f;
1084 : } else {
1085 0 : domain.fTop = domain.fBottom = srcRect.centerY();
1086 : }
1087 0 : if (bicubic) {
1088 0 : fp = GrBicubicEffect::Make(this->context()->resourceProvider(), std::move(proxy),
1089 0 : std::move(colorSpaceXform), texMatrix, domain);
1090 : } else {
1091 0 : fp = GrTextureDomainEffect::Make(this->context()->resourceProvider(), std::move(proxy),
1092 0 : std::move(colorSpaceXform), texMatrix,
1093 : domain, GrTextureDomain::kClamp_Mode,
1094 0 : params.filterMode());
1095 0 : }
1096 0 : } else if (bicubic) {
1097 0 : SkASSERT(GrSamplerParams::kNone_FilterMode == params.filterMode());
1098 0 : SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() };
1099 0 : fp = GrBicubicEffect::Make(this->context()->resourceProvider(), std::move(proxy),
1100 0 : std::move(colorSpaceXform), texMatrix, tileModes);
1101 : } else {
1102 0 : fp = GrSimpleTextureEffect::Make(this->context()->resourceProvider(), std::move(proxy),
1103 0 : std::move(colorSpaceXform), texMatrix, params);
1104 : }
1105 :
1106 0 : GrPaint grPaint;
1107 0 : if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint, viewMatrix,
1108 0 : std::move(fp), kAlpha_8_SkColorType == bitmap.colorType(),
1109 : &grPaint)) {
1110 0 : return;
1111 : }
1112 :
1113 : // Coverage-based AA would cause seams between tiles.
1114 0 : GrAA aa = GrBoolToAA(paint.isAntiAlias() &&
1115 0 : fRenderTargetContext->isStencilBufferMultisampled());
1116 0 : fRenderTargetContext->drawRect(this->clip(), std::move(grPaint), aa, viewMatrix, dstRect);
1117 : }
1118 :
1119 0 : void SkGpuDevice::drawSprite(const SkBitmap& bitmap,
1120 : int left, int top, const SkPaint& paint) {
1121 0 : ASSERT_SINGLE_OWNER
1122 : CHECK_SHOULD_DRAW();
1123 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSprite", fContext.get());
1124 :
1125 0 : if (fContext->abandoned()) {
1126 0 : return;
1127 : }
1128 :
1129 0 : sk_sp<SkSpecialImage> srcImg = this->makeSpecial(bitmap);
1130 0 : if (!srcImg) {
1131 0 : return;
1132 : }
1133 :
1134 0 : this->drawSpecial(srcImg.get(), left, top, paint);
1135 : }
1136 :
1137 :
1138 0 : void SkGpuDevice::drawSpecial(SkSpecialImage* special1,
1139 : int left, int top,
1140 : const SkPaint& paint) {
1141 0 : ASSERT_SINGLE_OWNER
1142 : CHECK_SHOULD_DRAW();
1143 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSpecial", fContext.get());
1144 :
1145 0 : SkIPoint offset = { 0, 0 };
1146 :
1147 0 : sk_sp<SkSpecialImage> result;
1148 0 : if (paint.getImageFilter()) {
1149 0 : result = this->filterTexture(special1, left, top,
1150 : &offset,
1151 0 : paint.getImageFilter());
1152 0 : if (!result) {
1153 0 : return;
1154 : }
1155 : } else {
1156 0 : result = sk_ref_sp(special1);
1157 : }
1158 :
1159 0 : SkASSERT(result->isTextureBacked());
1160 0 : sk_sp<GrTextureProxy> proxy = result->asTextureProxyRef(this->context());
1161 0 : if (!proxy) {
1162 0 : return;
1163 : }
1164 :
1165 0 : const GrPixelConfig config = proxy->config();
1166 :
1167 0 : SkPaint tmpUnfiltered(paint);
1168 0 : tmpUnfiltered.setImageFilter(nullptr);
1169 :
1170 : sk_sp<GrColorSpaceXform> colorSpaceXform =
1171 0 : GrColorSpaceXform::Make(result->getColorSpace(), fRenderTargetContext->getColorSpace());
1172 :
1173 0 : sk_sp<GrFragmentProcessor> fp(GrSimpleTextureEffect::Make(this->context()->resourceProvider(),
1174 0 : std::move(proxy),
1175 0 : std::move(colorSpaceXform),
1176 0 : SkMatrix::I()));
1177 0 : if (GrPixelConfigIsAlphaOnly(config)) {
1178 0 : fp = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
1179 : } else {
1180 0 : fp = GrFragmentProcessor::MulOutputByInputAlpha(std::move(fp));
1181 : }
1182 :
1183 0 : GrPaint grPaint;
1184 0 : if (!SkPaintToGrPaintReplaceShader(this->context(), fRenderTargetContext.get(), tmpUnfiltered,
1185 0 : std::move(fp), &grPaint)) {
1186 0 : return;
1187 : }
1188 :
1189 0 : const SkIRect& subset = result->subset();
1190 :
1191 0 : fRenderTargetContext->fillRectToRect(
1192 0 : this->clip(),
1193 0 : std::move(grPaint),
1194 0 : GrBoolToAA(paint.isAntiAlias()),
1195 : SkMatrix::I(),
1196 0 : SkRect::Make(SkIRect::MakeXYWH(left + offset.fX, top + offset.fY, subset.width(),
1197 0 : subset.height())),
1198 0 : SkRect::Make(subset));
1199 : }
1200 :
1201 0 : void SkGpuDevice::drawBitmapRect(const SkBitmap& bitmap,
1202 : const SkRect* src, const SkRect& origDst,
1203 : const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
1204 0 : ASSERT_SINGLE_OWNER
1205 : CHECK_SHOULD_DRAW();
1206 :
1207 : // The src rect is inferred to be the bmp bounds if not provided. Otherwise, the src rect must
1208 : // be clipped to the bmp bounds. To determine tiling parameters we need the filter mode which
1209 : // in turn requires knowing the src-to-dst mapping. If the src was clipped to the bmp bounds
1210 : // then we use the src-to-dst mapping to compute a new clipped dst rect.
1211 0 : const SkRect* dst = &origDst;
1212 0 : const SkRect bmpBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1213 : // Compute matrix from the two rectangles
1214 0 : if (!src) {
1215 0 : src = &bmpBounds;
1216 : }
1217 :
1218 : SkMatrix srcToDstMatrix;
1219 0 : if (!srcToDstMatrix.setRectToRect(*src, *dst, SkMatrix::kFill_ScaleToFit)) {
1220 0 : return;
1221 : }
1222 : SkRect tmpSrc, tmpDst;
1223 0 : if (src != &bmpBounds) {
1224 0 : if (!bmpBounds.contains(*src)) {
1225 0 : tmpSrc = *src;
1226 0 : if (!tmpSrc.intersect(bmpBounds)) {
1227 0 : return; // nothing to draw
1228 : }
1229 0 : src = &tmpSrc;
1230 0 : srcToDstMatrix.mapRect(&tmpDst, *src);
1231 0 : dst = &tmpDst;
1232 : }
1233 : }
1234 :
1235 0 : int maxTileSize = fContext->caps()->maxTileSize();
1236 :
1237 : // The tile code path doesn't currently support AA, so if the paint asked for aa and we could
1238 : // draw untiled, then we bypass checking for tiling purely for optimization reasons.
1239 0 : bool drawAA = !fRenderTargetContext->isUnifiedMultisampled() &&
1240 0 : paint.isAntiAlias() &&
1241 0 : bitmap.width() <= maxTileSize &&
1242 0 : bitmap.height() <= maxTileSize;
1243 :
1244 0 : bool skipTileCheck = drawAA || paint.getMaskFilter();
1245 :
1246 0 : if (!skipTileCheck) {
1247 : int tileSize;
1248 : SkIRect clippedSrcRect;
1249 :
1250 0 : GrSamplerParams params;
1251 : bool doBicubic;
1252 : GrSamplerParams::FilterMode textureFilterMode =
1253 0 : GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), this->ctm(), srcToDstMatrix,
1254 0 : &doBicubic);
1255 :
1256 : int tileFilterPad;
1257 :
1258 0 : if (doBicubic) {
1259 0 : tileFilterPad = GrBicubicEffect::kFilterTexelPad;
1260 0 : } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) {
1261 0 : tileFilterPad = 0;
1262 : } else {
1263 0 : tileFilterPad = 1;
1264 : }
1265 0 : params.setFilterMode(textureFilterMode);
1266 :
1267 0 : int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
1268 0 : if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), this->ctm(),
1269 : srcToDstMatrix, params, src, maxTileSizeForFilter, &tileSize,
1270 : &clippedSrcRect)) {
1271 0 : this->drawTiledBitmap(bitmap, this->ctm(), srcToDstMatrix, *src, clippedSrcRect,
1272 0 : params, paint, constraint, tileSize, doBicubic);
1273 0 : return;
1274 : }
1275 : }
1276 0 : GrBitmapTextureMaker maker(fContext.get(), bitmap);
1277 0 : this->drawTextureProducer(&maker, src, dst, constraint, this->ctm(), this->clip(), paint);
1278 : }
1279 :
1280 0 : sk_sp<SkSpecialImage> SkGpuDevice::makeSpecial(const SkBitmap& bitmap) {
1281 : // TODO: this makes a tight copy of 'bitmap' but it doesn't have to be (given SkSpecialImage's
1282 : // semantics). Since this is cached we would have to bake the fit into the cache key though.
1283 0 : sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(fContext->resourceProvider(), bitmap);
1284 0 : if (!proxy) {
1285 0 : return nullptr;
1286 : }
1287 :
1288 0 : const SkIRect rect = SkIRect::MakeWH(proxy->width(), proxy->height());
1289 :
1290 : // GrMakeCachedBitmapProxy creates a tight copy of 'bitmap' so we don't have to subset
1291 : // the special image
1292 : return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
1293 : rect,
1294 : bitmap.getGenerationID(),
1295 0 : std::move(proxy),
1296 0 : bitmap.refColorSpace(),
1297 0 : &this->surfaceProps());
1298 : }
1299 :
1300 0 : sk_sp<SkSpecialImage> SkGpuDevice::makeSpecial(const SkImage* image) {
1301 0 : SkPixmap pm;
1302 0 : if (image->isTextureBacked()) {
1303 0 : sk_sp<GrTextureProxy> proxy = as_IB(image)->asTextureProxyRef();
1304 :
1305 : return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
1306 0 : SkIRect::MakeWH(image->width(), image->height()),
1307 : image->uniqueID(),
1308 0 : std::move(proxy),
1309 0 : as_IB(image)->onImageInfo().refColorSpace(),
1310 0 : &this->surfaceProps());
1311 0 : } else if (image->peekPixels(&pm)) {
1312 0 : SkBitmap bm;
1313 :
1314 0 : bm.installPixels(pm);
1315 0 : return this->makeSpecial(bm);
1316 : } else {
1317 0 : return nullptr;
1318 : }
1319 : }
1320 :
1321 0 : sk_sp<SkSpecialImage> SkGpuDevice::snapSpecial() {
1322 0 : sk_sp<GrTextureProxy> proxy(this->accessRenderTargetContext()->asTextureProxyRef());
1323 0 : if (!proxy) {
1324 : // When the device doesn't have a texture, we create a temporary texture.
1325 : // TODO: we should actually only copy the portion of the source needed to apply the image
1326 : // filter
1327 0 : proxy = GrSurfaceProxy::Copy(fContext.get(),
1328 0 : this->accessRenderTargetContext()->asSurfaceProxy(),
1329 0 : SkBudgeted::kYes);
1330 0 : if (!proxy) {
1331 0 : return nullptr;
1332 : }
1333 : }
1334 :
1335 0 : const SkImageInfo ii = this->imageInfo();
1336 0 : const SkIRect srcRect = SkIRect::MakeWH(ii.width(), ii.height());
1337 :
1338 0 : SkASSERT(proxy->priv().isExact());
1339 : return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
1340 : srcRect,
1341 : kNeedNewImageUniqueID_SpecialImage,
1342 0 : std::move(proxy),
1343 0 : ii.refColorSpace(),
1344 0 : &this->surfaceProps());
1345 : }
1346 :
1347 0 : void SkGpuDevice::drawDevice(SkBaseDevice* device,
1348 : int left, int top, const SkPaint& paint) {
1349 0 : SkASSERT(!paint.getImageFilter());
1350 :
1351 0 : ASSERT_SINGLE_OWNER
1352 : // clear of the source device must occur before CHECK_SHOULD_DRAW
1353 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDevice", fContext.get());
1354 :
1355 : // drawDevice is defined to be in device coords.
1356 : CHECK_SHOULD_DRAW();
1357 :
1358 0 : SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
1359 0 : sk_sp<SkSpecialImage> srcImg(dev->snapSpecial());
1360 0 : if (!srcImg) {
1361 0 : return;
1362 : }
1363 :
1364 0 : this->drawSpecial(srcImg.get(), left, top, paint);
1365 : }
1366 :
1367 0 : void SkGpuDevice::drawImage(const SkImage* image, SkScalar x, SkScalar y,
1368 : const SkPaint& paint) {
1369 0 : ASSERT_SINGLE_OWNER
1370 0 : SkMatrix viewMatrix = this->ctm();
1371 0 : viewMatrix.preTranslate(x, y);
1372 : uint32_t pinnedUniqueID;
1373 :
1374 0 : if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
1375 : CHECK_SHOULD_DRAW();
1376 0 : GrTextureAdjuster adjuster(this->context(), std::move(proxy),
1377 0 : image->alphaType(), image->bounds(),
1378 0 : pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace());
1379 : this->drawTextureProducer(&adjuster, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint,
1380 0 : viewMatrix, this->clip(), paint);
1381 0 : return;
1382 : } else {
1383 0 : SkBitmap bm;
1384 0 : if (this->shouldTileImage(image, nullptr, SkCanvas::kFast_SrcRectConstraint,
1385 : paint.getFilterQuality(), this->ctm(), SkMatrix::I())) {
1386 : // only support tiling as bitmap at the moment, so force raster-version
1387 0 : if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
1388 0 : return;
1389 : }
1390 0 : this->drawBitmap(bm, SkMatrix::MakeTrans(x, y), paint);
1391 0 : } else if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) {
1392 : CHECK_SHOULD_DRAW();
1393 0 : GrImageTextureMaker maker(fContext.get(), cacher, image, SkImage::kAllow_CachingHint);
1394 : this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint,
1395 0 : viewMatrix, this->clip(), paint);
1396 0 : } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
1397 0 : this->drawBitmap(bm, SkMatrix::MakeTrans(x, y), paint);
1398 : }
1399 : }
1400 : }
1401 :
1402 0 : void SkGpuDevice::drawImageRect(const SkImage* image, const SkRect* src,
1403 : const SkRect& dst, const SkPaint& paint,
1404 : SkCanvas::SrcRectConstraint constraint) {
1405 0 : ASSERT_SINGLE_OWNER
1406 : uint32_t pinnedUniqueID;
1407 0 : if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
1408 : CHECK_SHOULD_DRAW();
1409 0 : GrTextureAdjuster adjuster(this->context(), std::move(proxy),
1410 0 : image->alphaType(), image->bounds(), pinnedUniqueID,
1411 0 : as_IB(image)->onImageInfo().colorSpace());
1412 0 : this->drawTextureProducer(&adjuster, src, &dst, constraint, this->ctm(), this->clip(),
1413 0 : paint);
1414 0 : return;
1415 : }
1416 0 : SkBitmap bm;
1417 : SkMatrix srcToDstRect;
1418 0 : srcToDstRect.setRectToRect((src ? *src : SkRect::MakeIWH(image->width(), image->height())),
1419 0 : dst, SkMatrix::kFill_ScaleToFit);
1420 0 : if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), this->ctm(),
1421 : srcToDstRect)) {
1422 : // only support tiling as bitmap at the moment, so force raster-version
1423 0 : if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
1424 0 : return;
1425 : }
1426 0 : this->drawBitmapRect(bm, src, dst, paint, constraint);
1427 0 : } else if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) {
1428 : CHECK_SHOULD_DRAW();
1429 0 : GrImageTextureMaker maker(fContext.get(), cacher, image, SkImage::kAllow_CachingHint);
1430 0 : this->drawTextureProducer(&maker, src, &dst, constraint, this->ctm(), this->clip(), paint);
1431 0 : } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
1432 0 : this->drawBitmapRect(bm, src, dst, paint, constraint);
1433 : }
1434 : }
1435 :
1436 0 : void SkGpuDevice::drawProducerNine(GrTextureProducer* producer,
1437 : const SkIRect& center, const SkRect& dst, const SkPaint& paint) {
1438 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerNine", fContext.get());
1439 :
1440 : CHECK_SHOULD_DRAW();
1441 :
1442 0 : bool useFallback = paint.getMaskFilter() || paint.isAntiAlias() ||
1443 0 : fRenderTargetContext->isUnifiedMultisampled();
1444 : bool doBicubic;
1445 : GrSamplerParams::FilterMode textureFilterMode =
1446 0 : GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), this->ctm(), SkMatrix::I(),
1447 0 : &doBicubic);
1448 0 : if (useFallback || doBicubic || GrSamplerParams::kNone_FilterMode != textureFilterMode) {
1449 0 : SkLatticeIter iter(producer->width(), producer->height(), center, dst);
1450 :
1451 : SkRect srcR, dstR;
1452 0 : while (iter.next(&srcR, &dstR)) {
1453 0 : this->drawTextureProducer(producer, &srcR, &dstR, SkCanvas::kStrict_SrcRectConstraint,
1454 0 : this->ctm(), this->clip(), paint);
1455 : }
1456 0 : return;
1457 : }
1458 :
1459 : static const GrSamplerParams::FilterMode kMode = GrSamplerParams::kNone_FilterMode;
1460 : sk_sp<GrFragmentProcessor> fp(
1461 : producer->createFragmentProcessor(SkMatrix::I(),
1462 0 : SkRect::MakeIWH(producer->width(), producer->height()),
1463 : GrTextureProducer::kNo_FilterConstraint, true,
1464 0 : &kMode, fRenderTargetContext->getColorSpace()));
1465 0 : GrPaint grPaint;
1466 0 : if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint,
1467 0 : this->ctm(), std::move(fp), producer->isAlphaOnly(),
1468 : &grPaint)) {
1469 0 : return;
1470 : }
1471 :
1472 : std::unique_ptr<SkLatticeIter> iter(
1473 0 : new SkLatticeIter(producer->width(), producer->height(), center, dst));
1474 0 : fRenderTargetContext->drawImageLattice(this->clip(), std::move(grPaint), this->ctm(),
1475 0 : producer->width(), producer->height(), std::move(iter),
1476 0 : dst);
1477 : }
1478 :
1479 0 : void SkGpuDevice::drawImageNine(const SkImage* image,
1480 : const SkIRect& center, const SkRect& dst, const SkPaint& paint) {
1481 0 : ASSERT_SINGLE_OWNER
1482 : uint32_t pinnedUniqueID;
1483 0 : if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
1484 : CHECK_SHOULD_DRAW();
1485 0 : GrTextureAdjuster adjuster(this->context(), std::move(proxy),
1486 0 : image->alphaType(), image->bounds(),
1487 0 : pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace());
1488 0 : this->drawProducerNine(&adjuster, center, dst, paint);
1489 : } else {
1490 0 : SkBitmap bm;
1491 0 : if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) {
1492 0 : GrImageTextureMaker maker(fContext.get(), cacher, image, SkImage::kAllow_CachingHint);
1493 0 : this->drawProducerNine(&maker, center, dst, paint);
1494 0 : } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
1495 0 : this->drawBitmapNine(bm, center, dst, paint);
1496 : }
1497 : }
1498 0 : }
1499 :
1500 0 : void SkGpuDevice::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1501 : const SkRect& dst, const SkPaint& paint) {
1502 0 : ASSERT_SINGLE_OWNER
1503 0 : GrBitmapTextureMaker maker(fContext.get(), bitmap);
1504 0 : this->drawProducerNine(&maker, center, dst, paint);
1505 0 : }
1506 :
1507 0 : void SkGpuDevice::drawProducerLattice(GrTextureProducer* producer,
1508 : const SkCanvas::Lattice& lattice, const SkRect& dst,
1509 : const SkPaint& paint) {
1510 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerLattice", fContext.get());
1511 :
1512 : CHECK_SHOULD_DRAW();
1513 :
1514 : static const GrSamplerParams::FilterMode kMode = GrSamplerParams::kNone_FilterMode;
1515 : sk_sp<GrFragmentProcessor> fp(
1516 : producer->createFragmentProcessor(SkMatrix::I(),
1517 0 : SkRect::MakeIWH(producer->width(), producer->height()),
1518 : GrTextureProducer::kNo_FilterConstraint, true,
1519 0 : &kMode, fRenderTargetContext->getColorSpace()));
1520 0 : GrPaint grPaint;
1521 0 : if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint,
1522 0 : this->ctm(), std::move(fp), producer->isAlphaOnly(),
1523 : &grPaint)) {
1524 0 : return;
1525 : }
1526 :
1527 : std::unique_ptr<SkLatticeIter> iter(
1528 0 : new SkLatticeIter(lattice, dst));
1529 0 : fRenderTargetContext->drawImageLattice(this->clip(), std::move(grPaint), this->ctm(),
1530 0 : producer->width(), producer->height(), std::move(iter),
1531 0 : dst);
1532 : }
1533 :
1534 0 : void SkGpuDevice::drawImageLattice(const SkImage* image,
1535 : const SkCanvas::Lattice& lattice, const SkRect& dst,
1536 : const SkPaint& paint) {
1537 0 : ASSERT_SINGLE_OWNER
1538 : uint32_t pinnedUniqueID;
1539 0 : if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
1540 : CHECK_SHOULD_DRAW();
1541 0 : GrTextureAdjuster adjuster(this->context(), std::move(proxy),
1542 0 : image->alphaType(), image->bounds(),
1543 0 : pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace());
1544 0 : this->drawProducerLattice(&adjuster, lattice, dst, paint);
1545 : } else {
1546 0 : SkBitmap bm;
1547 0 : if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) {
1548 0 : GrImageTextureMaker maker(fContext.get(), cacher, image, SkImage::kAllow_CachingHint);
1549 0 : this->drawProducerLattice(&maker, lattice, dst, paint);
1550 0 : } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
1551 0 : this->drawBitmapLattice(bm, lattice, dst, paint);
1552 : }
1553 : }
1554 0 : }
1555 :
1556 0 : void SkGpuDevice::drawBitmapLattice(const SkBitmap& bitmap,
1557 : const SkCanvas::Lattice& lattice, const SkRect& dst,
1558 : const SkPaint& paint) {
1559 0 : ASSERT_SINGLE_OWNER
1560 0 : GrBitmapTextureMaker maker(fContext.get(), bitmap);
1561 0 : this->drawProducerLattice(&maker, lattice, dst, paint);
1562 0 : }
1563 :
1564 0 : static bool init_vertices_paint(GrContext* context, GrRenderTargetContext* rtc,
1565 : const SkPaint& skPaint,
1566 : const SkMatrix& matrix, SkBlendMode bmode,
1567 : bool hasTexs, bool hasColors, GrPaint* grPaint) {
1568 0 : if (hasTexs && skPaint.getShader()) {
1569 0 : if (hasColors) {
1570 : // When there are texs and colors the shader and colors are combined using bmode.
1571 : return SkPaintToGrPaintWithXfermode(context, rtc, skPaint, matrix, bmode, false,
1572 0 : grPaint);
1573 : } else {
1574 : // We have a shader, but no colors to blend it against.
1575 0 : return SkPaintToGrPaint(context, rtc, skPaint, matrix, grPaint);
1576 : }
1577 : } else {
1578 0 : if (hasColors) {
1579 : // We have colors, but either have no shader or no texture coords (which implies that
1580 : // we should ignore the shader).
1581 0 : return SkPaintToGrPaintWithPrimitiveColor(context, rtc, skPaint, grPaint);
1582 : } else {
1583 : // No colors and no shaders. Just draw with the paint color.
1584 0 : return (!SkPaintToGrPaintNoShader(context, rtc, skPaint, grPaint));
1585 : }
1586 : }
1587 : }
1588 :
1589 0 : void SkGpuDevice::wireframeVertices(SkVertices::VertexMode vmode, int vertexCount,
1590 : const SkPoint vertices[], SkBlendMode bmode,
1591 : const uint16_t indices[], int indexCount,
1592 : const SkPaint& paint) {
1593 0 : ASSERT_SINGLE_OWNER
1594 : CHECK_SHOULD_DRAW();
1595 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "wireframeVertices", fContext.get());
1596 :
1597 0 : SkPaint copy(paint);
1598 0 : copy.setStyle(SkPaint::kStroke_Style);
1599 0 : copy.setStrokeWidth(0);
1600 :
1601 0 : GrPaint grPaint;
1602 : // we ignore the shader since we have no texture coordinates.
1603 0 : if (!SkPaintToGrPaintNoShader(this->context(), fRenderTargetContext.get(), copy, &grPaint)) {
1604 0 : return;
1605 : }
1606 :
1607 0 : int triangleCount = 0;
1608 0 : int n = (nullptr == indices) ? vertexCount : indexCount;
1609 0 : switch (vmode) {
1610 : case SkVertices::kTriangles_VertexMode:
1611 0 : triangleCount = n / 3;
1612 0 : break;
1613 : case SkVertices::kTriangleStrip_VertexMode:
1614 : case SkVertices::kTriangleFan_VertexMode:
1615 0 : triangleCount = n - 2;
1616 0 : break;
1617 : }
1618 :
1619 0 : VertState state(vertexCount, indices, indexCount);
1620 0 : VertState::Proc vertProc = state.chooseProc(vmode);
1621 :
1622 : //number of indices for lines per triangle with kLines
1623 0 : indexCount = triangleCount * 6;
1624 :
1625 0 : std::unique_ptr<uint16_t[]> lineIndices(new uint16_t[indexCount]);
1626 0 : int i = 0;
1627 0 : while (vertProc(&state)) {
1628 0 : lineIndices[i] = state.f0;
1629 0 : lineIndices[i + 1] = state.f1;
1630 0 : lineIndices[i + 2] = state.f1;
1631 0 : lineIndices[i + 3] = state.f2;
1632 0 : lineIndices[i + 4] = state.f2;
1633 0 : lineIndices[i + 5] = state.f0;
1634 0 : i += 6;
1635 : }
1636 0 : fRenderTargetContext->drawVertices(this->clip(),
1637 0 : std::move(grPaint),
1638 : this->ctm(),
1639 : kLines_GrPrimitiveType,
1640 : vertexCount,
1641 : vertices,
1642 : nullptr,
1643 : nullptr,
1644 0 : lineIndices.get(),
1645 0 : indexCount);
1646 : }
1647 :
1648 0 : void SkGpuDevice::drawVertices(const SkVertices* vertices, SkBlendMode mode,
1649 : const SkPaint& paint) {
1650 0 : ASSERT_SINGLE_OWNER
1651 : CHECK_SHOULD_DRAW();
1652 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext.get());
1653 :
1654 0 : SkASSERT(vertices);
1655 0 : GrPaint grPaint;
1656 0 : bool hasColors = vertices->hasColors();
1657 0 : bool hasTexs = vertices->hasTexCoords();
1658 0 : if (!hasTexs && !hasColors) {
1659 : // The dreaded wireframe mode. Fallback to drawVertices and go so slooooooow.
1660 0 : this->wireframeVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
1661 0 : mode, vertices->indices(), vertices->indexCount(), paint);
1662 : }
1663 0 : if (!init_vertices_paint(fContext.get(), fRenderTargetContext.get(), paint, this->ctm(),
1664 : mode, hasTexs, hasColors, &grPaint)) {
1665 0 : return;
1666 : }
1667 0 : fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), this->ctm(),
1668 0 : sk_ref_sp(const_cast<SkVertices*>(vertices)));
1669 : }
1670 :
1671 : ///////////////////////////////////////////////////////////////////////////////
1672 :
1673 0 : void SkGpuDevice::drawAtlas(const SkImage* atlas, const SkRSXform xform[],
1674 : const SkRect texRect[], const SkColor colors[], int count,
1675 : SkBlendMode mode, const SkPaint& paint) {
1676 0 : ASSERT_SINGLE_OWNER
1677 0 : if (paint.isAntiAlias()) {
1678 0 : this->INHERITED::drawAtlas(atlas, xform, texRect, colors, count, mode, paint);
1679 0 : return;
1680 : }
1681 :
1682 : CHECK_SHOULD_DRAW();
1683 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext.get());
1684 :
1685 0 : SkPaint p(paint);
1686 0 : p.setShader(atlas->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode));
1687 :
1688 0 : GrPaint grPaint;
1689 0 : if (colors) {
1690 0 : if (!SkPaintToGrPaintWithXfermode(this->context(), fRenderTargetContext.get(), p,
1691 : this->ctm(), (SkBlendMode)mode, true, &grPaint)) {
1692 0 : return;
1693 : }
1694 : } else {
1695 0 : if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), p, this->ctm(),
1696 : &grPaint)) {
1697 0 : return;
1698 : }
1699 : }
1700 :
1701 0 : SkDEBUGCODE(this->validate();)
1702 0 : fRenderTargetContext->drawAtlas(
1703 0 : this->clip(), std::move(grPaint), this->ctm(), count, xform, texRect, colors);
1704 : }
1705 :
1706 : ///////////////////////////////////////////////////////////////////////////////
1707 :
1708 0 : void SkGpuDevice::drawText(const void* text,
1709 : size_t byteLength, SkScalar x, SkScalar y,
1710 : const SkPaint& paint) {
1711 0 : ASSERT_SINGLE_OWNER
1712 : CHECK_SHOULD_DRAW();
1713 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext.get());
1714 0 : SkDEBUGCODE(this->validate();)
1715 :
1716 0 : fRenderTargetContext->drawText(this->clip(), paint, this->ctm(), (const char*)text, byteLength,
1717 0 : x, y, this->devClipBounds());
1718 0 : }
1719 :
1720 0 : void SkGpuDevice::drawPosText(const void* text, size_t byteLength,
1721 : const SkScalar pos[], int scalarsPerPos,
1722 : const SkPoint& offset, const SkPaint& paint) {
1723 0 : ASSERT_SINGLE_OWNER
1724 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPosText", fContext.get());
1725 : CHECK_SHOULD_DRAW();
1726 0 : SkDEBUGCODE(this->validate();)
1727 :
1728 0 : fRenderTargetContext->drawPosText(this->clip(), paint, this->ctm(), (const char*)text,
1729 : byteLength, pos, scalarsPerPos, offset,
1730 0 : this->devClipBounds());
1731 0 : }
1732 :
1733 0 : void SkGpuDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
1734 : const SkPaint& paint, SkDrawFilter* drawFilter) {
1735 0 : ASSERT_SINGLE_OWNER
1736 0 : GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawTextBlob", fContext.get());
1737 : CHECK_SHOULD_DRAW();
1738 :
1739 0 : SkDEBUGCODE(this->validate();)
1740 :
1741 0 : fRenderTargetContext->drawTextBlob(this->clip(), paint, this->ctm(), blob, x, y, drawFilter,
1742 0 : this->devClipBounds());
1743 0 : }
1744 :
1745 : ///////////////////////////////////////////////////////////////////////////////
1746 :
1747 0 : bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const {
1748 0 : return GrTextUtils::ShouldDisableLCD(paint);
1749 : }
1750 :
1751 0 : void SkGpuDevice::flush() {
1752 0 : ASSERT_SINGLE_OWNER
1753 :
1754 0 : fRenderTargetContext->prepareForExternalIO();
1755 0 : }
1756 :
1757 : ///////////////////////////////////////////////////////////////////////////////
1758 :
1759 0 : SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
1760 0 : ASSERT_SINGLE_OWNER
1761 :
1762 0 : SkSurfaceProps props(this->surfaceProps().flags(), cinfo.fPixelGeometry);
1763 :
1764 : // layers are never drawn in repeat modes, so we can request an approx
1765 : // match and ignore any padding.
1766 0 : SkBackingFit fit = kNever_TileUsage == cinfo.fTileUsage ? SkBackingFit::kApprox
1767 0 : : SkBackingFit::kExact;
1768 :
1769 : sk_sp<GrRenderTargetContext> rtc(fContext->makeRenderTargetContext(
1770 : fit,
1771 : cinfo.fInfo.width(), cinfo.fInfo.height(),
1772 : fRenderTargetContext->config(),
1773 0 : fRenderTargetContext->refColorSpace(),
1774 0 : fRenderTargetContext->desc().fSampleCnt,
1775 : kDefault_GrSurfaceOrigin,
1776 0 : &props));
1777 0 : if (!rtc) {
1778 0 : return nullptr;
1779 : }
1780 :
1781 : // Skia's convention is to only clear a device if it is non-opaque.
1782 0 : InitContents init = cinfo.fInfo.isOpaque() ? kUninit_InitContents : kClear_InitContents;
1783 :
1784 0 : return SkGpuDevice::Make(fContext.get(), std::move(rtc),
1785 0 : cinfo.fInfo.width(), cinfo.fInfo.height(), init).release();
1786 : }
1787 :
1788 0 : sk_sp<SkSurface> SkGpuDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1789 0 : ASSERT_SINGLE_OWNER
1790 : // TODO: Change the signature of newSurface to take a budgeted parameter.
1791 : static const SkBudgeted kBudgeted = SkBudgeted::kNo;
1792 : return SkSurface::MakeRenderTarget(fContext.get(), kBudgeted, info,
1793 0 : fRenderTargetContext->desc().fSampleCnt,
1794 0 : fRenderTargetContext->origin(), &props);
1795 : }
1796 :
1797 0 : SkImageFilterCache* SkGpuDevice::getImageFilterCache() {
1798 0 : ASSERT_SINGLE_OWNER
1799 : // We always return a transient cache, so it is freed after each
1800 : // filter traversal.
1801 0 : return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize);
1802 : }
1803 :
1804 : #endif
|