Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkBlitter.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
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
9
25#include "src/base/SkTLazy.h"
30#include "src/core/SkMask.h"
32#include "src/core/SkMemset.h"
36
37#include <cstddef>
38#include <functional>
39#include <optional>
40
41using namespace skia_private;
42
43// Hacks for testing.
45
47
48bool SkBlitter::isNullBlitter() const { return false; }
49
50/*
51void SkBlitter::blitH(int x, int y, int width) {
52 SkDEBUGFAIL("unimplemented");
53}
54
55
56void SkBlitter::blitAntiH(int x, int y, const SkAlpha antialias[],
57 const int16_t runs[]) {
58 SkDEBUGFAIL("unimplemented");
59}
60 */
61
63 SkAlpha alpha = (SkAlpha)(a * 255);
64 return alpha > 247 ? 0xFF : alpha < 8 ? 0 : alpha;
65}
66
68 SkIRect bounds = rect.roundOut();
69 SkASSERT(bounds.width() >= 3);
70
71 // skbug.com/7813
72 // To ensure consistency of the threaded backend (a rect that's considered fat in the init-once
73 // phase must also be considered fat in the draw phase), we have to deal with rects with small
74 // heights because the horizontal tiling in the threaded backend may change the height.
75 //
76 // This also implies that we cannot do vertical tiling unless we can blit any rect (not just the
77 // fat one.)
78 if (bounds.height() == 0) {
79 return;
80 }
81
82 int runSize = bounds.width() + 1; // +1 so we can set runs[bounds.width()] = 0
83 void* storage = this->allocBlitMemory(runSize * (sizeof(int16_t) + sizeof(SkAlpha)));
84 int16_t* runs = reinterpret_cast<int16_t*>(storage);
85 SkAlpha* alphas = reinterpret_cast<SkAlpha*>(runs + runSize);
86
87 runs[0] = 1;
88 runs[1] = bounds.width() - 2;
89 runs[bounds.width() - 1] = 1;
90 runs[bounds.width()] = 0;
91
92 SkScalar partialL = bounds.fLeft + 1 - rect.fLeft;
93 SkScalar partialR = rect.fRight - (bounds.fRight - 1);
94 SkScalar partialT = bounds.fTop + 1 - rect.fTop;
95 SkScalar partialB = rect.fBottom - (bounds.fBottom - 1);
96
97 if (bounds.height() == 1) {
98 partialT = rect.fBottom - rect.fTop;
99 }
100
101 alphas[0] = ScalarToAlpha(partialL * partialT);
102 alphas[1] = ScalarToAlpha(partialT);
103 alphas[bounds.width() - 1] = ScalarToAlpha(partialR * partialT);
104 this->blitAntiH(bounds.fLeft, bounds.fTop, alphas, runs);
105
106 if (bounds.height() > 2) {
107 this->blitAntiRect(bounds.fLeft, bounds.fTop + 1, bounds.width() - 2, bounds.height() - 2,
108 ScalarToAlpha(partialL), ScalarToAlpha(partialR));
109 }
110
111 if (bounds.height() > 1) {
112 alphas[0] = ScalarToAlpha(partialL * partialB);
113 alphas[1] = ScalarToAlpha(partialB);
114 alphas[bounds.width() - 1] = ScalarToAlpha(partialR * partialB);
115 this->blitAntiH(bounds.fLeft, bounds.fBottom - 1, alphas, runs);
116 }
117}
118
119void SkBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
120 if (alpha == 255) {
121 this->blitRect(x, y, 1, height);
122 } else {
123 int16_t runs[2];
124 runs[0] = 1;
125 runs[1] = 0;
126
127 while (--height >= 0) {
128 this->blitAntiH(x, y++, &alpha, runs);
129 }
130 }
131}
132
133void SkBlitter::blitRect(int x, int y, int width, int height) {
134 SkASSERT(width > 0);
135 while (--height >= 0) {
136 this->blitH(x, y++, width);
137 }
138}
139
140/// Default implementation doesn't check for easy optimizations
141/// such as alpha == 255; also uses blitV(), which some subclasses
142/// may not support.
143void SkBlitter::blitAntiRect(int x, int y, int width, int height,
144 SkAlpha leftAlpha, SkAlpha rightAlpha) {
145 if (leftAlpha > 0) { // we may send in x = -1 with leftAlpha = 0
146 this->blitV(x, y, height, leftAlpha);
147 }
148 x++;
149 if (width > 0) {
150 this->blitRect(x, y, width, height);
151 x += width;
152 }
153 if (rightAlpha > 0) {
154 this->blitV(x, y, height, rightAlpha);
155 }
156}
157
158//////////////////////////////////////////////////////////////////////////////
159
160static inline void bits_to_runs(SkBlitter* blitter, int x, int y,
161 const uint8_t bits[],
162 uint8_t left_mask, ptrdiff_t rowBytes,
163 uint8_t right_mask) {
164 int inFill = 0;
165 int pos = 0;
166
167 while (--rowBytes >= 0) {
168 uint8_t b = *bits++ & left_mask;
169 if (rowBytes == 0) {
170 b &= right_mask;
171 }
172
173 for (uint8_t test = 0x80U; test != 0; test >>= 1) {
174 if (b & test) {
175 if (!inFill) {
176 pos = x;
177 inFill = true;
178 }
179 } else {
180 if (inFill) {
181 blitter->blitH(pos, y, x - pos);
182 inFill = false;
183 }
184 }
185 x += 1;
186 }
187 left_mask = 0xFFU;
188 }
189
190 // final cleanup
191 if (inFill) {
192 blitter->blitH(pos, y, x - pos);
193 }
194}
195
196// maskBitCount is the number of 1's to place in the mask. It must be in the range between 1 and 8.
197static uint8_t generate_right_mask(int maskBitCount) {
198 return static_cast<uint8_t>((0xFF00U >> maskBitCount) & 0xFF);
199}
200
201void SkBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
203
204 if (mask.fFormat == SkMask::kLCD16_Format) {
205 return; // needs to be handled by subclass
206 }
207
208 if (mask.fFormat == SkMask::kBW_Format) {
209 int cx = clip.fLeft;
210 int cy = clip.fTop;
211 int maskLeft = mask.fBounds.fLeft;
212 int maskRowBytes = mask.fRowBytes;
213 int height = clip.height();
214
215 const uint8_t* bits = mask.getAddr1(cx, cy);
216
217 SkDEBUGCODE(const uint8_t* endOfImage =
218 mask.fImage + (mask.fBounds.height() - 1) * maskRowBytes
219 + ((mask.fBounds.width() + 7) >> 3));
220
221 if (cx == maskLeft && clip.fRight == mask.fBounds.fRight) {
222 while (--height >= 0) {
223 int affectedRightBit = mask.fBounds.width() - 1;
224 ptrdiff_t rowBytes = (affectedRightBit >> 3) + 1;
225 SkASSERT(bits + rowBytes <= endOfImage);
226 U8CPU rightMask = generate_right_mask((affectedRightBit & 7) + 1);
227 bits_to_runs(this, cx, cy, bits, 0xFF, rowBytes, rightMask);
228 bits += maskRowBytes;
229 cy += 1;
230 }
231 } else {
232 // Bits is calculated as the offset into the mask at the point {cx, cy} therefore, all
233 // addressing into the bit mask is relative to that point. Since this is an address
234 // calculated from a arbitrary bit in that byte, calculate the left most bit.
235 int bitsLeft = cx - ((cx - maskLeft) & 7);
236
237 // Everything is relative to the bitsLeft.
238 int leftEdge = cx - bitsLeft;
239 SkASSERT(leftEdge >= 0);
240 int rightEdge = clip.fRight - bitsLeft;
241 SkASSERT(rightEdge > leftEdge);
242
243 // Calculate left byte and mask
244 const uint8_t* leftByte = bits;
245 U8CPU leftMask = 0xFFU >> (leftEdge & 7);
246
247 // Calculate right byte and mask
248 int affectedRightBit = rightEdge - 1;
249 const uint8_t* rightByte = bits + (affectedRightBit >> 3);
250 U8CPU rightMask = generate_right_mask((affectedRightBit & 7) + 1);
251
252 // leftByte and rightByte are byte locations therefore, to get a count of bytes the
253 // code must add one.
254 ptrdiff_t rowBytes = rightByte - leftByte + 1;
255
256 while (--height >= 0) {
257 SkASSERT(bits + rowBytes <= endOfImage);
258 bits_to_runs(this, bitsLeft, cy, bits, leftMask, rowBytes, rightMask);
259 bits += maskRowBytes;
260 cy += 1;
261 }
262 }
263 } else {
264 int width = clip.width();
265 AutoSTMalloc<64, int16_t> runStorage(width + 1);
266 int16_t* runs = runStorage.get();
267 const uint8_t* aa = mask.getAddr8(clip.fLeft, clip.fTop);
268
269 SkOpts::memset16((uint16_t*)runs, 1, width);
270 runs[width] = 0;
271
272 int height = clip.height();
273 int y = clip.fTop;
274 while (--height >= 0) {
275 this->blitAntiH(clip.fLeft, y, aa, runs);
276 aa += mask.fRowBytes;
277 y += 1;
278 }
279 }
280}
281
282/////////////////////// these are not virtual, just helpers
283
284#if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
285void SkBlitter::blitMaskRegion(const SkMask& mask, const SkRegion& clip) {
286 if (clip.quickReject(mask.fBounds)) {
287 return;
288 }
289
290 SkRegion::Cliperator clipper(clip, mask.fBounds);
291
292 while (!clipper.done()) {
293 const SkIRect& cr = clipper.rect();
294 this->blitMask(mask, cr);
295 clipper.next();
296 }
297}
298#endif
299
301 SkRegion::Cliperator clipper(clip, rect);
302
303 while (!clipper.done()) {
304 const SkIRect& cr = clipper.rect();
305 this->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
306 clipper.next();
307 }
308}
309
311 SkRegionPriv::VisitSpans(clip, [this](const SkIRect& r) {
312 this->blitRect(r.left(), r.top(), r.width(), r.height());
313 });
314}
315
316///////////////////////////////////////////////////////////////////////////////
317
318void SkNullBlitter::blitH(int x, int y, int width) {}
319
320void SkNullBlitter::blitAntiH(int x, int y, const SkAlpha antialias[],
321 const int16_t runs[]) {}
322
323void SkNullBlitter::blitV(int x, int y, int height, SkAlpha alpha) {}
324
325void SkNullBlitter::blitRect(int x, int y, int width, int height) {}
326
327void SkNullBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {}
328
329bool SkNullBlitter::isNullBlitter() const { return true; }
330
331///////////////////////////////////////////////////////////////////////////////
332
333static int compute_anti_width(const int16_t runs[]) {
334 int width = 0;
335
336 for (;;) {
337 int count = runs[0];
338
339 SkASSERT(count >= 0);
340 if (count == 0) {
341 break;
342 }
343 width += count;
344 runs += count;
345 }
346 return width;
347}
348
349static inline bool y_in_rect(int y, const SkIRect& rect) {
350 return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
351}
352
353static inline bool x_in_rect(int x, const SkIRect& rect) {
354 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
355}
356
358 SkASSERT(width > 0);
359
360 if (!y_in_rect(y, fClipRect)) {
361 return;
362 }
363
364 int right = left + width;
365
366 if (left < fClipRect.fLeft) {
367 left = fClipRect.fLeft;
368 }
369 if (right > fClipRect.fRight) {
370 right = fClipRect.fRight;
371 }
372
373 width = right - left;
374 if (width > 0) {
375 fBlitter->blitH(left, y, width);
376 }
377}
378
379void SkRectClipBlitter::blitAntiH(int left, int y, const SkAlpha const_aa[],
380 const int16_t const_runs[]) {
381 SkAlpha* aa = const_cast<SkAlpha*>(const_aa);
382 int16_t* runs = const_cast<int16_t*>(const_runs);
383
384 if (!y_in_rect(y, fClipRect) || left >= fClipRect.fRight) {
385 return;
386 }
387
388 int x0 = left;
389 int x1 = left + compute_anti_width(runs);
390
391 if (x1 <= fClipRect.fLeft) {
392 return;
393 }
394
395 SkASSERT(x0 < x1);
396 if (x0 < fClipRect.fLeft) {
397 int dx = fClipRect.fLeft - x0;
398 SkAlphaRuns::BreakAt((int16_t*)runs, (uint8_t*)aa, dx);
399 runs += dx;
400 aa += dx;
401 x0 = fClipRect.fLeft;
402 }
403
404 SkASSERT(x0 < x1 && runs[x1 - x0] == 0);
405 if (x1 > fClipRect.fRight) {
406 x1 = fClipRect.fRight;
407 SkAlphaRuns::BreakAt((int16_t*)runs, (uint8_t*)aa, x1 - x0);
408 ((int16_t*)runs)[x1 - x0] = 0;
409 }
410
411 SkASSERT(x0 < x1 && runs[x1 - x0] == 0);
412 SkASSERT(compute_anti_width(runs) == x1 - x0);
413
414 fBlitter->blitAntiH(x0, y, aa, runs);
415}
416
417void SkRectClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
418 SkASSERT(height > 0);
419
420 if (!x_in_rect(x, fClipRect)) {
421 return;
422 }
423
424 int y0 = y;
425 int y1 = y + height;
426
427 if (y0 < fClipRect.fTop) {
428 y0 = fClipRect.fTop;
429 }
430 if (y1 > fClipRect.fBottom) {
431 y1 = fClipRect.fBottom;
432 }
433
434 if (y0 < y1) {
435 fBlitter->blitV(x, y0, y1 - y0, alpha);
436 }
437}
438
440 SkIRect r;
441
442 r.setLTRB(left, y, left + width, y + height);
443 if (r.intersect(fClipRect)) {
444 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
445 }
446}
447
449 SkAlpha leftAlpha, SkAlpha rightAlpha) {
450 SkIRect r;
451
452 // The *true* width of the rectangle blitted is width+2:
453 r.setLTRB(left, y, left + width + 2, y + height);
454 if (r.intersect(fClipRect)) {
455 if (r.fLeft != left) {
456 SkASSERT(r.fLeft > left);
457 leftAlpha = 255;
458 }
459 if (r.fRight != left + width + 2) {
460 SkASSERT(r.fRight < left + width + 2);
461 rightAlpha = 255;
462 }
463 if (255 == leftAlpha && 255 == rightAlpha) {
464 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
465 } else if (1 == r.width()) {
466 if (r.fLeft == left) {
467 fBlitter->blitV(r.fLeft, r.fTop, r.height(), leftAlpha);
468 } else {
469 SkASSERT(r.fLeft == left + width + 1);
470 fBlitter->blitV(r.fLeft, r.fTop, r.height(), rightAlpha);
471 }
472 } else {
473 fBlitter->blitAntiRect(r.fLeft, r.fTop, r.width() - 2, r.height(),
474 leftAlpha, rightAlpha);
475 }
476 }
477}
478
481
482 SkIRect r = clip;
483
484 if (r.intersect(fClipRect)) {
485 fBlitter->blitMask(mask, r);
486 }
487}
488
489///////////////////////////////////////////////////////////////////////////////
490
491void SkRgnClipBlitter::blitH(int x, int y, int width) {
492 SkRegion::Spanerator span(*fRgn, y, x, x + width);
493 int left, right;
494
495 while (span.next(&left, &right)) {
497 fBlitter->blitH(left, y, right - left);
498 }
499}
500
501void SkRgnClipBlitter::blitAntiH(int x, int y, const SkAlpha const_aa[],
502 const int16_t const_runs[]) {
503 SkAlpha* aa = const_cast<SkAlpha*>(const_aa);
504 int16_t* runs = const_cast<int16_t*>(const_runs);
505
506 int width = compute_anti_width(runs);
507 SkRegion::Spanerator span(*fRgn, y, x, x + width);
508 int left, right;
509 SkDEBUGCODE(const SkIRect& bounds = fRgn->getBounds();)
510
511 int prevRite = x;
512 while (span.next(&left, &right)) {
513 SkASSERT(x <= left);
515 SkASSERT(left >= bounds.fLeft && right <= bounds.fRight);
516
517 SkAlphaRuns::Break((int16_t*)runs, (uint8_t*)aa, left - x, right - left);
518
519 // now zero before left
520 if (left > prevRite) {
521 int index = prevRite - x;
522 ((uint8_t*)aa)[index] = 0; // skip runs after right
523 ((int16_t*)runs)[index] = SkToS16(left - prevRite);
524 }
525
526 prevRite = right;
527 }
528
529 if (prevRite > x) {
530 ((int16_t*)runs)[prevRite - x] = 0;
531
532 if (x < 0) {
533 int skip = runs[0];
534 SkASSERT(skip >= -x);
535 aa += skip;
536 runs += skip;
537 x += skip;
538 }
539 fBlitter->blitAntiH(x, y, aa, runs);
540 }
541}
542
543void SkRgnClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
544 SkIRect bounds;
545 bounds.setXYWH(x, y, 1, height);
546
547 SkRegion::Cliperator iter(*fRgn, bounds);
548
549 while (!iter.done()) {
550 const SkIRect& r = iter.rect();
551 SkASSERT(bounds.contains(r));
552
553 fBlitter->blitV(x, r.fTop, r.height(), alpha);
554 iter.next();
555 }
556}
557
558void SkRgnClipBlitter::blitRect(int x, int y, int width, int height) {
559 SkIRect bounds;
560 bounds.setXYWH(x, y, width, height);
561
562 SkRegion::Cliperator iter(*fRgn, bounds);
563
564 while (!iter.done()) {
565 const SkIRect& r = iter.rect();
566 SkASSERT(bounds.contains(r));
567
568 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
569 iter.next();
570 }
571}
572
574 SkAlpha leftAlpha, SkAlpha rightAlpha) {
575 // The *true* width of the rectangle to blit is width + 2
576 SkIRect bounds;
577 bounds.setXYWH(x, y, width + 2, height);
578
579 SkRegion::Cliperator iter(*fRgn, bounds);
580
581 while (!iter.done()) {
582 const SkIRect& r = iter.rect();
583 SkASSERT(bounds.contains(r));
584 SkASSERT(r.fLeft >= x);
585 SkASSERT(r.fRight <= x + width + 2);
586
587 SkAlpha effectiveLeftAlpha = (r.fLeft == x) ? leftAlpha : 255;
588 SkAlpha effectiveRightAlpha = (r.fRight == x + width + 2) ?
589 rightAlpha : 255;
590
591 if (255 == effectiveLeftAlpha && 255 == effectiveRightAlpha) {
592 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
593 } else if (1 == r.width()) {
594 if (r.fLeft == x) {
595 fBlitter->blitV(r.fLeft, r.fTop, r.height(),
596 effectiveLeftAlpha);
597 } else {
598 SkASSERT(r.fLeft == x + width + 1);
599 fBlitter->blitV(r.fLeft, r.fTop, r.height(),
600 effectiveRightAlpha);
601 }
602 } else {
603 fBlitter->blitAntiRect(r.fLeft, r.fTop, r.width() - 2, r.height(),
604 effectiveLeftAlpha, effectiveRightAlpha);
605 }
606 iter.next();
607 }
608}
609
610
613
614 SkRegion::Cliperator iter(*fRgn, clip);
615 const SkIRect& r = iter.rect();
616 SkBlitter* blitter = fBlitter;
617
618 while (!iter.done()) {
619 blitter->blitMask(mask, r);
620 iter.next();
621 }
622}
623
624///////////////////////////////////////////////////////////////////////////////
625
627 const SkIRect* ir) {
628 if (clip) {
629 const SkIRect& clipR = clip->getBounds();
630
631 if (clip->isEmpty() || (ir && !SkIRect::Intersects(clipR, *ir))) {
632 blitter = &fNullBlitter;
633 } else if (clip->isRect()) {
634 if (ir == nullptr || !clipR.contains(*ir)) {
635 fRectBlitter.init(blitter, clipR);
636 blitter = &fRectBlitter;
637 }
638 } else {
639 fRgnBlitter.init(blitter, clip);
640 blitter = &fRgnBlitter;
641 }
642 }
643 return blitter;
644}
645
646///////////////////////////////////////////////////////////////////////////////
647
649 const SkPaint& paint,
650 const SkMatrix& matrix) {
652 return false;
653 }
654#if defined(SK_FORCE_RASTER_PIPELINE_BLITTER)
655 return false;
656#else
657
658 if (paint.isDither()) {
659 return false;
660 }
661
662 const SkMaskFilterBase* mf = as_MFB(paint.getMaskFilter());
663
664 // The legacy blitters cannot handle any of these "complex" features (anymore).
665 if (device.alphaType() == kUnpremul_SkAlphaType ||
666 !paint.isSrcOver() ||
667 (mf && mf->getFormat() == SkMask::k3D_Format)) {
668 return false;
669 }
670
671 auto cs = device.colorSpace();
672 // We check (indirectly via makeContext()) later on if the shader can handle the colorspace
673 // in legacy mode, so here we just focus on if a single color needs raster-pipeline.
674 if (cs && !paint.getShader()) {
675 if (!paint.getColor4f().fitsInBytes() || !cs->isSRGB()) {
676 return false;
677 }
678 }
679
680 // Only kN32 is handled by legacy blitters now
681 return device.colorType() == kN32_SkColorType;
682#endif
683}
684
686 const SkMatrix& ctm,
687 const SkPaint& origPaint,
688 SkArenaAlloc* alloc,
689 bool drawCoverage,
690 sk_sp<SkShader> clipShader,
691 const SkSurfaceProps& props) {
692 SkASSERT(alloc);
693
694 if (kUnknown_SkColorType == device.colorType()) {
695 return alloc->make<SkNullBlitter>();
696 }
697
698 // We may tweak the original paint as we go.
700
701 if (auto mode = paint->asBlendMode()) {
702 // We have the most fast-paths for SrcOver, so see if we can act like SrcOver.
703 if (mode.value() != SkBlendMode::kSrcOver) {
704 switch (CheckFastPath(*paint, SkColorTypeIsAlwaysOpaque(device.colorType()))) {
706 paint.writable()->setBlendMode(SkBlendMode::kSrcOver);
707 break;
709 return alloc->make<SkNullBlitter>();
710 default:
711 break;
712 }
713 }
714
715 // A Clear blend mode will ignore the entire color pipeline, as if Src mode with 0x00000000.
716 if (mode.value() == SkBlendMode::kClear) {
717 SkPaint* p = paint.writable();
718 p->setShader(nullptr);
719 p->setColorFilter(nullptr);
720 p->setBlendMode(SkBlendMode::kSrc);
721 p->setColor(0x00000000);
722 }
723 }
724
725 if (paint->getColorFilter()) {
726 SkPaintPriv::RemoveColorFilter(paint.writable(), device.colorSpace());
727 }
728 SkASSERT(!paint->getColorFilter());
729
730 if (drawCoverage) {
731 if (device.colorType() == kAlpha_8_SkColorType) {
732 SkASSERT(!paint->getShader());
733 SkASSERT(paint->isSrcOver());
734 return alloc->make<SkA8_Coverage_Blitter>(device, *paint);
735 }
736 return alloc->make<SkNullBlitter>();
737 }
738
739 if (paint->isDither() && !SkPaintPriv::ShouldDither(*paint, device.colorType())) {
740 paint.writable()->setDither(false);
741 }
742
743 auto CreateSkRPBlitter = [&]() -> SkBlitter* {
744 auto blitter = SkCreateRasterPipelineBlitter(device, *paint, ctm, alloc, clipShader, props);
745 return blitter ? blitter
746 : alloc->make<SkNullBlitter>();
747 };
748
749 // We'll end here for many interesting cases: color spaces, color filters, most color types.
750 if (clipShader || !UseLegacyBlitter(device, *paint, ctm)) {
751 return CreateSkRPBlitter();
752 }
753
754 // Everything but legacy kN32_SkColorType should already be handled.
755 SkASSERT(device.colorType() == kN32_SkColorType);
756
757 // And we should be blending with SrcOver
758 SkASSERT(paint->asBlendMode() == SkBlendMode::kSrcOver);
759
760 // Legacy blitters keep their shader state on a shader context.
761 SkShaderBase::Context* shaderContext = nullptr;
762 if (paint->getShader()) {
763 shaderContext = as_SB(paint->getShader())
764 ->makeContext({paint->getAlpha(),
766 device.colorType(),
767 device.colorSpace(),
768 props},
769 alloc);
770
771 // Creating the context isn't always possible... try fallbacks before giving up.
772 if (!shaderContext) {
773 return CreateSkRPBlitter();
774 }
775 }
776
777 if (shaderContext) {
778 return alloc->make<SkARGB32_Shader_Blitter>(device, *paint, shaderContext);
779 } else if (paint->getColor() == SK_ColorBLACK) {
780 return alloc->make<SkARGB32_Black_Blitter>(device, *paint);
781 } else if (paint->getAlpha() == 0xFF) {
782 return alloc->make<SkARGB32_Opaque_Blitter>(device, *paint);
783 } else {
784 return alloc->make<SkARGB32_Blitter>(device, *paint);
785 }
786}
787
788///////////////////////////////////////////////////////////////////////////////
789
791 SkShaderBase::Context* shaderContext)
793 , fShader(paint.refShader())
794 , fShaderContext(shaderContext) {
797}
798
800
801///////////////////////////////////////////////////////////////////////////////////////////////////
802
803#ifdef SK_DEBUG
804
805void SkRectClipCheckBlitter::blitH(int x, int y, int width) {
806 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, width, 1)));
807 fBlitter->blitH(x, y, width);
808}
809
810void SkRectClipCheckBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
811 const int16_t* iter = runs;
812 for (; *iter; iter += *iter)
813 ;
814 int width = iter - runs;
815 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, width, 1)));
816 fBlitter->blitAntiH(x, y, aa, runs);
817}
818
819void SkRectClipCheckBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
820 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, 1, height)));
821 fBlitter->blitV(x, y, height, alpha);
822}
823
824void SkRectClipCheckBlitter::blitRect(int x, int y, int width, int height) {
825 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, width, height)));
826 fBlitter->blitRect(x, y, width, height);
827}
828
829void SkRectClipCheckBlitter::blitAntiRect(int x, int y, int width, int height,
830 SkAlpha leftAlpha, SkAlpha rightAlpha) {
831 bool skipLeft = !leftAlpha;
832 bool skipRight = !rightAlpha;
833 SkIRect r = SkIRect::MakeXYWH(x + skipLeft, y, width + 2 - skipRight - skipLeft, height);
834 SkASSERT(r.isEmpty() || fClipRect.contains(r));
835 fBlitter->blitAntiRect(x, y, width, height, leftAlpha, rightAlpha);
836}
837
838void SkRectClipCheckBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
840 SkASSERT(fClipRect.contains(clip));
841 fBlitter->blitMask(mask, clip);
842}
843
844void SkRectClipCheckBlitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) {
845 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, 2, 1)));
846 fBlitter->blitAntiH2(x, y, a0, a1);
847}
848
849void SkRectClipCheckBlitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {
850 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, 1, 2)));
851 fBlitter->blitAntiV2(x, y, a0, a1);
852}
853
854#endif
int count
SkPoint pos
kUnpremul_SkAlphaType
#define SkASSERT(cond)
Definition SkAssert.h:116
SkBlendFastPath CheckFastPath(const SkPaint &paint, bool dstIsOpaque)
@ kSrcOver
r = s + (1-sa)*d
@ kClear
r = 0
static int compute_anti_width(const int16_t runs[])
static void bits_to_runs(SkBlitter *blitter, int x, int y, const uint8_t bits[], uint8_t left_mask, ptrdiff_t rowBytes, uint8_t right_mask)
static bool x_in_rect(int x, const SkIRect &rect)
static bool y_in_rect(int y, const SkIRect &rect)
static uint8_t generate_right_mask(int maskBitCount)
bool gSkForceRasterPipelineBlitter
Definition SkBlitter.cpp:44
static SkAlpha ScalarToAlpha(SkScalar a)
Definition SkBlitter.cpp:62
unsigned U8CPU
Definition SkCPUTypes.h:18
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition SkColorType.h:21
@ kUnknown_SkColorType
uninitialized
Definition SkColorType.h:20
uint8_t SkAlpha
Definition SkColor.h:26
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
SkBlitter * SkCreateRasterPipelineBlitter(const SkPixmap &, const SkPaint &, const SkMatrix &ctm, SkArenaAlloc *, sk_sp< SkShader > clipShader, const SkSurfaceProps &props)
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static bool skip(SkStream *stream, size_t amount)
SK_API bool SkColorTypeIsAlwaysOpaque(SkColorType ct)
SkMaskFilterBase * as_MFB(SkMaskFilter *mf)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
SkShaderBase * as_SB(SkShader *shader)
constexpr int16_t SkToS16(S x)
Definition SkTo.h:23
static void Break(int16_t runs[], uint8_t alpha[], int x, int count)
static void BreakAt(int16_t runs[], uint8_t alpha[], int x)
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
SkBlitter * apply(SkBlitter *blitter, const SkRegion *clip, const SkIRect *bounds=nullptr)
void blitFatAntiRect(const SkRect &rect)
Definition SkBlitter.cpp:67
static SkBlitter * Choose(const SkPixmap &dst, const SkMatrix &ctm, const SkPaint &paint, SkArenaAlloc *, bool drawCoverage, sk_sp< SkShader > clipShader, const SkSurfaceProps &props)
virtual bool isNullBlitter() const
Definition SkBlitter.cpp:48
static bool UseLegacyBlitter(const SkPixmap &, const SkPaint &, const SkMatrix &)
void blitRectRegion(const SkIRect &rect, const SkRegion &clip)
virtual void blitMask(const SkMask &, const SkIRect &clip)
virtual void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha)
virtual void * allocBlitMemory(size_t sz)
Definition SkBlitter.h:129
void blitRegion(const SkRegion &clip)
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])=0
virtual ~SkBlitter()
Definition SkBlitter.cpp:46
virtual void blitH(int x, int y, int width)=0
Blit a horizontal run of one or more pixels.
virtual void blitV(int x, int y, int height, SkAlpha alpha)
Blit a vertical run of pixels with a constant alpha value.
virtual void blitRect(int x, int y, int width, int height)
Blit a solid rectangle one or more pixels wide.
virtual SkMask::Format getFormat() const =0
void blitMask(const SkMask &, const SkIRect &clip) override
void blitV(int x, int y, int height, SkAlpha alpha) override
Blit a vertical run of pixels with a constant alpha value.
void blitRect(int x, int y, int width, int height) override
Blit a solid rectangle one or more pixels wide.
bool isNullBlitter() const override
void blitH(int x, int y, int width) override
Blit a horizontal run of one or more pixels.
void blitAntiH(int x, int y, const SkAlpha[], const int16_t runs[]) override
static void RemoveColorFilter(SkPaint *, SkColorSpace *dstCS)
static bool ShouldDither(const SkPaint &, SkColorType)
bool isEmpty() const
Definition SkPath.cpp:406
const SkRect & getBounds() const
Definition SkPath.cpp:420
bool isRect(SkRect *rect, bool *isClosed=nullptr, SkPathDirection *direction=nullptr) const
Definition SkPath.cpp:506
void blitAntiH(int x, int y, const SkAlpha[], const int16_t runs[]) override
void blitH(int x, int y, int width) override
Blit a horizontal run of one or more pixels.
void blitV(int x, int y, int height, SkAlpha alpha) override
Blit a vertical run of pixels with a constant alpha value.
void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha) override
void blitMask(const SkMask &, const SkIRect &clip) override
void init(SkBlitter *blitter, const SkIRect &clipRect)
Definition SkBlitter.h:183
void blitRect(int x, int y, int width, int height) override
Blit a solid rectangle one or more pixels wide.
static void VisitSpans(const SkRegion &rgn, const std::function< void(const SkIRect &)> &)
const SkIRect & rect() const
Definition SkRegion.h:551
bool next(int *left, int *right)
const SkIRect & getBounds() const
Definition SkRegion.h:165
void blitMask(const SkMask &, const SkIRect &clip) override
void blitAntiH(int x, int y, const SkAlpha[], const int16_t runs[]) override
void init(SkBlitter *blitter, const SkRegion *clipRgn)
Definition SkBlitter.h:216
void blitRect(int x, int y, int width, int height) override
Blit a solid rectangle one or more pixels wide.
void blitV(int x, int y, int height, SkAlpha alpha) override
Blit a vertical run of pixels with a constant alpha value.
void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha) override
void blitH(int x, int y, int width) override
Blit a horizontal run of one or more pixels.
Context * makeContext(const ContextRec &, SkArenaAlloc *) const
SkShaderBase::Context * fShaderContext
~SkShaderBlitter() override
sk_sp< SkShader > fShader
SkShaderBlitter(const SkPixmap &device, const SkPaint &paint, SkShaderBase::Context *shaderContext)
const Paint & paint
VkDevice device
Definition main.cc:53
float SkScalar
Definition extension.cpp:12
static bool b
struct MyStruct a[10]
double y
double x
void(* memset16)(uint16_t[], uint16_t, int)
bool gSkForceRasterPipelineBlitter
Definition SkBlitter.cpp:44
int32_t height
int32_t width
bool intersect(const SkIRect &r)
Definition SkRect.h:513
static bool Intersects(const SkIRect &a, const SkIRect &b)
Definition SkRect.h:535
int32_t fBottom
larger y-axis bounds
Definition SkRect.h:36
constexpr int32_t top() const
Definition SkRect.h:120
constexpr int32_t height() const
Definition SkRect.h:165
int32_t fTop
smaller y-axis bounds
Definition SkRect.h:34
constexpr int32_t width() const
Definition SkRect.h:158
bool isEmpty() const
Definition SkRect.h:202
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
int32_t fLeft
smaller x-axis bounds
Definition SkRect.h:33
constexpr int32_t left() const
Definition SkRect.h:113
void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom)
Definition SkRect.h:253
bool contains(int32_t x, int32_t y) const
Definition SkRect.h:463
int32_t fRight
larger x-axis bounds
Definition SkRect.h:35
const uint32_t fRowBytes
Definition SkMask.h:43
@ k3D_Format
3 8bit per pixl planes: alpha, mul, add
Definition SkMask.h:29
@ kLCD16_Format
565 alpha for r/g/b
Definition SkMask.h:31
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
Definition SkMask.h:27
const uint8_t * getAddr8(int x, int y) const
Definition SkMask.h:79
const uint8_t * getAddr1(int x, int y) const
Definition SkMask.h:68
uint8_t const *const fImage
Definition SkMask.h:41
const SkIRect fBounds
Definition SkMask.h:42
const Format fFormat
Definition SkMask.h:44