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 #include "SkPM4fPriv.h"
11 #include "../jumper/SkJumper.h"
12 #include <algorithm>
13
SkRasterPipeline(SkArenaAlloc * alloc)14 SkRasterPipeline::SkRasterPipeline(SkArenaAlloc* alloc) : fAlloc(alloc) {
15 this->reset();
16 }
reset()17 void SkRasterPipeline::reset() {
18 fStages = nullptr;
19 fNumStages = 0;
20 fSlotsNeeded = 1; // We always need one extra slot for just_return().
21 }
22
append(StockStage stage,void * ctx)23 void SkRasterPipeline::append(StockStage stage, void* ctx) {
24 SkASSERT(stage != uniform_color); // Please use append_constant_color().
25 SkASSERT(stage != seed_shader); // Please use append_seed_shader().
26 this->unchecked_append(stage, ctx);
27 }
unchecked_append(StockStage stage,void * ctx)28 void SkRasterPipeline::unchecked_append(StockStage stage, void* ctx) {
29 fStages = fAlloc->make<StageList>( StageList{fStages, stage, ctx} );
30 fNumStages += 1;
31 fSlotsNeeded += ctx ? 2 : 1;
32 }
33
extend(const SkRasterPipeline & src)34 void SkRasterPipeline::extend(const SkRasterPipeline& src) {
35 if (src.empty()) {
36 return;
37 }
38 auto stages = fAlloc->makeArrayDefault<StageList>(src.fNumStages);
39
40 int n = src.fNumStages;
41 const StageList* st = src.fStages;
42 while (n --> 1) {
43 stages[n] = *st;
44 stages[n].prev = &stages[n-1];
45 st = st->prev;
46 }
47 stages[0] = *st;
48 stages[0].prev = fStages;
49
50 fStages = &stages[src.fNumStages - 1];
51 fNumStages += src.fNumStages;
52 fSlotsNeeded += src.fSlotsNeeded - 1; // Don't double count just_returns().
53 }
54
dump() const55 void SkRasterPipeline::dump() const {
56 SkDebugf("SkRasterPipeline, %d stages\n", fNumStages);
57 std::vector<const char*> stages;
58 for (auto st = fStages; st; st = st->prev) {
59 const char* name = "";
60 switch (st->stage) {
61 #define M(x) case x: name = #x; break;
62 SK_RASTER_PIPELINE_STAGES(M)
63 #undef M
64 }
65 stages.push_back(name);
66 }
67 std::reverse(stages.begin(), stages.end());
68 for (const char* name : stages) {
69 SkDebugf("\t%s\n", name);
70 }
71 SkDebugf("\n");
72 }
73
74 //#define TRACK_COLOR_HISTOGRAM
75 #ifdef TRACK_COLOR_HISTOGRAM
76 static int gBlack;
77 static int gWhite;
78 static int gColor;
79 #define INC_BLACK gBlack++
80 #define INC_WHITE gWhite++
81 #define INC_COLOR gColor++
82 #else
83 #define INC_BLACK
84 #define INC_WHITE
85 #define INC_COLOR
86 #endif
87
append_constant_color(SkArenaAlloc * alloc,const float rgba[4])88 void SkRasterPipeline::append_constant_color(SkArenaAlloc* alloc, const float rgba[4]) {
89 SkASSERT(0 <= rgba[0] && rgba[0] <= 1);
90 SkASSERT(0 <= rgba[1] && rgba[1] <= 1);
91 SkASSERT(0 <= rgba[2] && rgba[2] <= 1);
92 SkASSERT(0 <= rgba[3] && rgba[3] <= 1);
93
94 if (rgba[0] == 0 && rgba[1] == 0 && rgba[2] == 0 && rgba[3] == 1) {
95 this->append(black_color);
96 INC_BLACK;
97 } else if (rgba[0] == 1 && rgba[1] == 1 && rgba[2] == 1 && rgba[3] == 1) {
98 this->append(white_color);
99 INC_WHITE;
100 } else {
101 auto ctx = alloc->make<SkJumper_UniformColorCtx>();
102 Sk4f color = Sk4f::Load(rgba);
103 color.store(&ctx->r);
104
105 // To make loads more direct, we store 8-bit values in 16-bit slots.
106 color = color * 255.0f + 0.5f;
107 ctx->rgba[0] = (uint16_t)color[0];
108 ctx->rgba[1] = (uint16_t)color[1];
109 ctx->rgba[2] = (uint16_t)color[2];
110 ctx->rgba[3] = (uint16_t)color[3];
111
112 this->unchecked_append(uniform_color, ctx);
113 INC_COLOR;
114 }
115
116 #ifdef TRACK_COLOR_HISTOGRAM
117 SkDebugf("B=%d W=%d C=%d\n", gBlack, gWhite, gColor);
118 #endif
119 }
120
121 #undef INC_BLACK
122 #undef INC_WHITE
123 #undef INC_COLOR
124
125 //static int gCounts[5] = { 0, 0, 0, 0, 0 };
126
append_matrix(SkArenaAlloc * alloc,const SkMatrix & matrix)127 void SkRasterPipeline::append_matrix(SkArenaAlloc* alloc, const SkMatrix& matrix) {
128 SkMatrix::TypeMask mt = matrix.getType();
129 #if 0
130 if (mt > 4) mt = 4;
131 gCounts[mt] += 1;
132 SkDebugf("matrices: %d %d %d %d %d\n",
133 gCounts[0], gCounts[1], gCounts[2], gCounts[3], gCounts[4]);
134 #endif
135
136 // Based on a histogram of skps, we determined the following special cases were common, more
137 // or fewer can be used if client behaviors change.
138
139 if (mt == SkMatrix::kIdentity_Mask) {
140 return;
141 }
142 if (mt == SkMatrix::kTranslate_Mask) {
143 float* trans = alloc->makeArrayDefault<float>(2);
144 trans[0] = matrix.getTranslateX();
145 trans[1] = matrix.getTranslateY();
146 this->append(SkRasterPipeline::matrix_translate, trans);
147 } else if ((mt | (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) ==
148 (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
149 float* scaleTrans = alloc->makeArrayDefault<float>(4);
150 scaleTrans[0] = matrix.getScaleX();
151 scaleTrans[1] = matrix.getScaleY();
152 scaleTrans[2] = matrix.getTranslateX();
153 scaleTrans[3] = matrix.getTranslateY();
154 this->append(SkRasterPipeline::matrix_scale_translate, scaleTrans);
155 } else {
156 float* storage = alloc->makeArrayDefault<float>(9);
157 if (matrix.asAffine(storage)) {
158 // note: asAffine and the 2x3 stage really only need 6 entries
159 this->append(SkRasterPipeline::matrix_2x3, storage);
160 } else {
161 matrix.get9(storage);
162 this->append(SkRasterPipeline::matrix_perspective, storage);
163 }
164 }
165 }
166
append_seed_shader()167 void SkRasterPipeline::append_seed_shader() {
168 static const float iota[] = {
169 0.5f, 1.5f, 2.5f, 3.5f, 4.5f, 5.5f, 6.5f, 7.5f,
170 8.5f, 9.5f,10.5f,11.5f,12.5f,13.5f,14.5f,15.5f,
171 };
172 this->unchecked_append(SkRasterPipeline::seed_shader, const_cast<float*>(iota));
173 }
174