Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/core/SkRasterPipelineBlitter.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2016 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 "include/core/SkColor.h"
9
#include "include/core/SkPaint.h"
10
#include "include/core/SkShader.h"
11
#include "include/private/SkTo.h"
12
#include "src/core/SkArenaAlloc.h"
13
#include "src/core/SkBlendModePriv.h"
14
#include "src/core/SkBlitter.h"
15
#include "src/core/SkColorFilterBase.h"
16
#include "src/core/SkColorSpacePriv.h"
17
#include "src/core/SkColorSpaceXformSteps.h"
18
#include "src/core/SkMatrixProvider.h"
19
#include "src/core/SkOpts.h"
20
#include "src/core/SkRasterPipeline.h"
21
#include "src/core/SkUtils.h"
22
#include "src/shaders/SkShaderBase.h"
23
24
class SkRasterPipelineBlitter final : public SkBlitter {
25
public:
26
    // This is our common entrypoint for creating the blitter once we've sorted out shaders.
27
    static SkBlitter* Create(const SkPixmap&, const SkPaint&, SkArenaAlloc*,
28
                             const SkRasterPipeline& shaderPipeline,
29
                             bool is_opaque, bool is_constant,
30
                             sk_sp<SkShader> clipShader);
31
32
    SkRasterPipelineBlitter(SkPixmap dst,
33
                            SkBlendMode blend,
34
                            SkArenaAlloc* alloc)
35
        : fDst(dst)
36
        , fBlend(blend)
37
        , fAlloc(alloc)
38
        , fColorPipeline(alloc)
39
502k
    {}
40
41
    void blitH     (int x, int y, int w)                            override;
42
    void blitAntiH (int x, int y, const SkAlpha[], const int16_t[]) override;
43
    void blitAntiH2(int x, int y, U8CPU a0, U8CPU a1)               override;
44
    void blitAntiV2(int x, int y, U8CPU a0, U8CPU a1)               override;
45
    void blitMask  (const SkMask&, const SkIRect& clip)             override;
46
    void blitRect  (int x, int y, int width, int height)            override;
47
    void blitV     (int x, int y, int height, SkAlpha alpha)        override;
48
49
private:
50
    void append_load_dst      (SkRasterPipeline*) const;
51
    void append_store         (SkRasterPipeline*) const;
52
53
    // these check internally, and only append if there was a native clipShader
54
    void append_clip_scale    (SkRasterPipeline*) const;
55
    void append_clip_lerp     (SkRasterPipeline*) const;
56
57
    SkPixmap               fDst;
58
    SkBlendMode            fBlend;
59
    SkArenaAlloc*          fAlloc;
60
    SkRasterPipeline       fColorPipeline;
61
    // set to pipeline storage (for alpha) if we have a clipShader
62
    void*                  fClipShaderBuffer = nullptr; // "native" : float or U16
63
64
    SkRasterPipeline_MemoryCtx
65
        fDstPtr       = {nullptr,0},  // Always points to the top-left of fDst.
66
        fMaskPtr      = {nullptr,0};  // Updated each call to blitMask().
67
    SkRasterPipeline_EmbossCtx fEmbossCtx;  // Used only for k3D_Format masks.
68
69
    // We may be able to specialize blitH() or blitRect() into a memset.
70
    void   (*fMemset2D)(SkPixmap*, int x,int y, int w,int h, uint64_t color) = nullptr;
71
    uint64_t fMemsetColor = 0;   // Big enough for largest memsettable dst format, F16.
72
73
    // Built lazily on first use.
74
    std::function<void(size_t, size_t, size_t, size_t)> fBlitRect,
75
                                                        fBlitAntiH,
76
                                                        fBlitMaskA8,
77
                                                        fBlitMaskLCD16,
78
                                                        fBlitMask3D;
79
80
    // These values are pointed to by the blit pipelines above,
81
    // which allows us to adjust them from call to call.
82
    float fCurrentCoverage = 0.0f;
83
    float fDitherRate      = 0.0f;
84
85
    using INHERITED = SkBlitter;
86
};
87
88
SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
89
                                         const SkPaint& paint,
90
                                         const SkMatrixProvider& matrixProvider,
91
                                         SkArenaAlloc* alloc,
