Index: src/core/SkRecordOpts.cpp |
diff --git a/src/core/SkRecordOpts.cpp b/src/core/SkRecordOpts.cpp |
index 17595c01c55b5cef09a6509163346f2ebb0996a2..bdb15cbd15b0eb0efef622e0b11206af78e90d2d 100644 |
--- a/src/core/SkRecordOpts.cpp |
+++ b/src/core/SkRecordOpts.cpp |
@@ -12,6 +12,7 @@ |
#include "SkTDArray.h" |
using namespace SkRecords; |
+static void SkRecordNoopSaveLayerSaveLayerRestores(SkRecord* record); |
mtklein
2015/01/21 16:20:29
This is a sign we need unit tests. :) You'll want
Kimmo Kinnunen
2015/01/22 13:55:01
Done.
|
void SkRecordOptimize(SkRecord* record) { |
// This might be useful as a first pass in the future if we want to weed |
@@ -21,6 +22,7 @@ void SkRecordOptimize(SkRecord* record) { |
//SkRecordNoopSaveRestores(record); |
SkRecordNoopSaveLayerDrawRestores(record); |
+ SkRecordNoopSaveLayerSaveLayerRestores(record); |
mtklein
2015/01/21 16:20:30
Can you see any SKPs where these optimizations fee
Kimmo Kinnunen
2015/01/22 13:55:01
No, they are not related. They can not generate ne
|
} |
// Most of the optimizations in this file are pattern-based. These are all defined as structs with: |
@@ -56,6 +58,27 @@ struct SaveOnlyDrawsRestoreNooper { |
return true; |
} |
}; |
+ |
+static bool has_any_effect(const SkPaint& paint) { |
+ return paint.getPathEffect() || |
+ paint.getShader() || |
+ paint.getXfermode() || |
+ paint.getMaskFilter() || |
+ paint.getColorFilter() || |
+ paint.getRasterizer() || |
+ paint.getLooper() || |
+ paint.getImageFilter(); |
+} |
+ |
+static bool is_only_alpha(SkColor color) { |
+ return SK_ColorTRANSPARENT == SkColorSetA(color, SK_AlphaTRANSPARENT); |
+} |
+ |
+static SkColor blend_opacity_layer_color(SkColor baseColor, SkColor opacityLayerColor) { |
+ return SkColorSetA(baseColor, SkFloatToIntRound(SkColorGetA(baseColor) * |
+ SkColorGetA(opacityLayerColor) / 255.0f)); |
+} |
+ |
// Turns logical no-op Save-[non-drawing command]*-Restore patterns into actual no-ops. |
struct SaveNoDrawsRestoreNooper { |
// Star matches greedily, so we also have to exclude Save and Restore. |
@@ -111,34 +134,15 @@ struct SaveLayerDrawRestoreNooper { |
const uint32_t layerColor = layerPaint->getColor(); |
const uint32_t drawColor = drawPaint->getColor(); |
- if (!IsOnlyAlpha(layerColor) || HasAnyEffect(*layerPaint) || CantFoldAlpha(*drawPaint)) { |
+ if (!is_only_alpha(layerColor) || has_any_effect(*layerPaint) || CantFoldAlpha(*drawPaint)) { |
// Too fancy for us. |
return false; |
} |
- drawPaint->setColor(SkColorSetA(drawColor, |
- SkFloatToIntRound(SkColorGetA(drawColor) * |
- SkColorGetA(layerColor) / 255.0f))); |
+ drawPaint->setColor(blend_opacity_layer_color(drawColor, layerColor)); |
return KillSaveLayerAndRestore(record, begin); |
} |
- static bool KillSaveLayerAndRestore(SkRecord* record, unsigned saveLayerIndex) { |
- record->replace<NoOp>(saveLayerIndex); // SaveLayer |
- record->replace<NoOp>(saveLayerIndex+2); // Restore |
- return true; |
- } |
- |
- static bool HasAnyEffect(const SkPaint& paint) { |
- return paint.getPathEffect() || |
- paint.getShader() || |
- paint.getXfermode() || |
- paint.getMaskFilter() || |
- paint.getColorFilter() || |
- paint.getRasterizer() || |
- paint.getLooper() || |
- paint.getImageFilter(); |
- } |
- |
// The alpha folding can proceed if the single draw's paint has a shader, |
// path effect, mask filter and/or rasterizer. |
// TODO: most likely the looper and only some xfer modes are the hard |
@@ -150,8 +154,10 @@ struct SaveLayerDrawRestoreNooper { |
paint.getImageFilter(); |
} |
- static bool IsOnlyAlpha(SkColor color) { |
- return SK_ColorTRANSPARENT == SkColorSetA(color, SK_AlphaTRANSPARENT); |
+ static bool KillSaveLayerAndRestore(SkRecord* record, unsigned saveLayerIndex) { |
+ record->replace<NoOp>(saveLayerIndex); // SaveLayer |
+ record->replace<NoOp>(saveLayerIndex+2); // Restore |
+ return true; |
} |
}; |
void SkRecordNoopSaveLayerDrawRestores(SkRecord* record) { |
@@ -159,3 +165,59 @@ void SkRecordNoopSaveLayerDrawRestores(SkRecord* record) { |
apply(&pass, record); |
} |
+ |
+/* For SVG generated: |
+ SaveLayer (non-opaque) |
mtklein
2015/01/13 21:12:20
This pattern seems very specific. This makes me w
Kimmo Kinnunen
2015/01/22 13:55:01
Acknowledged.
|
+ Save |
+ Clip Rect |
+ Save Layer |
+ Restore |
+ Restore |
+ Restore |
+*/ |
+struct SaveLayerSaveLayerRestoreNooper { |
mtklein
2015/01/21 16:20:29
Might be I've set a bad naming precedent here. Ma
Kimmo Kinnunen
2015/01/22 13:55:01
Done.
|
+ typedef Pattern7<Is<SaveLayer>, Is<Save>, Is<ClipRect>, Is<SaveLayer>, |
+ Is<Restore>, Is<Restore>, Is<Restore> > Pattern; |
+ |
+ bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned end) { |
+ SaveLayer* opacityLayer = pattern->first<SaveLayer>(); |
+ if (opacityLayer->bounds != NULL) { |
+ // SaveLayer with bounds is too tricky for us. |
mtklein
2015/01/21 16:20:29
I removed this check in the other pattern. I thin
Kimmo Kinnunen
2015/01/22 13:55:01
Done.
|
+ return false; |
+ } |
+ |
+ SkPaint* opacityPaint = opacityLayer->paint; |
+ if (NULL == opacityPaint) { |
+ // There wasn't really any point to this SaveLayer at all. |
+ return KillSaveLayerAndRestore(record, begin); |
+ } |
+ |
+ SkPaint* secondLayerPaint = pattern->fourth<SaveLayer>()->paint; |
+ if (secondLayerPaint == NULL) { |
+ // We can just give the draw the SaveLayer's paint. |
mtklein
2015/01/21 16:20:29
// We can just give the inner SaveLayer the outer
Kimmo Kinnunen
2015/01/22 13:55:01
Done.
|
+ // TODO(mtklein): figure out how to do this clearly |
+ return false; |
+ } |
+ |
+ const uint32_t opacityColor = opacityPaint->getColor(); |
+ const uint32_t secondLayerColor = secondLayerPaint->getColor(); |
+ if (!is_only_alpha(opacityColor) || has_any_effect(*opacityPaint)) { |
mtklein
2015/01/21 16:20:29
We're not doing a CantFoldAlpha check here, and I'
Kimmo Kinnunen
2015/01/22 13:55:01
Done.
|
+ // Too fancy for us. |
+ return false; |
+ } |
+ |
+ secondLayerPaint->setColor(blend_opacity_layer_color(secondLayerColor, opacityColor)); |
+ return KillSaveLayerAndRestore(record, begin); |
+ } |
+ |
+ static bool KillSaveLayerAndRestore(SkRecord* record, unsigned saveLayerIndex) { |
+ record->replace<NoOp>(saveLayerIndex); // SaveLayer |
+ record->replace<NoOp>(saveLayerIndex + 6); // Restore |
+ return true; |
+ } |
+}; |
+ |
+static void SkRecordNoopSaveLayerSaveLayerRestores(SkRecord* record) { |
+ SaveLayerSaveLayerRestoreNooper pass; |
+ apply(&pass, record); |
+} |