Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2014 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 "SkRecordOpts.h"
      9 
     10 #include "SkRecordPattern.h"
     11 #include "SkRecords.h"
     12 #include "SkTDArray.h"
     13 
     14 using namespace SkRecords;
     15 
     16 void SkRecordOptimize(SkRecord* record) {
     17     // This might be useful  as a first pass in the future if we want to weed
     18     // out junk for other optimization passes.  Right now, nothing needs it,
     19     // and the bounding box hierarchy will do the work of skipping no-op
     20     // Save-NoDraw-Restore sequences better than we can here.
     21     //SkRecordNoopSaveRestores(record);
     22 
     23     SkRecordNoopSaveLayerDrawRestores(record);
     24 }
     25 
     26 // Most of the optimizations in this file are pattern-based.  These are all defined as structs with:
     27 //   - a Pattern typedef
     28 //   - a bool onMatch(SkRceord*, Pattern*, unsigned begin, unsigned end) method,
     29 //     which returns true if it made changes and false if not.
     30 
     31 // Run a pattern-based optimization once across the SkRecord, returning true if it made any changes.
     32 // It looks for spans which match Pass::Pattern, and when found calls onMatch() with the pattern,
     33 // record, and [begin,end) span of the commands that matched.
     34 template <typename Pass>
     35 static bool apply(Pass* pass, SkRecord* record) {
     36     typename Pass::Pattern pattern;
     37     bool changed = false;
     38     unsigned begin, end = 0;
     39 
     40     while (pattern.search(record, &begin, &end)) {
     41         changed |= pass->onMatch(record, &pattern, begin, end);
     42     }
     43     return changed;
     44 }
     45 
     46 // Turns the logical NoOp Save and Restore in Save-Draw*-Restore patterns into actual NoOps.
     47 struct SaveOnlyDrawsRestoreNooper {
     48     typedef Pattern3<Is<Save>,
     49                      Star<Or<Is<NoOp>, IsDraw> >,
     50                      Is<Restore> >
     51         Pattern;
     52 
     53     bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned end) {
     54         record->replace<NoOp>(begin);  // Save
     55         record->replace<NoOp>(end-1);  // Restore
     56         return true;
     57     }
     58 };
     59 // Turns logical no-op Save-[non-drawing command]*-Restore patterns into actual no-ops.
     60 struct SaveNoDrawsRestoreNooper {
     61     // Star matches greedily, so we also have to exclude Save and Restore.
     62     // Nested SaveLayers need to be excluded, or we'll match their Restore!
     63     typedef Pattern3<Is<Save>,
     64                      Star<Not<Or4<Is<Save>,
     65                                   Is<SaveLayer>,
     66                                   Is<Restore>,
     67                                   IsDraw> > >,
     68                      Is<Restore> >
     69         Pattern;
     70 
     71     bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned end) {
     72         // The entire span between Save and Restore (inclusively) does nothing.
     73         for (unsigned i = begin; i < end; i++) {
     74             record->replace<NoOp>(i);
     75         }
     76         return true;
     77     }
     78 };
     79 void SkRecordNoopSaveRestores(SkRecord* record) {
     80     SaveOnlyDrawsRestoreNooper onlyDraws;
     81     SaveNoDrawsRestoreNooper noDraws;
     82 
     83     // Run until they stop changing things.
     84     while (apply(&onlyDraws, record) || apply(&noDraws, record));
     85 }
     86 
     87 // For some SaveLayer-[drawing command]-Restore patterns, merge the SaveLayer's alpha into the
     88 // draw, and no-op the SaveLayer and Restore.
     89 struct SaveLayerDrawRestoreNooper {
     90     typedef Pattern3<Is<SaveLayer>, IsDraw, Is<Restore> > Pattern;
     91 
     92     bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned end) {
     93         SaveLayer* saveLayer = pattern->first<SaveLayer>();
     94         if (saveLayer->bounds != NULL) {
     95             // SaveLayer with bounds is too tricky for us.
     96             return false;
     97         }
     98 
     99         SkPaint* layerPaint = saveLayer->paint;
    100         if (NULL == layerPaint) {
    101             // There wasn't really any point to this SaveLayer at all.
    102             return KillSaveLayerAndRestore(record, begin);
    103         }
    104 
    105         SkPaint* drawPaint = pattern->second<SkPaint>();
    106         if (drawPaint == NULL) {
    107             // We can just give the draw the SaveLayer's paint.
    108             // TODO(mtklein): figure out how to do this clearly
    109             return false;
    110         }
    111 
    112         const uint32_t layerColor = layerPaint->getColor();
    113         const uint32_t  drawColor =  drawPaint->getColor();
    114         if (!IsOnlyAlpha(layerColor)  || !IsOpaque(drawColor) ||
    115             HasAnyEffect(*layerPaint) || HasAnyEffect(*drawPaint)) {
    116             // Too fancy for us.  Actually, as long as layerColor is just an alpha
    117             // we can blend it into drawColor's alpha; drawColor doesn't strictly have to be opaque.
    118             return false;
    119         }
    120 
    121         drawPaint->setColor(SkColorSetA(drawColor, SkColorGetA(layerColor)));
    122         return KillSaveLayerAndRestore(record, begin);
    123     }
    124 
    125     static bool KillSaveLayerAndRestore(SkRecord* record, unsigned saveLayerIndex) {
    126         record->replace<NoOp>(saveLayerIndex);    // SaveLayer
    127         record->replace<NoOp>(saveLayerIndex+2);  // Restore
    128         return true;
    129     }
    130 
    131     static bool HasAnyEffect(const SkPaint& paint) {
    132         return paint.getPathEffect()  ||
    133                paint.getShader()      ||
    134                paint.getXfermode()    ||
    135                paint.getMaskFilter()  ||
    136                paint.getColorFilter() ||
    137                paint.getRasterizer()  ||
    138                paint.getLooper()      ||
    139                paint.getImageFilter();
    140     }
    141 
    142     static bool IsOpaque(SkColor color) {
    143         return SkColorGetA(color) == SK_AlphaOPAQUE;
    144     }
    145     static bool IsOnlyAlpha(SkColor color) {
    146         return SK_ColorTRANSPARENT == SkColorSetA(color, SK_AlphaTRANSPARENT);
    147     }
    148 };
    149 void SkRecordNoopSaveLayerDrawRestores(SkRecord* record) {
    150     SaveLayerDrawRestoreNooper pass;
    151     apply(&pass, record);
    152 }
    153 
    154