92
681k
                                         sk_sp<SkShader> clipShader) {
93
681k
    if (!paint.asBlendMode()) {
94
        // The raster pipeline doesn't support SkBlender.
95
0
        return nullptr;
96
0
    }
97
98
681k
    SkColorSpace* dstCS = dst.colorSpace();
99
681k
    SkColorType dstCT = dst.colorType();
100
681k
    SkColor4f paintColor = paint.getColor4f();
101
681k
    SkColorSpaceXformSteps(sk_srgb_singleton(), kUnpremul_SkAlphaType,
102
681k
                           dstCS,               kUnpremul_SkAlphaType).apply(paintColor.vec());
103
104
681k
    auto shader = as_SB(paint.getShader());
105
106
681k
    SkRasterPipeline_<256> shaderPipeline;
107
681k
    if (!shader) {
108
        // Having no shader makes things nice and easy... just use the paint color.
109
109k
        shaderPipeline.append_constant_color(alloc, paintColor.premul().vec());
110
109k
        bool is_opaque    = paintColor.fA == 1.0f,
111
109k
             is_constant  = true;
112
109k
        return SkRasterPipelineBlitter::Create(dst, paint, alloc,
113
109k
                                               shaderPipeline, is_opaque, is_constant,
114
109k
                                               std::move(clipShader));
115
109k
    }
116
117
572k
    bool is_opaque    = shader->isOpaque() && paintColor.fA == 1.0f;
118
572k
    bool is_constant  = shader->isConstant();
119
120
572k
    if (shader->appendStages(
121
376k
                {&shaderPipeline, alloc, dstCT, dstCS, paint, nullptr, matrixProvider})) {
122
376k
        if (paintColor.fA != 1.0f) {
123
335k
            shaderPipeline.append(SkRasterPipeline::scale_1_float,
124
335k
                                  alloc->make<float>(paintColor.fA));
125
335k
        }
126
376k
        return SkRasterPipelineBlitter::Create(dst, paint, alloc,
127
376k
                                               shaderPipeline, is_opaque, is_constant,
128
376k
                                               std::move(clipShader));
129
376k
    }
130
131
    // The shader can't draw with SkRasterPipeline.
132
195k
    return nullptr;
133
195k
}
134
135
SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
136
                                         const SkPaint& paint,
137
                                         const SkRasterPipeline& shaderPipeline,
138
                                         bool is_opaque,
139
                                         SkArenaAlloc* alloc,
140
16.0k
                                         sk_sp<SkShader> clipShader) {
141
16.0k
    bool is_constant = false;  // If this were the case, it'd be better to just set a paint color.
142
16.0k
    return SkRasterPipelineBlitter::Create(dst, paint, alloc,
143
16.0k
                                           shaderPipeline, is_opaque, is_constant,
144
16.0k
                                           clipShader);
145
16.0k
}
146
147
SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
148
                                           const SkPaint& paint,
149
                                           SkArenaAlloc* alloc,
150
                                           const SkRasterPipeline& shaderPipeline,
151
                                           bool is_opaque,
152
                                           bool is_constant,
