1c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org/* 2c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org * Copyright 2014 Google Inc. 3c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org * 4c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org * Use of this source code is governed by a BSD-style license that can be 5c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org * found in the LICENSE file. 6c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org */ 7c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org 8ad8ce572f69633ffebe2fa486275d82a5e9a71fecommit-bot@chromium.org#include "SkRecordOpts.h" 9506db0b7d2905c6bedba9fc5d4aeaf231a9a34eacommit-bot@chromium.org 1073fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org#include "SkRecordPattern.h" 11506db0b7d2905c6bedba9fc5d4aeaf231a9a34eacommit-bot@chromium.org#include "SkRecords.h" 12506db0b7d2905c6bedba9fc5d4aeaf231a9a34eacommit-bot@chromium.org#include "SkTDArray.h" 13506db0b7d2905c6bedba9fc5d4aeaf231a9a34eacommit-bot@chromium.org 1473fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.orgusing namespace SkRecords; 1573fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org 16ad8ce572f69633ffebe2fa486275d82a5e9a71fecommit-bot@chromium.orgvoid SkRecordOptimize(SkRecord* record) { 171e78fc4ed2a1ef9f049311696ebd0a26e1c3782dmtklein // This might be useful as a first pass in the future if we want to weed 181e78fc4ed2a1ef9f049311696ebd0a26e1c3782dmtklein // out junk for other optimization passes. Right now, nothing needs it, 191e78fc4ed2a1ef9f049311696ebd0a26e1c3782dmtklein // and the bounding box hierarchy will do the work of skipping no-op 201e78fc4ed2a1ef9f049311696ebd0a26e1c3782dmtklein // Save-NoDraw-Restore sequences better than we can here. 211e78fc4ed2a1ef9f049311696ebd0a26e1c3782dmtklein //SkRecordNoopSaveRestores(record); 221e78fc4ed2a1ef9f049311696ebd0a26e1c3782dmtklein 2393f52a69443f9be16f4e98c21d1f6cf760a65f00mtklein SkRecordNoopSaveLayerDrawRestores(record); 24ad8ce572f69633ffebe2fa486275d82a5e9a71fecommit-bot@chromium.org} 25ad8ce572f69633ffebe2fa486275d82a5e9a71fecommit-bot@chromium.org 2673fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org// Most of the optimizations in this file are pattern-based. These are all defined as structs with: 2773fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org// - a Pattern typedef 2873fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org// - a bool onMatch(SkRceord*, Pattern*, unsigned begin, unsigned end) method, 2973fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org// which returns true if it made changes and false if not. 302e0c32af0508a1e544c9953ea2fe128dbae7d429commit-bot@chromium.org 3173fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org// Run a pattern-based optimization once across the SkRecord, returning true if it made any changes. 3273fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org// It looks for spans which match Pass::Pattern, and when found calls onMatch() with the pattern, 3373fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org// record, and [begin,end) span of the commands that matched. 3473fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.orgtemplate <typename Pass> 3573fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.orgstatic bool apply(Pass* pass, SkRecord* record) { 3673fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org typename Pass::Pattern pattern; 3773fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org bool changed = false; 3873fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org unsigned begin, end = 0; 392e0c32af0508a1e544c9953ea2fe128dbae7d429commit-bot@chromium.org 4073fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org while (pattern.search(record, &begin, &end)) { 4173fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org changed |= pass->onMatch(record, &pattern, begin, end); 422e0c32af0508a1e544c9953ea2fe128dbae7d429commit-bot@chromium.org } 4373fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org return changed; 4473fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org} 452e0c32af0508a1e544c9953ea2fe128dbae7d429commit-bot@chromium.org 46467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org// Turns the logical NoOp Save and Restore in Save-Draw*-Restore patterns into actual NoOps. 47467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.orgstruct SaveOnlyDrawsRestoreNooper { 48467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org typedef Pattern3<Is<Save>, 49467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org Star<Or<Is<NoOp>, IsDraw> >, 50467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org Is<Restore> > 51467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org Pattern; 52467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org 53467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned end) { 54467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org record->replace<NoOp>(begin); // Save 55467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org record->replace<NoOp>(end-1); // Restore 56467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org return true; 57467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org } 58467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org}; 5973fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org// Turns logical no-op Save-[non-drawing command]*-Restore patterns into actual no-ops. 60467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.orgstruct SaveNoDrawsRestoreNooper { 6173fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org // Star matches greedily, so we also have to exclude Save and Restore. 6299d6a9ee8b3516de892d118c71aa5e6e5c865efdmtklein // Nested SaveLayers need to be excluded, or we'll match their Restore! 6373fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org typedef Pattern3<Is<Save>, 6499d6a9ee8b3516de892d118c71aa5e6e5c865efdmtklein Star<Not<Or4<Is<Save>, 6599d6a9ee8b3516de892d118c71aa5e6e5c865efdmtklein Is<SaveLayer>, 6673fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org Is<Restore>, 6773fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org IsDraw> > >, 6873fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org Is<Restore> > 6973fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org Pattern; 7073fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org 7173fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned end) { 7273fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org // The entire span between Save and Restore (inclusively) does nothing. 7373fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org for (unsigned i = begin; i < end; i++) { 7473fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org record->replace<NoOp>(i); 7573fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org } 7673fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org return true; 772e0c32af0508a1e544c9953ea2fe128dbae7d429commit-bot@chromium.org } 7888c3e279ab79125e5741b0b0b3175291e2e2bbeecommit-bot@chromium.org}; 7973fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.orgvoid SkRecordNoopSaveRestores(SkRecord* record) { 80467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org SaveOnlyDrawsRestoreNooper onlyDraws; 81467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org SaveNoDrawsRestoreNooper noDraws; 82467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org 83467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org // Run until they stop changing things. 84467705adf05ba99bbd9ccdf6a40eb463484a6fbfcommit-bot@chromium.org while (apply(&onlyDraws, record) || apply(&noDraws, record)); 8573fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org} 8688c3e279ab79125e5741b0b0b3175291e2e2bbeecommit-bot@chromium.org 87f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org// For some SaveLayer-[drawing command]-Restore patterns, merge the SaveLayer's alpha into the 88f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org// draw, and no-op the SaveLayer and Restore. 89f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.orgstruct SaveLayerDrawRestoreNooper { 90f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org typedef Pattern3<Is<SaveLayer>, IsDraw, Is<Restore> > Pattern; 91f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org 92f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned end) { 93f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org SaveLayer* saveLayer = pattern->first<SaveLayer>(); 94f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org if (saveLayer->bounds != NULL) { 95f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org // SaveLayer with bounds is too tricky for us. 96f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org return false; 97f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org } 98f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org 99f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org SkPaint* layerPaint = saveLayer->paint; 100f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org if (NULL == layerPaint) { 101f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org // There wasn't really any point to this SaveLayer at all. 102f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org return KillSaveLayerAndRestore(record, begin); 103f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org } 104f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org 105f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org SkPaint* drawPaint = pattern->second<SkPaint>(); 106f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org if (drawPaint == NULL) { 107f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org // We can just give the draw the SaveLayer's paint. 108f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org // TODO(mtklein): figure out how to do this clearly 109f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org return false; 110f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org } 111f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org 112f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org const uint32_t layerColor = layerPaint->getColor(); 113f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org const uint32_t drawColor = drawPaint->getColor(); 114ee7e23d13f5400716715c1823ad6e41d9a5904cacommit-bot@chromium.org if (!IsOnlyAlpha(layerColor) || !IsOpaque(drawColor) || 115ee7e23d13f5400716715c1823ad6e41d9a5904cacommit-bot@chromium.org HasAnyEffect(*layerPaint) || HasAnyEffect(*drawPaint)) { 116f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org // Too fancy for us. Actually, as long as layerColor is just an alpha 117f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org // we can blend it into drawColor's alpha; drawColor doesn't strictly have to be opaque. 118f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org return false; 119f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org } 120f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org 121f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org drawPaint->setColor(SkColorSetA(drawColor, SkColorGetA(layerColor))); 122f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org return KillSaveLayerAndRestore(record, begin); 123f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org } 124f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org 125f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org static bool KillSaveLayerAndRestore(SkRecord* record, unsigned saveLayerIndex) { 126f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org record->replace<NoOp>(saveLayerIndex); // SaveLayer 127f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org record->replace<NoOp>(saveLayerIndex+2); // Restore 128f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org return true; 129f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org } 130f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org 131f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org static bool HasAnyEffect(const SkPaint& paint) { 132f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org return paint.getPathEffect() || 133f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org paint.getShader() || 134f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org paint.getXfermode() || 135f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org paint.getMaskFilter() || 136f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org paint.getColorFilter() || 137f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org paint.getRasterizer() || 138f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org paint.getLooper() || 139f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org paint.getImageFilter(); 140f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org } 141f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org 142f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org static bool IsOpaque(SkColor color) { 143f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org return SkColorGetA(color) == SK_AlphaOPAQUE; 144f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org } 145f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org static bool IsOnlyAlpha(SkColor color) { 146f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org return SK_ColorTRANSPARENT == SkColorSetA(color, SK_AlphaTRANSPARENT); 147f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org } 148f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org}; 149f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.orgvoid SkRecordNoopSaveLayerDrawRestores(SkRecord* record) { 150f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org SaveLayerDrawRestoreNooper pass; 151f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org apply(&pass, record); 152f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org} 153f5bf3cf0257dc3d18932bde51f8eae33442e071fcommit-bot@chromium.org 154