LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkRecordOpts.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 103 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : // Most of the optimizations in this file are pattern-based.  These are all defined as structs with:
      17             : //   - a Match typedef
      18             : //   - a bool onMatch(SkRceord*, Match*, int begin, int end) method,
      19             : //     which returns true if it made changes and false if not.
      20             : 
      21             : // Run a pattern-based optimization once across the SkRecord, returning true if it made any changes.
      22             : // It looks for spans which match Pass::Match, and when found calls onMatch() with that pattern,
      23             : // record, and [begin,end) span of the commands that matched.
      24             : template <typename Pass>
      25           0 : static bool apply(Pass* pass, SkRecord* record) {
      26           0 :     typename Pass::Match match;
      27           0 :     bool changed = false;
      28           0 :     int begin, end = 0;
      29             : 
      30           0 :     while (match.search(record, &begin, &end)) {
      31           0 :         changed |= pass->onMatch(record, &match, begin, end);
      32             :     }
      33           0 :     return changed;
      34             : }
      35             : 
      36             : ///////////////////////////////////////////////////////////////////////////////////////////////////
      37             : 
      38           0 : static void multiple_set_matrices(SkRecord* record) {
      39             :     struct {
      40             :         typedef Pattern<Is<SetMatrix>,
      41             :                         Greedy<Is<NoOp>>,
      42             :                         Is<SetMatrix> >
      43             :             Match;
      44             : 
      45           0 :         bool onMatch(SkRecord* record, Match* pattern, int begin, int end) {
      46           0 :             record->replace<NoOp>(begin);  // first SetMatrix
      47           0 :             return true;
      48             :         }
      49             :     } pass;
      50           0 :     while (apply(&pass, record));
      51           0 : }
      52             : 
      53             : ///////////////////////////////////////////////////////////////////////////////////////////////////
      54             : 
      55             : #if 0   // experimental, but needs knowledge of previous matrix to operate correctly
      56             : static void apply_matrix_to_draw_params(SkRecord* record) {
      57             :     struct {
      58             :         typedef Pattern<Is<SetMatrix>,
      59             :                         Greedy<Is<NoOp>>,
      60             :                         Is<SetMatrix> >
      61             :             Pattern;
      62             : 
      63             :         bool onMatch(SkRecord* record, Pattern* pattern, int begin, int end) {
      64             :             record->replace<NoOp>(begin);  // first SetMatrix
      65             :             return true;
      66             :         }
      67             :     } pass;
      68             :     // No need to loop, as we never "open up" opportunities for more of this type of optimization.
      69             :     apply(&pass, record);
      70             : }
      71             : #endif
      72             : 
      73             : ///////////////////////////////////////////////////////////////////////////////////////////////////
      74             : 
      75             : // Turns the logical NoOp Save and Restore in Save-Draw*-Restore patterns into actual NoOps.
      76             : struct SaveOnlyDrawsRestoreNooper {
      77             :     typedef Pattern<Is<Save>,
      78             :                     Greedy<Or<Is<NoOp>, IsDraw>>,
      79             :                     Is<Restore>>
      80             :         Match;
      81             : 
      82           0 :     bool onMatch(SkRecord* record, Match*, int begin, int end) {
      83           0 :         record->replace<NoOp>(begin);  // Save
      84           0 :         record->replace<NoOp>(end-1);  // Restore
      85           0 :         return true;
      86             :     }
      87             : };
      88             : 
      89           0 : static bool fold_opacity_layer_color_to_paint(const SkPaint* layerPaint,
      90             :                                               bool isSaveLayer,
      91             :                                               SkPaint* paint) {
      92             :     // We assume layerPaint is always from a saveLayer.  If isSaveLayer is
      93             :     // true, we assume paint is too.
      94             : 
      95             :     // The alpha folding can proceed if the filter layer paint does not have properties which cause
      96             :     // the resulting filter layer to be "blended" in complex ways to the parent layer. For example,
      97             :     // looper drawing unmodulated filter layer twice and then modulating the result produces
      98             :     // different image to drawing modulated filter layer twice.
      99             :     // TODO: most likely the looper and only some xfer modes are the hard constraints
     100           0 :     if (!paint->isSrcOver() || paint->getLooper()) {
     101           0 :         return false;
     102             :     }
     103             : 
     104           0 :     if (!isSaveLayer && paint->getImageFilter()) {
     105             :         // For normal draws, the paint color is used as one input for the color for the draw. Image
     106             :         // filter will operate on the result, and thus we can not change the input.
     107             :         // For layer saves, the image filter is applied to the layer contents. The layer is then
     108             :         // modulated with the paint color, so it's fine to proceed with the fold for saveLayer
     109             :         // paints with image filters.
     110           0 :         return false;
     111             :     }
     112             : 
     113           0 :     if (paint->getColorFilter()) {
     114             :         // Filter input depends on the paint color.
     115             : 
     116             :         // Here we could filter the color if we knew the draw is going to be uniform color.  This
     117             :         // should be detectable as drawPath/drawRect/.. without a shader being uniform, while
     118             :         // drawBitmap/drawSprite or a shader being non-uniform. However, current matchers don't
     119             :         // give the type out easily, so just do not optimize that at the moment.
     120           0 :         return false;
     121             :     }
     122             : 
     123           0 :     if (layerPaint) {
     124           0 :         const uint32_t layerColor = layerPaint->getColor();
     125             :         // The layer paint color must have only alpha component.
     126           0 :         if (SK_ColorTRANSPARENT != SkColorSetA(layerColor, SK_AlphaTRANSPARENT)) {
     127           0 :             return false;
     128             :         }
     129             : 
     130             :         // The layer paint can not have any effects.
     131           0 :         if (layerPaint->getPathEffect()  ||
     132           0 :             layerPaint->getShader()      ||
     133           0 :             !layerPaint->isSrcOver()     ||
     134           0 :             layerPaint->getMaskFilter()  ||
     135           0 :             layerPaint->getColorFilter() ||
     136           0 :             layerPaint->getRasterizer()  ||
     137           0 :             layerPaint->getLooper()      ||
     138           0 :             layerPaint->getImageFilter()) {
     139           0 :             return false;
     140             :         }
     141           0 :         paint->setAlpha(SkMulDiv255Round(paint->getAlpha(), SkColorGetA(layerColor)));
     142             :     }
     143             : 
     144           0 :     return true;
     145             : }
     146             : 
     147             : // Turns logical no-op Save-[non-drawing command]*-Restore patterns into actual no-ops.
     148             : struct SaveNoDrawsRestoreNooper {
     149             :     // Greedy matches greedily, so we also have to exclude Save and Restore.
     150             :     // Nested SaveLayers need to be excluded, or we'll match their Restore!
     151             :     typedef Pattern<Is<Save>,
     152             :                     Greedy<Not<Or<Is<Save>,
     153             :                                   Is<SaveLayer>,
     154             :                                   Is<Restore>,
     155             :                                   IsDraw>>>,
     156             :                     Is<Restore>>
     157             :         Match;
     158             : 
     159           0 :     bool onMatch(SkRecord* record, Match*, int begin, int end) {
     160             :         // The entire span between Save and Restore (inclusively) does nothing.
     161           0 :         for (int i = begin; i < end; i++) {
     162           0 :             record->replace<NoOp>(i);
     163             :         }
     164           0 :         return true;
     165             :     }
     166             : };
     167           0 : void SkRecordNoopSaveRestores(SkRecord* record) {
     168             :     SaveOnlyDrawsRestoreNooper onlyDraws;
     169             :     SaveNoDrawsRestoreNooper noDraws;
     170             : 
     171             :     // Run until they stop changing things.
     172           0 :     while (apply(&onlyDraws, record) || apply(&noDraws, record));
     173           0 : }
     174             : 
     175             : #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
     176           0 : static bool effectively_srcover(const SkPaint* paint) {
     177           0 :     if (!paint || paint->isSrcOver()) {
     178           0 :         return true;
     179             :     }
     180             :     // src-mode with opaque and no effects (which might change opaqueness) is ok too.
     181           0 :     return !paint->getShader() && !paint->getColorFilter() && !paint->getImageFilter() &&
     182           0 :            0xFF == paint->getAlpha() && paint->getBlendMode() == SkBlendMode::kSrc;
     183             : }
     184             : 
     185             : // For some SaveLayer-[drawing command]-Restore patterns, merge the SaveLayer's alpha into the
     186             : // draw, and no-op the SaveLayer and Restore.
     187             : struct SaveLayerDrawRestoreNooper {
     188             :     typedef Pattern<Is<SaveLayer>, IsDraw, Is<Restore>> Match;
     189             : 
     190           0 :     bool onMatch(SkRecord* record, Match* match, int begin, int end) {
     191           0 :         if (match->first<SaveLayer>()->backdrop) {
     192             :             // can't throw away the layer if we have a backdrop
     193           0 :             return false;
     194             :         }
     195             : 
     196           0 :         if (match->first<SaveLayer>()->saveLayerFlags & (1U << 31)) {
     197             :             // can't throw away the layer if the kDontClipToLayer_PrivateSaveLayerFlag is set
     198           0 :             return false;
     199             :         }
     200             : 
     201             :         // A SaveLayer's bounds field is just a hint, so we should be free to ignore it.
     202           0 :         SkPaint* layerPaint = match->first<SaveLayer>()->paint;
     203           0 :         SkPaint* drawPaint = match->second<SkPaint>();
     204             : 
     205           0 :         if (nullptr == layerPaint && effectively_srcover(drawPaint)) {
     206             :             // There wasn't really any point to this SaveLayer at all.
     207           0 :             return KillSaveLayerAndRestore(record, begin);
     208             :         }
     209             : 
     210           0 :         if (drawPaint == nullptr) {
     211             :             // We can just give the draw the SaveLayer's paint.
     212             :             // TODO(mtklein): figure out how to do this clearly
     213           0 :             return false;
     214             :         }
     215             : 
     216           0 :         if (!fold_opacity_layer_color_to_paint(layerPaint, false /*isSaveLayer*/, drawPaint)) {
     217           0 :             return false;
     218             :         }
     219             : 
     220           0 :         return KillSaveLayerAndRestore(record, begin);
     221             :     }
     222             : 
     223           0 :     static bool KillSaveLayerAndRestore(SkRecord* record, int saveLayerIndex) {
     224           0 :         record->replace<NoOp>(saveLayerIndex);    // SaveLayer
     225           0 :         record->replace<NoOp>(saveLayerIndex+2);  // Restore
     226           0 :         return true;
     227             :     }
     228             : };
     229           0 : void SkRecordNoopSaveLayerDrawRestores(SkRecord* record) {
     230             :     SaveLayerDrawRestoreNooper pass;
     231           0 :     apply(&pass, record);
     232           0 : }
     233             : #endif
     234             : 
     235             : /* For SVG generated:
     236             :   SaveLayer (non-opaque, typically for CSS opacity)
     237             :     Save
     238             :       ClipRect
     239             :       SaveLayer (typically for SVG filter)
     240             :       Restore
     241             :     Restore
     242             :   Restore
     243             : */
     244             : struct SvgOpacityAndFilterLayerMergePass {
     245             :     typedef Pattern<Is<SaveLayer>, Is<Save>, Is<ClipRect>, Is<SaveLayer>,
     246             :                     Is<Restore>, Is<Restore>, Is<Restore>> Match;
     247             : 
     248           0 :     bool onMatch(SkRecord* record, Match* match, int begin, int end) {
     249           0 :         if (match->first<SaveLayer>()->backdrop) {
     250             :             // can't throw away the layer if we have a backdrop
     251           0 :             return false;
     252             :         }
     253             : 
     254           0 :         SkPaint* opacityPaint = match->first<SaveLayer>()->paint;
     255           0 :         if (nullptr == opacityPaint) {
     256             :             // There wasn't really any point to this SaveLayer at all.
     257           0 :             return KillSaveLayerAndRestore(record, begin);
     258             :         }
     259             : 
     260             :         // This layer typically contains a filter, but this should work for layers with for other
     261             :         // purposes too.
     262           0 :         SkPaint* filterLayerPaint = match->fourth<SaveLayer>()->paint;
     263           0 :         if (filterLayerPaint == nullptr) {
     264             :             // We can just give the inner SaveLayer the paint of the outer SaveLayer.
     265             :             // TODO(mtklein): figure out how to do this clearly
     266           0 :             return false;
     267             :         }
     268             : 
     269           0 :         if (!fold_opacity_layer_color_to_paint(opacityPaint, true /*isSaveLayer*/,
     270             :                                                filterLayerPaint)) {
     271           0 :             return false;
     272             :         }
     273             : 
     274           0 :         return KillSaveLayerAndRestore(record, begin);
     275             :     }
     276             : 
     277           0 :     static bool KillSaveLayerAndRestore(SkRecord* record, int saveLayerIndex) {
     278           0 :         record->replace<NoOp>(saveLayerIndex);     // SaveLayer
     279           0 :         record->replace<NoOp>(saveLayerIndex + 6); // Restore
     280           0 :         return true;
     281             :     }
     282             : };
     283             : 
     284           0 : void SkRecordMergeSvgOpacityAndFilterLayers(SkRecord* record) {
     285             :     SvgOpacityAndFilterLayerMergePass pass;
     286           0 :     apply(&pass, record);
     287           0 : }
     288             : 
     289             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     290             : 
     291           0 : void SkRecordOptimize(SkRecord* record) {
     292             :     // This might be useful  as a first pass in the future if we want to weed
     293             :     // out junk for other optimization passes.  Right now, nothing needs it,
     294             :     // and the bounding box hierarchy will do the work of skipping no-op
     295             :     // Save-NoDraw-Restore sequences better than we can here.
     296             :     // As there is a known problem with this peephole and drawAnnotation, disable this.
     297             :     // If we want to enable this we must first fix this bug:
     298             :     //     https://bugs.chromium.org/p/skia/issues/detail?id=5548
     299             : //    SkRecordNoopSaveRestores(record);
     300             : 
     301             :     // Turn off this optimization completely for Android framework
     302             :     // because it makes the following Android CTS test fail:
     303             :     // android.uirendering.cts.testclasses.LayerTests#testSaveLayerClippedWithAlpha
     304             : #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
     305           0 :     SkRecordNoopSaveLayerDrawRestores(record);
     306             : #endif
     307           0 :     SkRecordMergeSvgOpacityAndFilterLayers(record);
     308             : 
     309           0 :     record->defrag();
     310           0 : }
     311             : 
     312           0 : void SkRecordOptimize2(SkRecord* record) {
     313           0 :     multiple_set_matrices(record);
     314           0 :     SkRecordNoopSaveRestores(record);
     315             :     // See why we turn this off in SkRecordOptimize above.
     316             : #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
     317           0 :     SkRecordNoopSaveLayerDrawRestores(record);
     318             : #endif
     319           0 :     SkRecordMergeSvgOpacityAndFilterLayers(record);
     320             : 
     321           0 :     record->defrag();
     322           0 : }

Generated by: LCOV version 1.13