153
502k
                                           sk_sp<SkShader> clipShader) {
154
502k
    const auto bm = paint.asBlendMode();
155
502k
    if (!bm) {
156
0
        return nullptr;
157
0
    }
158
159
502k
    auto blitter = alloc->make<SkRasterPipelineBlitter>(dst, bm.value(), alloc);
160
161
    // Our job in this factory is to fill out the blitter's color pipeline.
162
    // This is the common front of the full blit pipelines, each constructed lazily on first use.
163
    // The full blit pipelines handle reading and writing the dst, blending, coverage, dithering.
164
502k
    auto colorPipeline = &blitter->fColorPipeline;
165
166
502k
    if (clipShader) {
167
0
        auto clipP = colorPipeline;
168
0
        SkPaint clipPaint;  // just need default values
169
0
        SkColorType clipCT = kRGBA_8888_SkColorType;
170
0
        SkColorSpace* clipCS = nullptr;
171
0
        SkSimpleMatrixProvider clipMatrixProvider(SkMatrix::I());
172
0
        SkStageRec rec = {clipP, alloc, clipCT, clipCS, clipPaint, nullptr, clipMatrixProvider};
173
0
        if (as_SB(clipShader)->appendStages(rec)) {
174
0
            struct Storage {
175
                // large enough for highp (float) or lowp(U16)
176
0
                float   fA[SkRasterPipeline_kMaxStride];
177
0
            };
178
0
            auto storage = alloc->make<Storage>();
179
0
            clipP->append(SkRasterPipeline::store_src_a, storage->fA);
180
0
            blitter->fClipShaderBuffer = storage->fA;
181
0
            is_constant = false;
182
0
        } else {
183
0
            return nullptr;
184
0
        }
185
502k
    }
186
187
    // Let's get the shader in first.
188
502k
    colorPipeline->extend(shaderPipeline);
189
190
    // If there's a color filter it comes next.
191
502k
    if (auto colorFilter = paint.getColorFilter()) {
192
106k
        SkSimpleMatrixProvider matrixProvider(SkMatrix::I());
193
106k
        SkStageRec rec = {
194
106k
            colorPipeline, alloc, dst.colorType(), dst.colorSpace(), paint, nullptr, matrixProvider
195
106k
        };
196
106k
        if (!as_CFB(colorFilter)->appendStages(rec, is_opaque)) {
197
38.6k
            return nullptr;
198
38.6k
        }
199
68.0k
        is_opaque = is_opaque && as_CFB(colorFilter)->isAlphaUnchanged();
200
68.0k
    }
201
202
    // Not all formats make sense to dither (think, F16).  We set their dither rate
203
    // to zero.  We only dither non-constant shaders, so is_constant won't change here.
204
463k
    if (paint.isDither() && !is_constant) {
205
138k
        switch (dst.info().colorType()) {
206
0
            case kARGB_4444_SkColorType:    blitter->fDitherRate =   1/15.0f; break;
207
0
            case   kRGB_565_SkColorType:    blitter->fDitherRate =   1/63.0f; break;
208
0
            case    kGray_8_SkColorType:
209
0
            case  kRGB_888x_SkColorType:
210
204
            case kRGBA_8888_SkColorType:
211
138k
            case kBGRA_8888_SkColorType:    blitter->fDitherRate =  1/255.0f; break;
212
0
            case kRGB_101010x_SkColorType:
213
0
            case kRGBA_1010102_SkColorType:
214
0
            case kBGR_101010x_SkColorType:
215
0
            case kBGRA_1010102_SkColorType: blitter->fDitherRate = 1/1023.0f; break;
216
217
0
            case kUnknown_SkColorType:
218
19
            case kAlpha_8_SkColorType:
219
19
            case kRGBA_F16_SkColorType:
220
19
            case kRGBA_F16Norm_SkColorType:
221
19
            case kRGBA_F32_SkColorType:
222
19
            case kR8G8_unorm_SkColorType:
223
19
            case kA16_float_SkColorType:
224
19
            case kA16_unorm_SkColorType:
225
19
            case kR16G16_float_SkColorType:
226
19
            case kR16G16_unorm_SkColorType:
227
19
            case kR16G16B16A16_unorm_SkColorType: blitter->fDitherRate = 0.0f; break;
228
138k
        }
229
138k
        if (blitter->fDitherRate > 0.0f) {
230
138k
            colorPipeline->append(SkRasterPipeline::dither, &blitter->fDitherRate);
231
138k
        }
232
138k
    }
233
234
    // We're logically done here.  The code between here and return blitter is all optimization.
235
236
    // A pipeline that's still constant here can collapse back into a constant color.
237
463k
    if (is_constant) {
238
115k
        SkColor4f constantColor;
239
115k
        SkRasterPipeline_MemoryCtx constantColorPtr = { &constantColor, 0 };
240
115k
        colorPipeline->append_gamut_clamp_if_normalized(dst.info());
241
115k
        colorPipeline->append(SkRasterPipeline::store_f32, &constantColorPtr);
242
115k
        colorPipeline->run(0,0,1,1);
243
115k
        colorPipeline->reset();
244
115k
        colorPipeline->append_constant_color(alloc, constantColor);
245
246
115k
        is_opaque = constantColor.fA == 1.0f;
247
115k
    }
248
249
    // We can strength-reduce SrcOver into Src when opaque.
250
463k
    if (is_opaque && blitter->fBlend == SkBlendMode::kSrcOver) {
251
36.4k
        blitter->fBlend = SkBlendMode::kSrc;
252
36.4k
    }
253
254
    // When we're drawing a constant color in Src mode, we can sometimes just memset.
255
    // (The previous two optimizations help find more opportunities for this one.)
256
463k
    if (is_constant && blitter->fBlend == SkBlendMode::kSrc) {
257
        // Run our color pipeline all the way through to produce what we'd memset when we can.
258
        // Not all blits can memset, so we need to keep colorPipeline too.
259
104k
        SkRasterPipeline_<256> p;
260
104k
        p.extend(*colorPipeline);
261
104k
        p.append_gamut_clamp_if_normalized(dst.info());
262
104k
        blitter->fDstPtr = SkRasterPipeline_MemoryCtx{&blitter->fMemsetColor, 0};
263
104k
        blitter->append_store(&p);
264
104k
        p.run(0,0,1,1);
265
266
104k
        switch (blitter->fDst.shiftPerPixel()) {
267
3.45M
            case 0: blitter->fMemset2D = [](SkPixmap* dst, int x,int y, int w,int h, uint64_t c) {
268
3.45M
                void* p = dst->writable_addr(x,y);
269
8.91M
                while (h --> 0) {
270
5.46M
                    memset(p, c, w);
271
5.46M
                    p = SkTAddOffset<void>(p, dst->rowBytes());
272
5.46M
                }
273
3.45M
            }; break;
274
275
367
            case 1: blitter->fMemset2D = [](SkPixmap* dst, int x,int y, int w,int h, uint64_t c) {
276
367
                SkOpts::rect_memset16(dst->writable_addr16(x,y), c, w, dst->rowBytes(), h);
277
367
            }; break;
278
279
304k
            case 2: blitter->fMemset2D = [](SkPixmap* dst, int x,int y, int w,int h, uint64_t c) {
280
304k
                SkOpts::rect_memset32(dst->writable_addr32(x,y), c, w, dst->rowBytes(), h);
281
304k
            }; break;
282
283
179
            case 3: blitter->fMemset2D = [](SkPixmap* dst, int x,int y, int w,int h, uint64_t c) {
284
179
                SkOpts::rect_memset64(dst->writable_addr64(x,y), c, w, dst->rowBytes(), h);
285
179
            }; break;
286
287
            // TODO(F32)?
288
104k
        }
289
104k
    }
290
291
463k
    blitter->fDstPtr = SkRasterPipeline_MemoryCtx{
292
463k
        blitter->fDst.writable_addr(),
293
463k
        blitter->fDst.rowBytesAsPixels(),
294
463k
    };
295
296
463k
    return blitter;
297
463k
}
298
299
71.9k
void SkRasterPipelineBlitter::append_load_dst(SkRasterPipeline* p) const {
300
71.9k
    p->append_load_dst(fDst.info().colorType(), &fDstPtr);
301
71.9k
    if (fDst.info().alphaType() == kUnpremul_SkAlphaType) {
302
0
        p->append(SkRasterPipeline::premul_dst);
303
0
    }
304
71.9k
}
305
306
181k
void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p) const {
307
181k
    if (fDst.info().alphaType() == kUnpremul_SkAlphaType) {
308
0
        p->append(SkRasterPipeline::unpremul);
309
0
    }
310
181k
    p->append_store(fDst.info().colorType(), &fDstPtr);
311
181k
}
312
313
21.1k
void SkRasterPipelineBlitter::append_clip_scale(SkRasterPipeline* p) const {
314
21.1k
    if (fClipShaderBuffer) {
315
0
        p->append(SkRasterPipeline::scale_native, fClipShaderBuffer);
316
0
    }
317
21.1k
}
318
319
68.1k
void SkRasterPipelineBlitter::append_clip_lerp(SkRasterPipeline* p) const {
320
68.1k
    if (fClipShaderBuffer) {
321
0
        p->append(SkRasterPipeline::lerp_native, fClipShaderBuffer);
322
0
    }
323
68.1k
}
324
325
4.60M
void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
326
4.60M
    this->blitRect(x,y,w,1);
