• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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/private/SkImageInfoPriv.h"
9 #include "include/private/SkMacros.h"
10 #include "src/core/SkArenaAlloc.h"
11 #include "src/core/SkBlendModePriv.h"
12 #include "src/core/SkColorSpacePriv.h"
13 #include "src/core/SkColorSpaceXformSteps.h"
14 #include "src/core/SkCoreBlitters.h"
15 #include "src/core/SkLRUCache.h"
16 #include "src/core/SkOpts.h"
17 #include "src/core/SkVM.h"
18 #include "src/core/SkVMBlitter.h"
19 #include "src/shaders/SkColorFilterShader.h"
20 
21 namespace {
22 
23     // Uniforms set by the Blitter itself,
24     // rather than by the Shader, which follow this struct in the skvm::Uniforms buffer.
25     struct BlitterUniforms {
26         int right;  // First device x + blit run length n, used to get device x coordiate.
27         int y;      // Device y coordiate.
28     };
29     static_assert(SkIsAlign4(sizeof(BlitterUniforms)), "");
30     static constexpr int kBlitterUniformsCount = sizeof(BlitterUniforms) / 4;
31 
32     enum class Coverage { Full, UniformA8, MaskA8, MaskLCD16, Mask3D };
33 
34     struct Params {
35         sk_sp<SkColorSpace> colorSpace;
36         sk_sp<SkShader>     shader;
37         SkColorType         colorType;
38         SkAlphaType         alphaType;
39         SkBlendMode         blendMode;
40         Coverage            coverage;
41         SkFilterQuality     quality;
42         bool                dither;
43         SkMatrix            ctm;
44 
withCoverage__anona8707d6a0111::Params45         Params withCoverage(Coverage c) const {
46             Params p = *this;
47             p.coverage = c;
48             return p;
49         }
50     };
51 
52     SK_BEGIN_REQUIRE_DENSE;
53     struct Key {
54         uint64_t colorSpace;
55         uint64_t shader;
56         uint8_t  colorType,
57                  alphaType,
58                  blendMode,
59                  coverage,
60                  dither;
61         uint8_t padding[3] = {0,0,0};
62         // Params::quality and Params::ctm are only passed to shader->program(),
63         // not used here by the blitter itself.  No need to include them in the key;
64         // they'll be folded into the shader key if used.
65 
operator ==__anona8707d6a0111::Key66         bool operator==(const Key& that) const {
67             return this->colorSpace == that.colorSpace
68                 && this->shader     == that.shader
69                 && this->colorType  == that.colorType
70                 && this->alphaType  == that.alphaType
71                 && this->blendMode  == that.blendMode
72                 && this->coverage   == that.coverage
73                 && this->dither     == that.dither;
74         }
75 
withCoverage__anona8707d6a0111::Key76         Key withCoverage(Coverage c) const {
77             Key k = *this;
78             k.coverage = SkToU8(c);
79             return k;
80         }
81     };
82     SK_END_REQUIRE_DENSE;
83 
debug_name(const Key & key)84     static SkString debug_name(const Key& key) {
85         return SkStringPrintf("CT%d-AT%d-Cov%d-Blend%d-Dither%d-CS%llx-Shader%llx",
86                               key.colorType,
87                               key.alphaType,
88                               key.coverage,
89                               key.blendMode,
90                               key.dither,
91                               key.colorSpace,
92                               key.shader);
93     }
94 
try_acquire_program_cache()95     static SkLRUCache<Key, skvm::Program>* try_acquire_program_cache() {
96     #if 1 && defined(SKVM_JIT)
97         thread_local static SkLRUCache<Key, skvm::Program> cache{8};
98         return &cache;
99     #else
100         // iOS in particular does not support thread_local until iOS 9.0.
101         // On the other hand, we'll never be able to JIT there anyway.
102         // It's probably fine to not cache any interpreted programs, anywhere.
103         return nullptr;
104     #endif
105     }
106 
release_program_cache()107     static void release_program_cache() { }
108 
109 
110     struct Builder : public skvm::Builder {
111 
112         // If Builder can't build this program, CacheKey() sets *ok to false.
CacheKey__anona8707d6a0111::Builder113         static Key CacheKey(const Params& params,
114                             skvm::Uniforms* uniforms,
115                             SkArenaAlloc* alloc,
116                             bool* ok) {
117             SkASSERT(params.shader);
118             uint64_t shaderHash = 0;
119             {
120                 const SkShaderBase* shader = as_SB(params.shader);
121                 skvm::Builder p;
122 
123                 skvm::I32 dx = p.sub(p.uniform32(uniforms->base, offsetof(BlitterUniforms, right)),
124                                      p.index()),
125                           dy = p.uniform32(uniforms->base, offsetof(BlitterUniforms, y));
126                 skvm::F32 x = p.add(p.to_f32(dx), p.splat(0.5f)),
127                           y = p.add(p.to_f32(dy), p.splat(0.5f));
128 
129                 skvm::F32 r,g,b,a;
130                 if (shader->program(&p,
131                                     params.ctm, /*localM=*/nullptr,
132                                     params.quality, params.colorSpace.get(),
133                                     uniforms,alloc,
134                                     x,y, &r,&g,&b,&a)) {
135                     shaderHash = p.hash();
136                     // p.hash() folds in all instructions to produce r,g,b,a but does not know
137                     // precisely which value we'll treat as which channel.  Imagine the shader
138                     // called std::swap(*r,*b)... it draws differently, but p.hash() is unchanged.
139                     const int outputs[] = { r.id, g.id, b.id, a.id };
140                     shaderHash ^= SkOpts::hash(outputs, sizeof(outputs));
141                 } else {
142                     *ok = false;
143                 }
144             }
145 
146             switch (params.colorType) {
147                 default: *ok = false;
148                          break;
149 
150                 case kRGB_565_SkColorType:
151                 case kRGB_888x_SkColorType:
152                 case kRGBA_8888_SkColorType:
153                 case kBGRA_8888_SkColorType:
154                 case kRGBA_1010102_SkColorType:
155                 case kBGRA_1010102_SkColorType:
156                 case kRGB_101010x_SkColorType:
157                 case kBGR_101010x_SkColorType:  break;
158             }
159 
160             if (!skvm::BlendModeSupported(params.blendMode)) {
161                 *ok = false;
162             }
163 
164             return {
165                 params.colorSpace ? params.colorSpace->hash() : 0,
166                 shaderHash,
167                 SkToU8(params.colorType),
168                 SkToU8(params.alphaType),
169                 SkToU8(params.blendMode),
170                 SkToU8(params.coverage),
171                 SkToU8(params.dither),
172             };
173         }
174 
Builder__anona8707d6a0111::Builder175         Builder(const Params& params, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) {
176             // First two arguments are always uniforms and the destination buffer.
177             uniforms->base    = uniform();
178             skvm::Arg dst_ptr = arg(SkColorTypeBytesPerPixel(params.colorType));
179             // Other arguments depend on params.coverage:
180             //    - Full:      (no more arguments)
181             //    - Mask3D:    mul varying, add varying, 8-bit coverage varying
182             //    - MaskA8:    8-bit coverage varying
183             //    - MaskLCD16: 565 coverage varying
184             //    - UniformA8: 8-bit coverage uniform
185 
186             skvm::I32 dx = sub(uniform32(uniforms->base, offsetof(BlitterUniforms, right)),
187                                index()),
188                       dy = uniform32(uniforms->base, offsetof(BlitterUniforms, y));
189             skvm::F32 x = add(to_f32(dx), splat(0.5f)),
190                       y = add(to_f32(dy), splat(0.5f));
191 
192             skvm::Color src;
193             SkAssertResult(as_SB(params.shader)->program(this,
194                                                          params.ctm, /*localM=*/nullptr,
195                                                          params.quality, params.colorSpace.get(),
196                                                          uniforms, alloc,
197                                                          x,y, &src.r, &src.g, &src.b, &src.a));
198             if (params.coverage == Coverage::Mask3D) {
199                 skvm::F32 M = from_unorm(8, load8(varying<uint8_t>())),
200                           A = from_unorm(8, load8(varying<uint8_t>()));
201 
202                 src.r = min(mad(src.r, M, A), src.a);
203                 src.g = min(mad(src.g, M, A), src.a);
204                 src.b = min(mad(src.b, M, A), src.a);
205             }
206 
207             // If we can determine this we can skip a fair bit of clamping!
208             bool src_in_gamut = false;
209 
210             // Normalized premul formats can surprisingly represent some out-of-gamut
211             // values (e.g. r=0xff, a=0xee fits in unorm8 but r = 1.07), but most code
212             // working with normalized premul colors is not prepared to handle r,g,b > a.
213             // So we clamp the shader to gamut here before blending and coverage.
214             //
215             // In addition, GL clamps all its color channels to limits of the format just
216             // before the blend step (~here).  To match that auto-clamp, we clamp alpha to
217             // [0,1] too, just in case someone gave us a crazy alpha.
218             if (!src_in_gamut
219                     && params.alphaType == kPremul_SkAlphaType
220                     && SkColorTypeIsNormalized(params.colorType)) {
221                 src.a = clamp(src.a, splat(0.0f), splat(1.0f));
222                 src.r = clamp(src.r, splat(0.0f), src.a);
223                 src.g = clamp(src.g, splat(0.0f), src.a);
224                 src.b = clamp(src.b, splat(0.0f), src.a);
225                 src_in_gamut = true;
226             }
227 
228             // There are several orderings here of when we load dst and coverage
229             // and how coverage is applied, and to complicate things, LCD coverage
230             // needs to know dst.a.  We're careful to assert it's loaded in time.
231             skvm::Color dst;
232             SkDEBUGCODE(bool dst_loaded = false;)
233 
234             // load_coverage() returns false when there's no need to apply coverage.
235             auto load_coverage = [&](skvm::Color* cov) {
236                 switch (params.coverage) {
237                     case Coverage::Full: return false;
238 
239                     case Coverage::UniformA8: cov->r = cov->g = cov->b = cov->a =
240                                               from_unorm(8, uniform8(uniform(), 0));
241                                               return true;
242 
243                     case Coverage::Mask3D:
244                     case Coverage::MaskA8: cov->r = cov->g = cov->b = cov->a =
245                                            from_unorm(8, load8(varying<uint8_t>()));
246                                            return true;
247 
248                     case Coverage::MaskLCD16:
249                         SkASSERT(dst_loaded);
250                         *cov = unpack_565(load16(varying<uint16_t>()));
251                         cov->a = select(lt(src.a, dst.a), min(cov->r, min(cov->g,cov->b))
252                                                         , max(cov->r, max(cov->g,cov->b)));
253                         return true;
254                 }
255                 // GCC insists...
256                 return false;
257             };
258 
259             // The math for some blend modes lets us fold coverage into src before the blend,
260             // obviating the need for the lerp afterwards. This early-coverage strategy tends
261             // to be both faster and require fewer registers.
262             bool lerp_coverage_post_blend = true;
263             if (SkBlendMode_ShouldPreScaleCoverage(params.blendMode,
264                                                    params.coverage == Coverage::MaskLCD16)) {
265                 skvm::Color cov;
266                 if (load_coverage(&cov)) {
267                     src.r = mul(src.r, cov.r);
268                     src.g = mul(src.g, cov.g);
269                     src.b = mul(src.b, cov.b);
270                     src.a = mul(src.a, cov.a);
271                 }
272                 lerp_coverage_post_blend = false;
273             }
274 
275             // Load up the destination color.
276             SkDEBUGCODE(dst_loaded = true;)
277             switch (params.colorType) {
278                 default: SkUNREACHABLE;
279                 case kRGB_565_SkColorType: dst = unpack_565(load16(dst_ptr));
280                                            break;
281 
282                 case  kRGB_888x_SkColorType: [[fallthrough]];
283                 case kRGBA_8888_SkColorType: dst = unpack_8888(load32(dst_ptr));
284                                              break;
285 
286                 case kBGRA_8888_SkColorType: dst = unpack_8888(load32(dst_ptr));
287                                              std::swap(dst.r, dst.b);
288                                              break;
289 
290                 case  kRGB_101010x_SkColorType: [[fallthrough]];
291                 case kRGBA_1010102_SkColorType: dst = unpack_1010102(load32(dst_ptr));
292                                                 break;
293 
294                 case  kBGR_101010x_SkColorType: [[fallthrough]];
295                 case kBGRA_1010102_SkColorType: dst = unpack_1010102(load32(dst_ptr));
296                                                 std::swap(dst.r, dst.b);
297                                                 break;
298             }
299 
300             // When a destination is known opaque, we may assume it both starts and stays fully
301             // opaque, ignoring any math that disagrees.  This sometimes trims a little work.
302             const bool dst_is_opaque = SkAlphaTypeIsOpaque(params.alphaType)
303                                     || SkColorTypeIsAlwaysOpaque(params.colorType);
304             if (dst_is_opaque) {
305                 dst.a = splat(1.0f);
306             } else if (params.alphaType == kUnpremul_SkAlphaType) {
307                 premul(&dst.r, &dst.g, &dst.b, dst.a);
308             }
309 
310             src = skvm::BlendModeProgram(this, params.blendMode, src, dst);
311 
312             // Lerp with coverage post-blend if needed.
313             skvm::Color cov;
314             if (lerp_coverage_post_blend && load_coverage(&cov)) {
315                 src.r = mad(sub(src.r, dst.r), cov.r, dst.r);
316                 src.g = mad(sub(src.g, dst.g), cov.g, dst.g);
317                 src.b = mad(sub(src.b, dst.b), cov.b, dst.b);
318                 src.a = mad(sub(src.a, dst.a), cov.a, dst.a);
319             }
320 
321             if (dst_is_opaque) {
322                 src.a = splat(1.0f);
323             } else if (params.alphaType == kUnpremul_SkAlphaType) {
324                 unpremul(&src.r, &src.g, &src.b, src.a);
325             }
326 
327             float dither_rate = 0.0f;
328             switch (params.colorType) {
329                 case kARGB_4444_SkColorType:    dither_rate =   1/15.0f; break;
330                 case   kRGB_565_SkColorType:    dither_rate =   1/63.0f; break;
331                 case    kGray_8_SkColorType:
332                 case  kRGB_888x_SkColorType:
333                 case kRGBA_8888_SkColorType:
334                 case kBGRA_8888_SkColorType:    dither_rate =  1/255.0f; break;
335                 case kRGB_101010x_SkColorType:
336                 case kRGBA_1010102_SkColorType:
337                 case kBGR_101010x_SkColorType:
338                 case kBGRA_1010102_SkColorType: dither_rate = 1/1023.0f; break;
339 
340                 case kUnknown_SkColorType:
341                 case kAlpha_8_SkColorType:
342                 case kRGBA_F16_SkColorType:
343                 case kRGBA_F16Norm_SkColorType:
344                 case kRGBA_F32_SkColorType:
345                 case kR8G8_unorm_SkColorType:
346                 case kA16_float_SkColorType:
347                 case kA16_unorm_SkColorType:
348                 case kR16G16_float_SkColorType:
349                 case kR16G16_unorm_SkColorType:
350                 case kR16G16B16A16_unorm_SkColorType: dither_rate = 0.0f; break;
351             }
352             if (params.dither && dither_rate > 0) {
353                 // See SkRasterPipeline dither stage.
354 
355                 // This is 8x8 ordered dithering.  From here we'll only need dx and dx^dy.
356                 skvm::I32 X = dx,
357                           Y = bit_xor(dx,dy);
358 
359                 // If X's low bits are abc and Y's def, M is fcebda,
360                 // 6 bits producing all values [0,63] shuffled over an 8x8 grid.
361                 skvm::I32 M = bit_or(shl(bit_and(Y, splat(1)), 5),
362                               bit_or(shl(bit_and(X, splat(1)), 4),
363                               bit_or(shl(bit_and(Y, splat(2)), 2),
364                               bit_or(shl(bit_and(X, splat(2)), 1),
365                               bit_or(shr(bit_and(Y, splat(4)), 1),
366                                      shr(bit_and(X, splat(4)), 2))))));
367 
368                 // Scale to [0,1) by /64, then to (-0.5,0.5) using 63/128 (~0.492) as 0.5-ε,
369                 // and finally scale all that by the dither_rate.  We keep dither strength
370                 // strictly within ±0.5 to not change exact values like 0 or 1.
371                 float scale = dither_rate * (  2/128.0f),
372                       bias  = dither_rate * (-63/128.0f);
373                 skvm::F32 dither = mad(to_f32(M), splat(scale), splat(bias));
374 
375                 src.r = add(src.r, dither);
376                 src.g = add(src.g, dither);
377                 src.b = add(src.b, dither);
378 
379                 // TODO: this is consistent with the old code but doesn't make sense for unpremul.
380                 src.r = clamp(src.r, splat(0.0f), src.a);
381                 src.g = clamp(src.g, splat(0.0f), src.a);
382                 src.b = clamp(src.b, splat(0.0f), src.a);
383             }
384 
385             // Clamp to fit destination color format if needed.
386             if (src_in_gamut) {
387                 // An in-gamut src blended with an in-gamut dst should stay in gamut.
388                 // Being in-gamut implies all channels are in [0,1], so no need to clamp.
389                 assert_true(eq(src.r, clamp(src.r, splat(0.0f), splat(1.0f))));
390                 assert_true(eq(src.g, clamp(src.g, splat(0.0f), splat(1.0f))));
391                 assert_true(eq(src.b, clamp(src.b, splat(0.0f), splat(1.0f))));
392                 assert_true(eq(src.a, clamp(src.a, splat(0.0f), splat(1.0f))));
393             } else if (SkColorTypeIsNormalized(params.colorType)) {
394                 src.r = clamp(src.r, splat(0.0f), splat(1.0f));
395                 src.g = clamp(src.g, splat(0.0f), splat(1.0f));
396                 src.b = clamp(src.b, splat(0.0f), splat(1.0f));
397                 src.a = clamp(src.a, splat(0.0f), splat(1.0f));
398             }
399 
400             // Store back to the destination.
401             switch (params.colorType) {
402                 default: SkUNREACHABLE;
403 
404                 case kRGB_565_SkColorType:
405                     store16(dst_ptr, pack(pack(to_unorm(5,src.b),
406                                                to_unorm(6,src.g), 5),
407                                                to_unorm(5,src.r),11));
408                     break;
409 
410                 case kBGRA_8888_SkColorType: std::swap(src.r, src.b);  [[fallthrough]];
411                 case  kRGB_888x_SkColorType:                           [[fallthrough]];
412                 case kRGBA_8888_SkColorType:
413                      store32(dst_ptr, pack(pack(to_unorm(8, src.r),
414                                                 to_unorm(8, src.g), 8),
415                                            pack(to_unorm(8, src.b),
416                                                 to_unorm(8, src.a), 8), 16));
417                      break;
418 
419                 case  kBGR_101010x_SkColorType:                          [[fallthrough]];
420                 case kBGRA_1010102_SkColorType: std::swap(src.r, src.b); [[fallthrough]];
421                 case  kRGB_101010x_SkColorType:                          [[fallthrough]];
422                 case kRGBA_1010102_SkColorType:
423                      store32(dst_ptr, pack(pack(to_unorm(10, src.r),
424                                                 to_unorm(10, src.g), 10),
425                                            pack(to_unorm(10, src.b),
426                                                 to_unorm( 2, src.a), 10), 20));
427                      break;
428             }
429         }
430     };
431 
432     struct NoopColorFilter : public SkColorFilter {
onProgram__anona8707d6a0111::NoopColorFilter433         bool onProgram(skvm::Builder*,
434                        SkColorSpace*,
435                        skvm::Uniforms*, SkArenaAlloc*,
436                        skvm::F32*, skvm::F32*, skvm::F32*, skvm::F32*) const override {
437             return true;
438         }
439 
onAppendStages__anona8707d6a0111::NoopColorFilter440         bool onAppendStages(const SkStageRec&, bool) const override { return true; }
441 
442         // Only created here, should never be flattened / unflattened.
getFactory__anona8707d6a0111::NoopColorFilter443         Factory getFactory() const override { return nullptr; }
getTypeName__anona8707d6a0111::NoopColorFilter444         const char* getTypeName() const override { return "NoopColorFilter"; }
445     };
446 
effective_params(const SkPixmap & device,const SkPaint & paint,const SkMatrix & ctm)447     static Params effective_params(const SkPixmap& device,
448                                    const SkPaint& paint,
449                                    const SkMatrix& ctm) {
450         // Color filters have been handled for us by SkBlitter::Choose().
451         SkASSERT(!paint.getColorFilter());
452 
453         // If there's no explicit shader, the paint color is the shader,
454         // but if there is a shader, it's modulated by the paint alpha.
455         sk_sp<SkShader> shader = paint.refShader();
456         if (!shader) {
457             shader = SkShaders::Color(paint.getColor4f(), nullptr);
458         } else if (paint.getAlphaf() < 1.0f) {
459             shader = sk_make_sp<SkColorFilterShader>(std::move(shader),
460                                                      paint.getAlphaf(),
461                                                      sk_make_sp<NoopColorFilter>());
462         }
463 
464         // The most common blend mode is SrcOver, and it can be strength-reduced
465         // _greatly_ to Src mode when the shader is opaque.
466         SkBlendMode blendMode = paint.getBlendMode();
467         if (blendMode == SkBlendMode::kSrcOver && shader->isOpaque()) {
468             blendMode =  SkBlendMode::kSrc;
469         }
470 
471         bool dither = paint.isDither() && !as_SB(shader)->isConstant();
472 
473         // In general all the information we use to make decisions here need to
474         // be reflected in Params and Key to make program caching sound, and it
475         // might appear that shader->isOpaque() is a property of the shader's
476         // uniforms than its fundamental program structure and so unsafe to use.
477         //
478         // Opacity is such a powerful property that SkShaderBase::program()
479         // forces opacity for any shader subclass that claims isOpaque(), so
480         // the opaque bit is strongly guaranteed to be part of the program and
481         // not just a property of the uniforms.  The shader program hash includes
482         // this information, making it safe to use anywhere in the blitter codegen.
483 
484         return {
485             device.refColorSpace(),
486             std::move(shader),
487             device.colorType(),
488             device.alphaType(),
489             blendMode,
490             Coverage::Full,  // Placeholder... withCoverage() will change as needed.
491             paint.getFilterQuality(),
492             dither,
493             ctm,
494         };
495     }
496 
497     class Blitter final : public SkBlitter {
498     public:
Blitter(const SkPixmap & device,const SkPaint & paint,const SkMatrix & ctm,bool * ok)499         Blitter(const SkPixmap& device, const SkPaint& paint, const SkMatrix& ctm, bool* ok)
500             : fDevice(device)
501             , fUniforms(kBlitterUniformsCount)
502             , fParams(effective_params(device, paint, ctm))
503             , fKey(Builder::CacheKey(fParams, &fUniforms, &fAlloc, ok))
504         {}
505 
~Blitter()506         ~Blitter() override {
507             if (SkLRUCache<Key, skvm::Program>* cache = try_acquire_program_cache()) {
508                 auto cache_program = [&](skvm::Program&& program, Coverage coverage) {
509                     if (!program.empty()) {
510                         Key key = fKey.withCoverage(coverage);
511                         if (skvm::Program* found = cache->find(key)) {
512                             *found = std::move(program);
513                         } else {
514                             cache->insert(key, std::move(program));
515                         }
516                     }
517                 };
518                 cache_program(std::move(fBlitH),         Coverage::Full);
519                 cache_program(std::move(fBlitAntiH),     Coverage::UniformA8);
520                 cache_program(std::move(fBlitMaskA8),    Coverage::MaskA8);
521                 cache_program(std::move(fBlitMask3D),    Coverage::Mask3D);
522                 cache_program(std::move(fBlitMaskLCD16), Coverage::MaskLCD16);
523 
524                 release_program_cache();
525             }
526         }
527 
528     private:
529         SkPixmap       fDevice;
530         skvm::Uniforms fUniforms;                // Most data is copied directly into fUniforms,
531         SkArenaAlloc   fAlloc{2*sizeof(void*)};  // but a few effects need to ref large content.
532         const Params   fParams;
533         const Key      fKey;
534         skvm::Program  fBlitH,
535                        fBlitAntiH,
536                        fBlitMaskA8,
537                        fBlitMask3D,
538                        fBlitMaskLCD16;
539 
buildProgram(Coverage coverage)540         skvm::Program buildProgram(Coverage coverage) {
541             Key key = fKey.withCoverage(coverage);
542             {
543                 skvm::Program p;
544                 if (SkLRUCache<Key, skvm::Program>* cache = try_acquire_program_cache()) {
545                     if (skvm::Program* found = cache->find(key)) {
546                         p = std::move(*found);
547                     }
548                     release_program_cache();
549                 }
550                 if (!p.empty()) {
551                     return p;
552                 }
553             }
554             // We don't really _need_ to rebuild fUniforms here.
555             // It's just more natural to have effects unconditionally emit them,
556             // and more natural to rebuild fUniforms than to emit them into a dummy buffer.
557             // fUniforms should reuse the exact same memory, so this is very cheap.
558             SkDEBUGCODE(size_t prev = fUniforms.buf.size();)
559             fUniforms.buf.resize(kBlitterUniformsCount);
560             Builder builder{fParams.withCoverage(coverage), &fUniforms, &fAlloc};
561             SkASSERT(fUniforms.buf.size() == prev);
562 
563             skvm::Program program = builder.done(debug_name(key).c_str());
564             if (false) {
565                 static std::atomic<int> missed{0},
566                                          total{0};
567                 if (!program.hasJIT()) {
568                     SkDebugf("\ncouldn't JIT %s\n", debug_name(key).c_str());
569                     builder.dump();
570                     program.dump();
571                     missed++;
572                 }
573                 if (0 == total++) {
574                     atexit([]{ SkDebugf("SkVMBlitter compiled %d programs, %d without JIT.\n",
575                                         total.load(), missed.load()); });
576                 }
577             }
578             return program;
579         }
580 
updateUniforms(int right,int y)581         void updateUniforms(int right, int y) {
582             BlitterUniforms uniforms{right, y};
583             memcpy(fUniforms.buf.data(), &uniforms, sizeof(BlitterUniforms));
584         }
585 
blitH(int x,int y,int w)586         void blitH(int x, int y, int w) override {
587             if (fBlitH.empty()) {
588                 fBlitH = this->buildProgram(Coverage::Full);
589             }
590             this->updateUniforms(x+w, y);
591             fBlitH.eval(w, fUniforms.buf.data(), fDevice.addr(x,y));
592         }
593 
blitAntiH(int x,int y,const SkAlpha cov[],const int16_t runs[])594         void blitAntiH(int x, int y, const SkAlpha cov[], const int16_t runs[]) override {
595             if (fBlitAntiH.empty()) {
596                 fBlitAntiH = this->buildProgram(Coverage::UniformA8);
597             }
598             for (int16_t run = *runs; run > 0; run = *runs) {
599                 this->updateUniforms(x+run, y);
600                 fBlitAntiH.eval(run, fUniforms.buf.data(), fDevice.addr(x,y), cov);
601 
602                 x    += run;
603                 runs += run;
604                 cov  += run;
605             }
606         }
607 
blitMask(const SkMask & mask,const SkIRect & clip)608         void blitMask(const SkMask& mask, const SkIRect& clip) override {
609             if (mask.fFormat == SkMask::kBW_Format) {
610                 return SkBlitter::blitMask(mask, clip);
611             }
612 
613             const skvm::Program* program = nullptr;
614             switch (mask.fFormat) {
615                 default: SkUNREACHABLE;     // ARGB and SDF masks shouldn't make it here.
616 
617                 case SkMask::k3D_Format:
618                     if (fBlitMask3D.empty()) {
619                         fBlitMask3D = this->buildProgram(Coverage::Mask3D);
620                     }
621                     program = &fBlitMask3D;
622                     break;
623 
624                 case SkMask::kA8_Format:
625                     if (fBlitMaskA8.empty()) {
626                         fBlitMaskA8 = this->buildProgram(Coverage::MaskA8);
627                     }
628                     program = &fBlitMaskA8;
629                     break;
630 
631                 case SkMask::kLCD16_Format:
632                     if (fBlitMaskLCD16.empty()) {
633                         fBlitMaskLCD16 = this->buildProgram(Coverage::MaskLCD16);
634                     }
635                     program = &fBlitMaskLCD16;
636                     break;
637             }
638 
639             SkASSERT(program);
640             if (program) {
641                 for (int y = clip.top(); y < clip.bottom(); y++) {
642                     int x = clip.left(),
643                         w = clip.width();
644                     void* dptr =        fDevice.writable_addr(x,y);
645                     auto  mptr = (const uint8_t*)mask.getAddr(x,y);
646                     this->updateUniforms(x+w,y);
647 
648                     if (program == &fBlitMask3D) {
649                         size_t plane = mask.computeImageSize();
650                         program->eval(w, fUniforms.buf.data(), dptr, mptr + 1*plane
651                                                                    , mptr + 2*plane
652                                                                    , mptr + 0*plane);
653                     } else {
654                         program->eval(w, fUniforms.buf.data(), dptr, mptr);
655                     }
656                 }
657             }
658         }
659     };
660 
661 }  // namespace
662 
BlendModeSupported(SkBlendMode mode)663 bool skvm::BlendModeSupported(SkBlendMode mode) {
664     return mode <= SkBlendMode::kScreen;
665 }
666 
BlendModeProgram(skvm::Builder * p,SkBlendMode mode,skvm::Color src,skvm::Color dst)667 skvm::Color skvm::BlendModeProgram(skvm::Builder* p,
668                                    SkBlendMode mode, skvm::Color src, skvm::Color dst) {
669     auto mma = [&](skvm::F32 x, skvm::F32 y, skvm::F32 z, skvm::F32 w) {
670         return p->mad(x,y, p->mul(z,w));
671     };
672 
673     auto inv = [&](skvm::F32 x) {
674         return p->sub(p->splat(1.0f), x);
675     };
676 
677     switch (mode) {
678         default: SkASSERT(false); /*but also, for safety, fallthrough*/
679 
680         case SkBlendMode::kClear: return {
681             p->splat(0.0f),
682             p->splat(0.0f),
683             p->splat(0.0f),
684             p->splat(0.0f),
685         };
686 
687         case SkBlendMode::kSrc: return src;
688         case SkBlendMode::kDst: return dst;
689 
690         case SkBlendMode::kDstOver: std::swap(src, dst); // fall-through
691         case SkBlendMode::kSrcOver: return {
692             p->mad(dst.r, inv(src.a), src.r),
693             p->mad(dst.g, inv(src.a), src.g),
694             p->mad(dst.b, inv(src.a), src.b),
695             p->mad(dst.a, inv(src.a), src.a),
696         };
697 
698         case SkBlendMode::kDstIn: std::swap(src, dst); // fall-through
699         case SkBlendMode::kSrcIn: return {
700             p->mul(src.r, dst.a),
701             p->mul(src.g, dst.a),
702             p->mul(src.b, dst.a),
703             p->mul(src.a, dst.a),
704         };
705 
706         case SkBlendMode::kDstOut: std::swap(src, dst); // fall-through
707         case SkBlendMode::kSrcOut: return {
708             p->mul(src.r, inv(dst.a)),
709             p->mul(src.g, inv(dst.a)),
710             p->mul(src.b, inv(dst.a)),
711             p->mul(src.a, inv(dst.a)),
712         };
713 
714         case SkBlendMode::kDstATop: std::swap(src, dst); // fall-through
715         case SkBlendMode::kSrcATop: return {
716             mma(src.r, dst.a,  dst.r, inv(src.a)),
717             mma(src.g, dst.a,  dst.g, inv(src.a)),
718             mma(src.b, dst.a,  dst.b, inv(src.a)),
719             mma(src.a, dst.a,  dst.a, inv(src.a)),
720         };
721 
722         case SkBlendMode::kXor: return {
723             mma(src.r, inv(dst.a),  dst.r, inv(src.a)),
724             mma(src.g, inv(dst.a),  dst.g, inv(src.a)),
725             mma(src.b, inv(dst.a),  dst.b, inv(src.a)),
726             mma(src.a, inv(dst.a),  dst.a, inv(src.a)),
727         };
728 
729         case SkBlendMode::kPlus: return {
730             p->min(p->add(src.r, dst.r), p->splat(1.0f)),
731             p->min(p->add(src.g, dst.g), p->splat(1.0f)),
732             p->min(p->add(src.b, dst.b), p->splat(1.0f)),
733             p->min(p->add(src.a, dst.a), p->splat(1.0f)),
734         };
735 
736         case SkBlendMode::kModulate: return {
737             p->mul(src.r, dst.r),
738             p->mul(src.g, dst.g),
739             p->mul(src.b, dst.b),
740             p->mul(src.a, dst.a),
741         };
742 
743         case SkBlendMode::kScreen: return {
744             // (s+d)-(s*d) gave us trouble with our "r,g,b <= after blending" asserts.
745             // It's kind of plausible that s + (d - sd) keeps more precision?
746             p->add(src.r, p->sub(dst.r, p->mul(src.r, dst.r))),
747             p->add(src.g, p->sub(dst.g, p->mul(src.g, dst.g))),
748             p->add(src.b, p->sub(dst.b, p->mul(src.b, dst.b))),
749             p->add(src.a, p->sub(dst.a, p->mul(src.a, dst.a))),
750         };
751     }
752 }
753 
SkCreateSkVMBlitter(const SkPixmap & device,const SkPaint & paint,const SkMatrix & ctm,SkArenaAlloc * alloc)754 SkBlitter* SkCreateSkVMBlitter(const SkPixmap& device,
755                                const SkPaint& paint,
756                                const SkMatrix& ctm,
757                                SkArenaAlloc* alloc) {
758     bool ok = true;
759     auto blitter = alloc->make<Blitter>(device, paint, ctm, &ok);
760     return ok ? blitter : nullptr;
761 }
762