• 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 "SkRasterPipeline.h"
9 #include "SkPM4f.h"
10 
SkRasterPipeline(SkArenaAlloc * alloc)11 SkRasterPipeline::SkRasterPipeline(SkArenaAlloc* alloc) : fAlloc(alloc) {
12     this->reset();
13 }
reset()14 void SkRasterPipeline::reset() {
15     fStages      = nullptr;
16     fNumStages   = 0;
17     fSlotsNeeded = 1;  // We always need one extra slot for just_return().
18 }
19 
append(StockStage stage,void * ctx)20 void SkRasterPipeline::append(StockStage stage, void* ctx) {
21     SkASSERT(stage != from_srgb);
22     this->unchecked_append(stage, ctx);
23 }
unchecked_append(StockStage stage,void * ctx)24 void SkRasterPipeline::unchecked_append(StockStage stage, void* ctx) {
25     fStages = fAlloc->make<StageList>( StageList{fStages, stage, ctx} );
26     fNumStages   += 1;
27     fSlotsNeeded += ctx ? 2 : 1;
28 }
29 
extend(const SkRasterPipeline & src)30 void SkRasterPipeline::extend(const SkRasterPipeline& src) {
31     if (src.empty()) {
32         return;
33     }
34     auto stages = fAlloc->makeArrayDefault<StageList>(src.fNumStages);
35 
36     int n = src.fNumStages;
37     const StageList* st = src.fStages;
38     while (n --> 1) {
39         stages[n]      = *st;
40         stages[n].prev = &stages[n-1];
41         st = st->prev;
42     }
43     stages[0]      = *st;
44     stages[0].prev = fStages;
45 
46     fStages = &stages[src.fNumStages - 1];
47     fNumStages   += src.fNumStages;
48     fSlotsNeeded += src.fSlotsNeeded - 1;  // Don't double count just_returns().
49 }
50 
dump() const51 void SkRasterPipeline::dump() const {
52     SkDebugf("SkRasterPipeline, %d stages (in reverse)\n", fNumStages);
53     for (auto st = fStages; st; st = st->prev) {
54         const char* name = "";
55         switch (st->stage) {
56         #define M(x) case x: name = #x; break;
57             SK_RASTER_PIPELINE_STAGES(M)
58         #undef M
59         }
60         SkDebugf("\t%s\n", name);
61     }
62     SkDebugf("\n");
63 }
64 
65 //#define TRACK_COLOR_HISTOGRAM
66 #ifdef TRACK_COLOR_HISTOGRAM
67     static int gBlack;
68     static int gWhite;
69     static int gColor;
70     #define INC_BLACK   gBlack++
71     #define INC_WHITE   gWhite++
72     #define INC_COLOR   gColor++
73 #else
74     #define INC_BLACK
75     #define INC_WHITE
76     #define INC_COLOR
77 #endif
78 
append_uniform_color(SkArenaAlloc * alloc,const SkPM4f & c)79 void SkRasterPipeline::append_uniform_color(SkArenaAlloc* alloc, const SkPM4f& c) {
80     if (c.r() == 0 && c.g() == 0 && c.b() == 0 && c.a() == 1) {
81         this->append(black_color);
82         INC_BLACK;
83     } else if (c.r() == 1 && c.g() == 1 && c.b() == 1 && c.a() == 1) {
84         this->append(white_color);
85         INC_WHITE;
86     } else {
87         float* storage = alloc->makeArray<float>(4);
88         memcpy(storage, c.fVec, 4 * sizeof(float));
89         this->append(uniform_color, storage);
90         INC_COLOR;
91     }
92 
93 #ifdef TRACK_COLOR_HISTOGRAM
94     SkDebugf("B=%d W=%d C=%d\n", gBlack, gWhite, gColor);
95 #endif
96 }
97 
98 #undef INC_BLACK
99 #undef INC_WHITE
100 #undef INC_COLOR
101 
102 // It's pretty easy to start with sound premultiplied linear floats, pack those
103 // to sRGB encoded bytes, then read them back to linear floats and find them not
104 // quite premultiplied, with a color channel just a smidge greater than the alpha
105 // channel.  This can happen basically any time we have different transfer
106 // functions for alpha and colors... sRGB being the only one we draw into.
107 
108 // This is an annoying problem with no known good solution.  So apply the clamp hammer.
109 
append_from_srgb(SkAlphaType at)110 void SkRasterPipeline::append_from_srgb(SkAlphaType at) {
111     this->unchecked_append(from_srgb, nullptr);
112     if (at == kPremul_SkAlphaType) {
113         this->append(SkRasterPipeline::clamp_a);
114     }
115 }
116 
append_from_srgb_dst(SkAlphaType at)117 void SkRasterPipeline::append_from_srgb_dst(SkAlphaType at) {
118     this->unchecked_append(from_srgb_dst, nullptr);
119     if (at == kPremul_SkAlphaType) {
120         this->append(SkRasterPipeline::clamp_a_dst);
121     }
122 }
123 
124 //static int gCounts[5] = { 0, 0, 0, 0, 0 };
125 
append_matrix(SkArenaAlloc * alloc,const SkMatrix & matrix)126 void SkRasterPipeline::append_matrix(SkArenaAlloc* alloc, const SkMatrix& matrix) {
127     SkMatrix::TypeMask mt = matrix.getType();
128 #if 0
129     if (mt > 4) mt = 4;
130     gCounts[mt] += 1;
131     SkDebugf("matrices: %d %d %d %d %d\n",
132              gCounts[0], gCounts[1], gCounts[2], gCounts[3], gCounts[4]);
133 #endif
134 
135     // Based on a histogram of skps, we determined the following special cases were common, more
136     // or fewer can be used if client behaviors change.
137 
138     if (mt == SkMatrix::kIdentity_Mask) {
139         return;
140     }
141     if (mt == SkMatrix::kTranslate_Mask) {
142         float* trans = alloc->makeArrayDefault<float>(2);
143         trans[0] = matrix.getTranslateX();
144         trans[1] = matrix.getTranslateY();
145         this->append(SkRasterPipeline::matrix_translate, trans);
146     } else if ((mt | (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) ==
147                      (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
148         float* scaleTrans = alloc->makeArrayDefault<float>(4);
149         scaleTrans[0] = matrix.getTranslateX();
150         scaleTrans[1] = matrix.getTranslateY();
151         scaleTrans[2] = matrix.getScaleX();
152         scaleTrans[3] = matrix.getScaleY();
153         this->append(SkRasterPipeline::matrix_scale_translate, scaleTrans);
154     } else {
155         float* storage = alloc->makeArrayDefault<float>(9);
156         if (matrix.asAffine(storage)) {
157             // note: asAffine and the 2x3 stage really only need 6 entries
158             this->append(SkRasterPipeline::matrix_2x3, storage);
159         } else {
160             matrix.get9(storage);
161             this->append(SkRasterPipeline::matrix_perspective, storage);
162         }
163     }
164 }
165