327
4.60M
}
328
329
4.70M
void SkRasterPipelineBlitter::blitRect(int x, int y, int w, int h) {
330
4.70M
    if (fMemset2D) {
331
3.76M
        fMemset2D(&fDst, x,y, w,h, fMemsetColor);
332
3.76M
        return;
333
3.76M
    }
334
335
942k
    if (!fBlitRect) {
336
48.3k
        SkRasterPipeline p(fAlloc);
337
48.3k
        p.extend(fColorPipeline);
338
48.3k
        p.append_gamut_clamp_if_normalized(fDst.info());
339
48.3k
        if (fBlend == SkBlendMode::kSrcOver
340
18.7k
                && (fDst.info().colorType() == kRGBA_8888_SkColorType ||
341
18.7k
                    fDst.info().colorType() == kBGRA_8888_SkColorType)
342
18.6k
                && !fDst.colorSpace()
343
18.6k
                && fDst.info().alphaType() != kUnpremul_SkAlphaType
344
18.6k
                && fDitherRate == 0.0f) {
345
17.3k
            if (fDst.info().colorType() == kBGRA_8888_SkColorType) {
346
17.3k
                p.append(SkRasterPipeline::swap_rb);
347
17.3k
            }
348
17.3k
            this->append_clip_scale(&p);
349
17.3k
            p.append(SkRasterPipeline::srcover_rgba_8888, &fDstPtr);
350
30.9k
        } else {
351
30.9k
            if (fBlend != SkBlendMode::kSrc) {
352
25.3k
                this->append_load_dst(&p);
353
25.3k
                SkBlendMode_AppendStages(fBlend, &p);
354
25.3k
                this->append_clip_lerp(&p);
355
5.64k
            } else if (fClipShaderBuffer) {
356
0
                this->append_load_dst(&p);
357
0
                this->append_clip_lerp(&p);
358
0
            }
359
30.9k
            this->append_store(&p);
360
30.9k
        }
361
48.3k
        fBlitRect = p.compile();
362
48.3k
    }
363
364
942k
    fBlitRect(x,y,w,h);
365
942k
}
366
367
2.47M
void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
368
2.47M
    if (!fBlitAntiH) {
369
22.4k
        SkRasterPipeline p(fAlloc);
370
22.4k
        p.extend(fColorPipeline);
371
22.4k
        p.append_gamut_clamp_if_normalized(fDst.info());
372
22.4k
        if (SkBlendMode_ShouldPreScaleCoverage(fBlend, /*rgb_coverage=*/false)) {
373
1.74k
            p.append(SkRasterPipeline::scale_1_float, &fCurrentCoverage);
374
1.74k
            this->append_clip_scale(&p);
375
1.74k
            this->append_load_dst(&p);
376
1.74k
            SkBlendMode_AppendStages(fBlend, &p);
377
20.6k
        } else {
378
20.6k
            this->append_load_dst(&p);
379
20.6k
            SkBlendMode_AppendStages(fBlend, &p);
380
20.6k
            p.append(SkRasterPipeline::lerp_1_float, &fCurrentCoverage);
381
20.6k
            this->append_clip_lerp(&p);
382
20.6k
        }
383
384
22.4k
        this->append_store(&p);
385
22.4k
        fBlitAntiH = p.compile();
386
22.4k
    }
