Home | History | Annotate | Download | only in core
      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