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 14 SkRasterPipeline::SkRasterPipeline(SkArenaAlloc* alloc) : fAlloc(alloc) { 15 this->reset(); 16 } 17 void SkRasterPipeline::reset() { 18 fStages = nullptr; 19 fNumStages = 0; 20 fSlotsNeeded = 1; // We always need one extra slot for just_return(). 21 } 22 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 } 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 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 55 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 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 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 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