387
388
12.0M
    for (int16_t run = *runs; run > 0; run = *runs) {
389
9.56M
        switch (*aa) {
390
1.53M
            case 0x00:                       break;
391
1.82M
            case 0xff: this->blitH(x,y,run); break;
392
6.20M
            default:
393
6.20M
                fCurrentCoverage = *aa * (1/255.0f);
394
6.20M
                fBlitAntiH(x,y,run,1);
395
9.56M
        }
396
9.56M
        x    += run;
397
9.56M
        runs += run;
398
9.56M
        aa   += run;
399
9.56M
    }
400
2.47M
}
401
402
365k
void SkRasterPipelineBlitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) {
403
365k
    SkIRect clip = {x,y, x+2,y+1};
404
365k
    uint8_t coverage[] = { (uint8_t)a0, (uint8_t)a1 };
405
406
365k
    SkMask mask;
407
365k
    mask.fImage    = coverage;
408
365k
    mask.fBounds   = clip;
409
365k
    mask.fRowBytes = 2;
410
365k
    mask.fFormat   = SkMask::kA8_Format;
411
412
365k
    this->blitMask(mask, clip);
413
365k
}
414
415
99.0k
void SkRasterPipelineBlitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {
416
99.0k
    SkIRect clip = {x,y, x+1,y+2};
417
99.0k
    uint8_t coverage[] = { (uint8_t)a0, (uint8_t)a1 };
418
419
99.0k
    SkMask mask;
420
99.0k
    mask.fImage    = coverage;
421
99.0k
    mask.fBounds   = clip;
422
99.0k
    mask.fRowBytes = 1;
423
99.0k
    mask.fFormat   = SkMask::kA8_Format;
424
425
99.0k
    this->blitMask(mask, clip);
426
99.0k
}
427
428
3.40M
void SkRasterPipelineBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
429
3.40M
    SkIRect clip = {x,y, x+1,y+height};
