• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/core/SkRasterPipeline.h"
9 
10 #include "include/core/SkColorType.h"
11 #include "include/core/SkImageInfo.h"
12 #include "include/core/SkMatrix.h"
13 #include "include/private/base/SkDebug.h"
14 #include "include/private/base/SkTemplates.h"
15 #include "modules/skcms/skcms.h"
16 #include "src/base/SkVx.h"
17 #include "src/core/SkImageInfoPriv.h"
18 #include "src/core/SkOpts.h"
19 #include "src/core/SkRasterPipelineOpContexts.h"
20 #include "src/core/SkRasterPipelineOpList.h"
21 
22 #include <algorithm>
23 #include <cstring>
24 #include <vector>
25 
26 using namespace skia_private;
27 using Op = SkRasterPipelineOp;
28 
29 bool gForceHighPrecisionRasterPipeline;
30 
SkRasterPipeline(SkArenaAlloc * alloc)31 SkRasterPipeline::SkRasterPipeline(SkArenaAlloc* alloc) : fAlloc(alloc) {
32     this->reset();
33 }
34 
reset()35 void SkRasterPipeline::reset() {
36     // We intentionally leave the alloc alone here; we don't own it.
37     fRewindCtx   = nullptr;
38     fStages      = nullptr;
39     fTailPointer = nullptr;
40     fNumStages   = 0;
41     fMemoryCtxInfos.clear();
42 }
43 
append(SkRasterPipelineOp op,void * ctx)44 void SkRasterPipeline::append(SkRasterPipelineOp op, void* ctx) {
45     SkASSERT(op != Op::uniform_color);            // Please use appendConstantColor().
46     SkASSERT(op != Op::unbounded_uniform_color);  // Please use appendConstantColor().
47     SkASSERT(op != Op::set_rgb);                  // Please use appendSetRGB().
48     SkASSERT(op != Op::unbounded_set_rgb);        // Please use appendSetRGB().
49     SkASSERT(op != Op::parametric);               // Please use appendTransferFunction().
50     SkASSERT(op != Op::gamma_);                   // Please use appendTransferFunction().
51     SkASSERT(op != Op::PQish);                    // Please use appendTransferFunction().
52     SkASSERT(op != Op::HLGish);                   // Please use appendTransferFunction().
53     SkASSERT(op != Op::HLGinvish);                // Please use appendTransferFunction().
54     SkASSERT(op != Op::stack_checkpoint);         // Please use appendStackRewind().
55     SkASSERT(op != Op::stack_rewind);             // Please use appendStackRewind().
56     this->uncheckedAppend(op, ctx);
57 }
58 
tailPointer()59 uint8_t* SkRasterPipeline::tailPointer() {
60     if (!fTailPointer) {
61         // All ops in the pipeline that use the tail value share the same value.
62         fTailPointer = fAlloc->make<uint8_t>(0xFF);
63     }
64     return fTailPointer;
65 }
66 
uncheckedAppend(SkRasterPipelineOp op,void * ctx)67 void SkRasterPipeline::uncheckedAppend(SkRasterPipelineOp op, void* ctx) {
68     bool isLoad = false, isStore = false;
69     SkColorType ct = kUnknown_SkColorType;
70 
71 #define COLOR_TYPE_CASE(stage_ct, sk_ct) \
72     case Op::load_##stage_ct:            \
73     case Op::load_##stage_ct##_dst:      \
74         ct = sk_ct;                      \
75         isLoad = true;                   \
76         break;                           \
77     case Op::store_##stage_ct:           \
78         ct = sk_ct;                      \
79         isStore = true;                  \
80         break;
81 
82     switch (op) {
83         COLOR_TYPE_CASE(a8, kAlpha_8_SkColorType)
84         COLOR_TYPE_CASE(565, kRGB_565_SkColorType)
85         COLOR_TYPE_CASE(4444, kARGB_4444_SkColorType)
86         COLOR_TYPE_CASE(8888, kRGBA_8888_SkColorType)
87         COLOR_TYPE_CASE(rg88, kR8G8_unorm_SkColorType)
88         COLOR_TYPE_CASE(16161616, kR16G16B16A16_unorm_SkColorType)
89         COLOR_TYPE_CASE(a16, kA16_unorm_SkColorType)
90         COLOR_TYPE_CASE(rg1616, kR16G16_unorm_SkColorType)
91         COLOR_TYPE_CASE(f16, kRGBA_F16_SkColorType)
92         COLOR_TYPE_CASE(af16, kA16_float_SkColorType)
93         COLOR_TYPE_CASE(rgf16, kR16G16_float_SkColorType)
94         COLOR_TYPE_CASE(f32, kRGBA_F32_SkColorType)
95         COLOR_TYPE_CASE(1010102, kRGBA_1010102_SkColorType)
96         COLOR_TYPE_CASE(1010102_xr, kBGR_101010x_XR_SkColorType)
97         COLOR_TYPE_CASE(10101010_xr, kBGRA_10101010_XR_SkColorType)
98         COLOR_TYPE_CASE(10x6, kRGBA_10x6_SkColorType)
99 
100 #undef COLOR_TYPE_CASE
101 
102         // Odd stage that doesn't have a load variant (appendLoad uses load_a8 + alpha_to_red)
103         case Op::store_r8: {
104             ct = kR8_unorm_SkColorType;
105             isStore = true;
106             break;
107         }
108         case Op::srcover_rgba_8888: {
109             ct = kRGBA_8888_SkColorType;
110             isLoad = true;
111             isStore = true;
112             break;
113         }
114         case Op::scale_u8:
115         case Op::lerp_u8: {
116             ct = kAlpha_8_SkColorType;
117             isLoad = true;
118             break;
119         }
120         case Op::scale_565:
121         case Op::lerp_565: {
122             ct = kRGB_565_SkColorType;
123             isLoad = true;
124             break;
125         }
126         case Op::emboss: {
127             // Special-case, this op uses a context that holds *two* MemoryCtxs
128             SkRasterPipeline_EmbossCtx* embossCtx = (SkRasterPipeline_EmbossCtx*)ctx;
129             this->addMemoryContext(&embossCtx->add,
130                                    SkColorTypeBytesPerPixel(kAlpha_8_SkColorType),
131                                    /*load=*/true, /*store=*/false);
132             this->addMemoryContext(&embossCtx->mul,
133                                    SkColorTypeBytesPerPixel(kAlpha_8_SkColorType),
134                                    /*load=*/true, /*store=*/false);
135             break;
136         }
137         case Op::init_lane_masks: {
138             auto* initCtx = (SkRasterPipeline_InitLaneMasksCtx*)ctx;
139             initCtx->tail = this->tailPointer();
140             break;
141         }
142         case Op::branch_if_all_lanes_active: {
143             auto* branchCtx = (SkRasterPipeline_BranchIfAllLanesActiveCtx*)ctx;
144             branchCtx->tail = this->tailPointer();
145             break;
146         }
147         default:
148             break;
149     }
150 
151     fStages = fAlloc->make<StageList>(StageList{fStages, op, ctx});
152     fNumStages += 1;
153 
154     if (isLoad || isStore) {
155         SkASSERT(ct != kUnknown_SkColorType);
156         this->addMemoryContext(
157                 (SkRasterPipeline_MemoryCtx*)ctx, SkColorTypeBytesPerPixel(ct), isLoad, isStore);
158     }
159 }
160 
append(SkRasterPipelineOp op,uintptr_t ctx)161 void SkRasterPipeline::append(SkRasterPipelineOp op, uintptr_t ctx) {
162     void* ptrCtx;
163     memcpy(&ptrCtx, &ctx, sizeof(ctx));
164     this->append(op, ptrCtx);
165 }
166 
extend(const SkRasterPipeline & src)167 void SkRasterPipeline::extend(const SkRasterPipeline& src) {
168     if (src.empty()) {
169         return;
170     }
171     // Create a rewind context if `src` has one already, but we don't. If we _do_ already have one,
172     // we need to keep it, since we already have rewind ops that reference it. Either way, we need
173     // to rewrite all the rewind ops to point to _our_ rewind context; we only get that checkpoint.
174     if (src.fRewindCtx && !fRewindCtx) {
175         fRewindCtx = fAlloc->make<SkRasterPipeline_RewindCtx>();
176     }
177     auto stages = fAlloc->makeArrayDefault<StageList>(src.fNumStages);
178 
179     int n = src.fNumStages;
180     const StageList* st = src.fStages;
181     while (n --> 1) {
182         stages[n]      = *st;
183         stages[n].prev = &stages[n-1];
184 
185         // We make sure that all ops use _our_ stack context and tail pointer.
186         switch (stages[n].stage) {
187             case Op::stack_rewind: {
188                 stages[n].ctx = fRewindCtx;
189                 break;
190             }
191             case Op::init_lane_masks: {
192                 auto* ctx = (SkRasterPipeline_InitLaneMasksCtx*)stages[n].ctx;
193                 ctx->tail = this->tailPointer();
194                 break;
195             }
196             case Op::branch_if_all_lanes_active: {
197                 auto* ctx = (SkRasterPipeline_BranchIfAllLanesActiveCtx*)stages[n].ctx;
198                 ctx->tail = this->tailPointer();
199                 break;
200             }
201             default:
202                 break;
203         }
204 
205         st = st->prev;
206     }
207     stages[0]      = *st;
208     stages[0].prev = fStages;
209 
210     fStages = &stages[src.fNumStages - 1];
211     fNumStages += src.fNumStages;
212     for (const SkRasterPipeline_MemoryCtxInfo& info : src.fMemoryCtxInfos) {
213         this->addMemoryContext(info.context, info.bytesPerPixel, info.load, info.store);
214     }
215 }
216 
GetOpName(SkRasterPipelineOp op)217 const char* SkRasterPipeline::GetOpName(SkRasterPipelineOp op) {
218     const char* name = "";
219     switch (op) {
220     #define M(x) case Op::x: name = #x; break;
221         SK_RASTER_PIPELINE_OPS_ALL(M)
222     #undef M
223     }
224     return name;
225 }
226 
dump() const227 void SkRasterPipeline::dump() const {
228     SkDebugf("SkRasterPipeline, %d stages\n", fNumStages);
229     std::vector<const char*> stages;
230     for (auto st = fStages; st; st = st->prev) {
231         stages.push_back(GetOpName(st->stage));
232     }
233     std::reverse(stages.begin(), stages.end());
234     for (const char* name : stages) {
235         SkDebugf("\t%s\n", name);
236     }
237     SkDebugf("\n");
238 }
239 
appendSetRGB(SkArenaAlloc * alloc,const float rgb[3])240 void SkRasterPipeline::appendSetRGB(SkArenaAlloc* alloc, const float rgb[3]) {
241     auto arg = alloc->makeArrayDefault<float>(3);
242     arg[0] = rgb[0];
243     arg[1] = rgb[1];
244     arg[2] = rgb[2];
245 
246     auto op = Op::unbounded_set_rgb;
247     if (0 <= rgb[0] && rgb[0] <= 1 &&
248         0 <= rgb[1] && rgb[1] <= 1 &&
249         0 <= rgb[2] && rgb[2] <= 1)
250     {
251         op = Op::set_rgb;
252     }
253 
254     this->uncheckedAppend(op, arg);
255 }
256 
appendConstantColor(SkArenaAlloc * alloc,const float rgba[4])257 void SkRasterPipeline::appendConstantColor(SkArenaAlloc* alloc, const float rgba[4]) {
258     // r,g,b might be outside [0,1], but alpha should probably always be in [0,1].
259     SkASSERT(0 <= rgba[3] && rgba[3] <= 1);
260 
261     if (rgba[0] == 0 && rgba[1] == 0 && rgba[2] == 0 && rgba[3] == 1) {
262         this->append(Op::black_color);
263     } else if (rgba[0] == 1 && rgba[1] == 1 && rgba[2] == 1 && rgba[3] == 1) {
264         this->append(Op::white_color);
265     } else {
266         auto ctx = alloc->make<SkRasterPipeline_UniformColorCtx>();
267         skvx::float4 color = skvx::float4::Load(rgba);
268         color.store(&ctx->r);
269 
270         // uniform_color requires colors in range and can go lowp,
271         // while unbounded_uniform_color supports out-of-range colors too but not lowp.
272         if (0 <= rgba[0] && rgba[0] <= rgba[3] &&
273             0 <= rgba[1] && rgba[1] <= rgba[3] &&
274             0 <= rgba[2] && rgba[2] <= rgba[3]) {
275             // To make loads more direct, we store 8-bit values in 16-bit slots.
276             color = color * 255.0f + 0.5f;
277             ctx->rgba[0] = (uint16_t)color[0];
278             ctx->rgba[1] = (uint16_t)color[1];
279             ctx->rgba[2] = (uint16_t)color[2];
280             ctx->rgba[3] = (uint16_t)color[3];
281             this->uncheckedAppend(Op::uniform_color, ctx);
282         } else {
283             this->uncheckedAppend(Op::unbounded_uniform_color, ctx);
284         }
285     }
286 }
287 
appendMatrix(SkArenaAlloc * alloc,const SkMatrix & matrix)288 void SkRasterPipeline::appendMatrix(SkArenaAlloc* alloc, const SkMatrix& matrix) {
289     SkMatrix::TypeMask mt = matrix.getType();
290 
291     if (mt == SkMatrix::kIdentity_Mask) {
292         return;
293     }
294     if (mt == SkMatrix::kTranslate_Mask) {
295         float* trans = alloc->makeArrayDefault<float>(2);
296         trans[0] = matrix.getTranslateX();
297         trans[1] = matrix.getTranslateY();
298         this->append(Op::matrix_translate, trans);
299     } else if ((mt | (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) ==
300                      (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
301         float* scaleTrans = alloc->makeArrayDefault<float>(4);
302         scaleTrans[0] = matrix.getScaleX();
303         scaleTrans[1] = matrix.getScaleY();
304         scaleTrans[2] = matrix.getTranslateX();
305         scaleTrans[3] = matrix.getTranslateY();
306         this->append(Op::matrix_scale_translate, scaleTrans);
307     } else {
308         float* storage = alloc->makeArrayDefault<float>(9);
309         matrix.get9(storage);
310         if (!matrix.hasPerspective()) {
311             // note: asAffine and the 2x3 stage really only need 6 entries
312             this->append(Op::matrix_2x3, storage);
313         } else {
314             this->append(Op::matrix_perspective, storage);
315         }
316     }
317 }
318 
appendLoad(SkColorType ct,const SkRasterPipeline_MemoryCtx * ctx)319 void SkRasterPipeline::appendLoad(SkColorType ct, const SkRasterPipeline_MemoryCtx* ctx) {
320     switch (ct) {
321         case kUnknown_SkColorType: SkASSERT(false); break;
322 
323         case kAlpha_8_SkColorType:           this->append(Op::load_a8,      ctx); break;
324         case kA16_unorm_SkColorType:         this->append(Op::load_a16,     ctx); break;
325         case kA16_float_SkColorType:         this->append(Op::load_af16,    ctx); break;
326         case kRGB_565_SkColorType:           this->append(Op::load_565,     ctx); break;
327         case kARGB_4444_SkColorType:         this->append(Op::load_4444,    ctx); break;
328         case kR8G8_unorm_SkColorType:        this->append(Op::load_rg88,    ctx); break;
329         case kR16G16_unorm_SkColorType:      this->append(Op::load_rg1616,  ctx); break;
330         case kR16G16_float_SkColorType:      this->append(Op::load_rgf16,   ctx); break;
331         case kRGBA_8888_SkColorType:         this->append(Op::load_8888,    ctx); break;
332         case kRGBA_1010102_SkColorType:      this->append(Op::load_1010102, ctx); break;
333         case kR16G16B16A16_unorm_SkColorType:this->append(Op::load_16161616,ctx); break;
334         case kRGBA_F16Norm_SkColorType:
335         case kRGBA_F16_SkColorType:          this->append(Op::load_f16,     ctx); break;
336         case kRGBA_F32_SkColorType:          this->append(Op::load_f32,     ctx); break;
337         case kRGBA_10x6_SkColorType:         this->append(Op::load_10x6,    ctx); break;
338 
339         case kGray_8_SkColorType:            this->append(Op::load_a8, ctx);
340                                              this->append(Op::alpha_to_gray);
341                                              break;
342 
343         case kR8_unorm_SkColorType:          this->append(Op::load_a8, ctx);
344                                              this->append(Op::alpha_to_red);
345                                              break;
346 
347         case kRGB_888x_SkColorType:          this->append(Op::load_8888, ctx);
348                                              this->append(Op::force_opaque);
349                                              break;
350 
351         case kBGRA_1010102_SkColorType:      this->append(Op::load_1010102, ctx);
352                                              this->append(Op::swap_rb);
353                                              break;
354 
355         case kRGB_101010x_SkColorType:       this->append(Op::load_1010102, ctx);
356                                              this->append(Op::force_opaque);
357                                              break;
358 
359         case kBGR_101010x_SkColorType:       this->append(Op::load_1010102, ctx);
360                                              this->append(Op::force_opaque);
361                                              this->append(Op::swap_rb);
362                                              break;
363 
364         case kBGRA_10101010_XR_SkColorType:  this->append(Op::load_10101010_xr, ctx);
365                                              this->append(Op::swap_rb);
366                                              break;
367 
368         case kBGR_101010x_XR_SkColorType:    this->append(Op::load_1010102_xr, ctx);
369                                              this->append(Op::force_opaque);
370                                              this->append(Op::swap_rb);
371                                              break;
372 
373         case kBGRA_8888_SkColorType:         this->append(Op::load_8888, ctx);
374                                              this->append(Op::swap_rb);
375                                              break;
376 
377         case kSRGBA_8888_SkColorType:
378             this->append(Op::load_8888, ctx);
379             this->appendTransferFunction(*skcms_sRGB_TransferFunction());
380             break;
381     }
382 }
383 
appendLoadDst(SkColorType ct,const SkRasterPipeline_MemoryCtx * ctx)384 void SkRasterPipeline::appendLoadDst(SkColorType ct, const SkRasterPipeline_MemoryCtx* ctx) {
385     switch (ct) {
386         case kUnknown_SkColorType: SkASSERT(false); break;
387 
388         case kAlpha_8_SkColorType:            this->append(Op::load_a8_dst,      ctx); break;
389         case kA16_unorm_SkColorType:          this->append(Op::load_a16_dst,     ctx); break;
390         case kA16_float_SkColorType:          this->append(Op::load_af16_dst,    ctx); break;
391         case kRGB_565_SkColorType:            this->append(Op::load_565_dst,     ctx); break;
392         case kARGB_4444_SkColorType:          this->append(Op::load_4444_dst,    ctx); break;
393         case kR8G8_unorm_SkColorType:         this->append(Op::load_rg88_dst,    ctx); break;
394         case kR16G16_unorm_SkColorType:       this->append(Op::load_rg1616_dst,  ctx); break;
395         case kR16G16_float_SkColorType:       this->append(Op::load_rgf16_dst,   ctx); break;
396         case kRGBA_8888_SkColorType:          this->append(Op::load_8888_dst,    ctx); break;
397         case kRGBA_1010102_SkColorType:       this->append(Op::load_1010102_dst, ctx); break;
398         case kR16G16B16A16_unorm_SkColorType: this->append(Op::load_16161616_dst,ctx); break;
399         case kRGBA_F16Norm_SkColorType:
400         case kRGBA_F16_SkColorType:           this->append(Op::load_f16_dst,     ctx); break;
401         case kRGBA_F32_SkColorType:           this->append(Op::load_f32_dst,     ctx); break;
402         case kRGBA_10x6_SkColorType:          this->append(Op::load_10x6_dst,    ctx); break;
403 
404         case kGray_8_SkColorType:             this->append(Op::load_a8_dst, ctx);
405                                               this->append(Op::alpha_to_gray_dst);
406                                               break;
407 
408         case kR8_unorm_SkColorType:           this->append(Op::load_a8_dst, ctx);
409                                               this->append(Op::alpha_to_red_dst);
410                                               break;
411 
412         case kRGB_888x_SkColorType:           this->append(Op::load_8888_dst, ctx);
413                                               this->append(Op::force_opaque_dst);
414                                               break;
415 
416         case kBGRA_1010102_SkColorType:       this->append(Op::load_1010102_dst, ctx);
417                                               this->append(Op::swap_rb_dst);
418                                               break;
419 
420         case kRGB_101010x_SkColorType:        this->append(Op::load_1010102_dst, ctx);
421                                               this->append(Op::force_opaque_dst);
422                                               break;
423 
424         case kBGR_101010x_SkColorType:        this->append(Op::load_1010102_dst, ctx);
425                                               this->append(Op::force_opaque_dst);
426                                               this->append(Op::swap_rb_dst);
427                                               break;
428 
429         case kBGR_101010x_XR_SkColorType:     this->append(Op::load_1010102_xr_dst, ctx);
430                                               this->append(Op::force_opaque_dst);
431                                               this->append(Op::swap_rb_dst);
432                                               break;
433 
434         case kBGRA_10101010_XR_SkColorType:   this->append(Op::load_10101010_xr_dst, ctx);
435                                               this->append(Op::swap_rb_dst);
436                                               break;
437 
438         case kBGRA_8888_SkColorType:          this->append(Op::load_8888_dst, ctx);
439                                               this->append(Op::swap_rb_dst);
440                                               break;
441 
442         case kSRGBA_8888_SkColorType:
443             // TODO: We could remove the double-swap if we had _dst versions of all the TF stages
444             this->append(Op::load_8888_dst, ctx);
445             this->append(Op::swap_src_dst);
446             this->appendTransferFunction(*skcms_sRGB_TransferFunction());
447             this->append(Op::swap_src_dst);
448             break;
449     }
450 }
451 
appendStore(SkColorType ct,const SkRasterPipeline_MemoryCtx * ctx)452 void SkRasterPipeline::appendStore(SkColorType ct, const SkRasterPipeline_MemoryCtx* ctx) {
453     switch (ct) {
454         case kUnknown_SkColorType: SkASSERT(false); break;
455 
456         case kAlpha_8_SkColorType:            this->append(Op::store_a8,      ctx); break;
457         case kR8_unorm_SkColorType:           this->append(Op::store_r8,      ctx); break;
458         case kA16_unorm_SkColorType:          this->append(Op::store_a16,     ctx); break;
459         case kA16_float_SkColorType:          this->append(Op::store_af16,    ctx); break;
460         case kRGB_565_SkColorType:            this->append(Op::store_565,     ctx); break;
461         case kARGB_4444_SkColorType:          this->append(Op::store_4444,    ctx); break;
462         case kR8G8_unorm_SkColorType:         this->append(Op::store_rg88,    ctx); break;
463         case kR16G16_unorm_SkColorType:       this->append(Op::store_rg1616,  ctx); break;
464         case kR16G16_float_SkColorType:       this->append(Op::store_rgf16,   ctx); break;
465         case kRGBA_8888_SkColorType:          this->append(Op::store_8888,    ctx); break;
466         case kRGBA_1010102_SkColorType:       this->append(Op::store_1010102, ctx); break;
467         case kR16G16B16A16_unorm_SkColorType: this->append(Op::store_16161616,ctx); break;
468         case kRGBA_F16Norm_SkColorType:
469         case kRGBA_F16_SkColorType:           this->append(Op::store_f16,     ctx); break;
470         case kRGBA_F32_SkColorType:           this->append(Op::store_f32,     ctx); break;
471         case kRGBA_10x6_SkColorType:          this->append(Op::store_10x6,    ctx); break;
472 
473         case kRGB_888x_SkColorType:           this->append(Op::force_opaque);
474                                               this->append(Op::store_8888, ctx);
475                                               break;
476 
477         case kBGRA_1010102_SkColorType:       this->append(Op::swap_rb);
478                                               this->append(Op::store_1010102, ctx);
479                                               break;
480 
481         case kRGB_101010x_SkColorType:        this->append(Op::force_opaque);
482                                               this->append(Op::store_1010102, ctx);
483                                               break;
484 
485         case kBGR_101010x_SkColorType:        this->append(Op::force_opaque);
486                                               this->append(Op::swap_rb);
487                                               this->append(Op::store_1010102, ctx);
488                                               break;
489 
490         case kBGR_101010x_XR_SkColorType:     this->append(Op::force_opaque);
491                                               this->append(Op::swap_rb);
492                                               this->append(Op::store_1010102_xr, ctx);
493                                               break;
494 
495         case kBGRA_10101010_XR_SkColorType:   this->append(Op::swap_rb);
496                                               this->append(Op::store_10101010_xr, ctx);
497                                               break;
498 
499         case kGray_8_SkColorType:             this->append(Op::bt709_luminance_or_luma_to_alpha);
500                                               this->append(Op::store_a8, ctx);
501                                               break;
502 
503         case kBGRA_8888_SkColorType:          this->append(Op::swap_rb);
504                                               this->append(Op::store_8888, ctx);
505                                               break;
506 
507         case kSRGBA_8888_SkColorType:
508             this->appendTransferFunction(*skcms_sRGB_Inverse_TransferFunction());
509             this->append(Op::store_8888, ctx);
510             break;
511     }
512 }
513 
appendTransferFunction(const skcms_TransferFunction & tf)514 void SkRasterPipeline::appendTransferFunction(const skcms_TransferFunction& tf) {
515     void* ctx = const_cast<void*>(static_cast<const void*>(&tf));
516     switch (skcms_TransferFunction_getType(&tf)) {
517         case skcms_TFType_Invalid: SkASSERT(false); break;
518 
519         case skcms_TFType_sRGBish:
520             if (tf.a == 1 && tf.b == 0 && tf.c == 0 && tf.d == 0 && tf.e == 0 && tf.f == 0) {
521                 this->uncheckedAppend(Op::gamma_, ctx);
522             } else {
523                 this->uncheckedAppend(Op::parametric, ctx);
524             }
525             break;
526         case skcms_TFType_PQish:     this->uncheckedAppend(Op::PQish,     ctx); break;
527         case skcms_TFType_HLGish:    this->uncheckedAppend(Op::HLGish,    ctx); break;
528         case skcms_TFType_HLGinvish: this->uncheckedAppend(Op::HLGinvish, ctx); break;
529     }
530 }
531 
532 // GPUs clamp all color channels to the limits of the format just before the blend step. To match
533 // that auto-clamp, the RP blitter uses this helper immediately before appending blending stages.
appendClampIfNormalized(const SkImageInfo & info)534 void SkRasterPipeline::appendClampIfNormalized(const SkImageInfo& info) {
535     if (SkColorTypeIsNormalized(info.colorType())) {
536         this->uncheckedAppend(Op::clamp_01, nullptr);
537     }
538 }
539 
appendStackRewind()540 void SkRasterPipeline::appendStackRewind() {
541     if (!fRewindCtx) {
542         fRewindCtx = fAlloc->make<SkRasterPipeline_RewindCtx>();
543     }
544     this->uncheckedAppend(Op::stack_rewind, fRewindCtx);
545 }
546 
prepend_to_pipeline(SkRasterPipelineStage * & ip,SkOpts::StageFn stageFn,void * ctx)547 static void prepend_to_pipeline(SkRasterPipelineStage*& ip, SkOpts::StageFn stageFn, void* ctx) {
548     --ip;
549     ip->fn = stageFn;
550     ip->ctx = ctx;
551 }
552 
buildLowpPipeline(SkRasterPipelineStage * ip) const553 bool SkRasterPipeline::buildLowpPipeline(SkRasterPipelineStage* ip) const {
554     if (gForceHighPrecisionRasterPipeline || fRewindCtx) {
555         return false;
556     }
557     // Stages are stored backwards in fStages; to compensate, we assemble the pipeline in reverse
558     // here, back to front.
559     prepend_to_pipeline(ip, SkOpts::just_return_lowp, /*ctx=*/nullptr);
560     for (const StageList* st = fStages; st; st = st->prev) {
561         int opIndex = (int)st->stage;
562         if (opIndex >= kNumRasterPipelineLowpOps || !SkOpts::ops_lowp[opIndex]) {
563             // This program contains a stage that doesn't exist in lowp.
564             return false;
565         }
566         prepend_to_pipeline(ip, SkOpts::ops_lowp[opIndex], st->ctx);
567     }
568     return true;
569 }
570 
buildHighpPipeline(SkRasterPipelineStage * ip) const571 void SkRasterPipeline::buildHighpPipeline(SkRasterPipelineStage* ip) const {
572     // We assemble the pipeline in reverse, since the stage list is stored backwards.
573     prepend_to_pipeline(ip, SkOpts::just_return_highp, /*ctx=*/nullptr);
574     for (const StageList* st = fStages; st; st = st->prev) {
575         int opIndex = (int)st->stage;
576         prepend_to_pipeline(ip, SkOpts::ops_highp[opIndex], st->ctx);
577     }
578 
579     // stack_checkpoint and stack_rewind are only implemented in highp. We only need these stages
580     // when generating long (or looping) pipelines from SkSL. The other stages used by the SkSL
581     // Raster Pipeline generator will only have highp implementations, because we can't execute SkSL
582     // code without floating point.
583     if (fRewindCtx) {
584         const int rewindIndex = (int)Op::stack_checkpoint;
585         prepend_to_pipeline(ip, SkOpts::ops_highp[rewindIndex], fRewindCtx);
586     }
587 }
588 
buildPipeline(SkRasterPipelineStage * ip) const589 SkRasterPipeline::StartPipelineFn SkRasterPipeline::buildPipeline(SkRasterPipelineStage* ip) const {
590     // We try to build a lowp pipeline first; if that fails, we fall back to a highp float pipeline.
591     if (this->buildLowpPipeline(ip)) {
592         return SkOpts::start_pipeline_lowp;
593     }
594 
595     this->buildHighpPipeline(ip);
596     return SkOpts::start_pipeline_highp;
597 }
598 
stagesNeeded() const599 int SkRasterPipeline::stagesNeeded() const {
600     // Add 1 to budget for a `just_return` stage at the end.
601     int stages = fNumStages + 1;
602 
603     // If we have any stack_rewind stages, we will need to inject a stack_checkpoint stage.
604     if (fRewindCtx) {
605         stages += 1;
606     }
607     return stages;
608 }
609 
run(size_t x,size_t y,size_t w,size_t h) const610 void SkRasterPipeline::run(size_t x, size_t y, size_t w, size_t h) const {
611     if (this->empty()) {
612         return;
613     }
614 
615     int stagesNeeded = this->stagesNeeded();
616 
617     // Best to not use fAlloc here... we can't bound how often run() will be called.
618     AutoSTMalloc<32, SkRasterPipelineStage> program(stagesNeeded);
619 
620     int numMemoryCtxs = fMemoryCtxInfos.size();
621     AutoSTMalloc<2, SkRasterPipeline_MemoryCtxPatch> patches(numMemoryCtxs);
622     for (int i = 0; i < numMemoryCtxs; ++i) {
623         patches[i].info = fMemoryCtxInfos[i];
624         patches[i].backup = nullptr;
625         memset(patches[i].scratch, 0, sizeof(patches[i].scratch));
626     }
627 
628     auto start_pipeline = this->buildPipeline(program.get() + stagesNeeded);
629     start_pipeline(x, y, x + w, y + h, program.get(),
630                    SkSpan{patches.data(), numMemoryCtxs},
631                    fTailPointer);
632 }
633 
compile() const634 std::function<void(size_t, size_t, size_t, size_t)> SkRasterPipeline::compile() const {
635     if (this->empty()) {
636         return [](size_t, size_t, size_t, size_t) {};
637     }
638 
639     int stagesNeeded = this->stagesNeeded();
640 
641     SkRasterPipelineStage* program = fAlloc->makeArray<SkRasterPipelineStage>(stagesNeeded);
642 
643     int numMemoryCtxs = fMemoryCtxInfos.size();
644     SkRasterPipeline_MemoryCtxPatch* patches =
645             fAlloc->makeArray<SkRasterPipeline_MemoryCtxPatch>(numMemoryCtxs);
646     for (int i = 0; i < numMemoryCtxs; ++i) {
647         patches[i].info = fMemoryCtxInfos[i];
648         patches[i].backup = nullptr;
649         memset(patches[i].scratch, 0, sizeof(patches[i].scratch));
650     }
651     uint8_t* tailPointer = fTailPointer;
652 
653     auto start_pipeline = this->buildPipeline(program + stagesNeeded);
654     return [=](size_t x, size_t y, size_t w, size_t h) {
655         start_pipeline(x, y, x + w, y + h, program,
656                        SkSpan{patches, numMemoryCtxs},
657                        tailPointer);
658     };
659 }
660 
addMemoryContext(SkRasterPipeline_MemoryCtx * ctx,int bytesPerPixel,bool load,bool store)661 void SkRasterPipeline::addMemoryContext(SkRasterPipeline_MemoryCtx* ctx,
662                                         int bytesPerPixel,
663                                         bool load,
664                                         bool store) {
665     SkRasterPipeline_MemoryCtxInfo* info =
666             std::find_if(fMemoryCtxInfos.begin(), fMemoryCtxInfos.end(),
667                          [=](const SkRasterPipeline_MemoryCtxInfo& i) { return i.context == ctx; });
668     if (info != fMemoryCtxInfos.end()) {
669         SkASSERT(bytesPerPixel == info->bytesPerPixel);
670         info->load = info->load || load;
671         info->store = info->store || store;
672     } else {
673         fMemoryCtxInfos.push_back(SkRasterPipeline_MemoryCtxInfo{ctx, bytesPerPixel, load, store});
674     }
675 }
676