430
431
3.40M
    SkMask mask;
432
3.40M
    mask.fImage    = &alpha;
433
3.40M
    mask.fBounds   = clip;
434
3.40M
    mask.fRowBytes = 0;     // so we reuse the 1 "row" for all of height
435
3.40M
    mask.fFormat   = SkMask::kA8_Format;
436
437
3.40M
    this->blitMask(mask, clip);
438
3.40M
}
439
440
3.89M
void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
441
3.89M
    if (mask.fFormat == SkMask::kBW_Format) {
442
        // TODO: native BW masks?
443
2.19k
        return INHERITED::blitMask(mask, clip);
444
2.19k
    }
445
446
    // ARGB and SDF masks shouldn't make it here.
447
3.89M
    SkASSERT(mask.fFormat == SkMask::kA8_Format
448
3.89M
          || mask.fFormat == SkMask::kLCD16_Format
449
3.89M
          || mask.fFormat == SkMask::k3D_Format);
450
451
3.89M
    auto extract_mask_plane = [&mask](int plane, SkRasterPipeline_MemoryCtx* ctx) {
452
        // LCD is 16-bit per pixel; A8 and 3D are 8-bit per pixel.
453
3.89M
        size_t bpp = mask.fFormat == SkMask::kLCD16_Format ? 2 : 1;
454
455
        // Select the right mask plane.  Usually plane == 0 and this is just mask.fImage.
456
3.89M
        auto ptr = (uintptr_t)mask.fImage
457
3.89M
                 + plane * mask.computeImageSize();
458
459
        // Update ctx to point "into" this current mask, but lined up with fDstPtr at (0,0).
460
        // This sort of trickery upsets UBSAN (pointer-overflow) so our ptr must be a uintptr_t.
461
        // mask.fRowBytes is a uint32_t, which would break our addressing math on 64-bit builds.
462
3.89M
        size_t rowBytes = mask.fRowBytes;
463
3.89M
        ctx->stride = rowBytes / bpp;
464
3.89M
        ctx->pixels = (void*)(ptr - mask.fBounds.left() * bpp
465
3.89M
                                  - mask.fBounds.top()  * rowBytes);
466
3.89M
    };
SkRasterPipelineBlitter.cpp:SkRasterPipelineBlitter::blitMask(SkMask const&, SkIRect const&)::$_4::operator()(int, SkRasterPipeline_MemoryCtx*) const
Line
Count
Source
451
3.89M
    auto extract_mask_plane = [&mask](int plane, SkRasterPipeline_MemoryCtx* ctx) {
452
        // LCD is 16-bit per pixel; A8 and 3D are 8-bit per pixel.
453
3.89M
        size_t bpp = mask.fFormat == SkMask::kLCD16_Format ? 2 : 1;
454
455
        // Select the right mask plane.  Usually plane == 0 and this is just mask.fImage.
456
3.89M
        auto ptr = (uintptr_t)mask.fImage
457
3.89M
                 + plane * mask.computeImageSize();
458
459
        // Update ctx to point "into" this current mask, but lined up with fDstPtr at (0,0).
460
        // This sort of trickery upsets UBSAN (pointer-overflow) so our ptr must be a uintptr_t.
461
        // mask.fRowBytes is a uint32_t, which would break our addressing math on 64-bit builds.
462
3.89M
        size_t rowBytes = mask.fRowBytes;
463
3.89M
        ctx->stride = rowBytes / bpp;
464
3.89M
        ctx->pixels = (void*)(ptr - mask.fBounds.left() * bpp
465
3.89M
                                  - mask.fBounds.top()  * rowBytes);
466
3.89M
    };
Unexecuted instantiation: SkRasterPipelineBlitter.cpp:SkRasterPipelineBlitter::blitMask(SkMask const&, SkIRect const&)::$_5::operator()(int, SkRasterPipeline_MemoryCtx*) const
467
468
3.89M
    extract_mask_plane(0, &fMaskPtr);
469
3.89M
    if (mask.fFormat == SkMask::k3D_Format) {
470
0
        extract_mask_plane(1, &fEmbossCtx.mul);
471
0
        extract_mask_plane(2, &fEmbossCtx.add);
472
0
    }
473
474
    // Lazily build whichever pipeline we need, specialized for each mask format.
475
3.89M
    if (mask.fFormat == SkMask::kA8_Format && !fBlitMaskA8) {
476
24.1k
        SkRasterPipeline p(fAlloc);
477
24.1k
        p.extend(fColorPipeline);
478
24.1k
        p.append_gamut_clamp_if_normalized(fDst.info());
479
24.1k
        if (SkBlendMode_ShouldPreScaleCoverage(fBlend, /*rgb_coverage=*/false)) {
480
2.03k
            p.append(SkRasterPipeline::scale_u8, &fMaskPtr);
481
2.03k
            this->append_clip_scale(&p);
482
2.03k
            this->append_load_dst(&p);
483
2.03k
            SkBlendMode_AppendStages(fBlend, &p);
484
22.1k
        } else {
485
22.1k
            this->append_load_dst(&p);
486
22.1k
            SkBlendMode_AppendStages(fBlend, &p);
487
22.1k
            p.append(SkRasterPipeline::lerp_u8, &fMaskPtr);
488
22.1k
            this->append_clip_lerp(&p);
489
22.1k
        }
490
24.1k
        this->append_store(&p);
491
24.1k
        fBlitMaskA8 = p.compile();
492
24.1k
    }
493
3.89M
    if (mask.fFormat == SkMask::kLCD16_Format && !fBlitMaskLCD16) {
494
0
        SkRasterPipeline p(fAlloc);
495
0
        p.extend(fColorPipeline);
496
0
        p.append_gamut_clamp_if_normalized(fDst.info());
497
0
        if (SkBlendMode_ShouldPreScaleCoverage(fBlend, /*rgb_coverage=*/true)) {
498
            // Somewhat unusually, scale_565 needs dst loaded first.
499
0
            this->append_load_dst(&p);
500
0
            p.append(SkRasterPipeline::scale_565, &fMaskPtr);
501
0
            this->append_clip_scale(&p);
502
0
            SkBlendMode_AppendStages(fBlend, &p);
503
0
        } else {
504
0
            this->append_load_dst(&p);
505
0
            SkBlendMode_AppendStages(fBlend, &p);
506
0
            p.append(SkRasterPipeline::lerp_565, &fMaskPtr);
507
0
            this->append_clip_lerp(&p);
508
0
        }
509
0
        this->append_store(&p);
510
0
        fBlitMaskLCD16 = p.compile();
511
0
    }
512
3.89M
    if (mask.fFormat == SkMask::k3D_Format && !fBlitMask3D) {
513
0
        SkRasterPipeline p(fAlloc);
514
0
        p.extend(fColorPipeline);
515
        // This bit is where we differ from kA8_Format:
516
0
        p.append(SkRasterPipeline::emboss, &fEmbossCtx);
517
        // Now onward just as kA8.
518
0
        p.append_gamut_clamp_if_normalized(fDst.info());
519
0
        if (SkBlendMode_ShouldPreScaleCoverage(fBlend, /*rgb_coverage=*/false)) {
520
0
            p.append(SkRasterPipeline::scale_u8, &fMaskPtr);
521
0
            this->append_clip_scale(&p);
522
0
            this->append_load_dst(&p);
523
0
            SkBlendMode_AppendStages(fBlend, &p);
524
0
        } else {
525
0
            this->append_load_dst(&p);
526
0
            SkBlendMode_AppendStages(fBlend, &p);
527
0
            p.append(SkRasterPipeline::lerp_u8, &fMaskPtr);
528
0
            this->append_clip_lerp(&p);
529
0
        }
530
0
        this->append_store(&p);
531
0
        fBlitMask3D = p.compile();
532
0
    }
533
534
3.89M
    std::function<void(size_t,size_t,size_t,size_t)>* blitter = nullptr;
535
3.89M
    switch (mask.fFormat) {
536
3.89M
        case SkMask::kA8_Format:    blitter = &fBlitMaskA8;    break;
537
0
        case SkMask::kLCD16_Format: blitter = &fBlitMaskLCD16; break;
538
0
        case SkMask::k3D_Format:    blitter = &fBlitMask3D;    break;
539
0
        default:
540
0
            SkASSERT(false);
541
0
            return;
542
3.89M
    }
543
544
3.89M
    SkASSERT(blitter);
545
3.89M
    (*blitter)(clip.left(),clip.top(), clip.width(),clip.height());
546
3.89M
}