Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(689)

Side by Side Diff: gm/recordopts.cpp

Issue 840483005: Fold alpha to the draw in savelayer-draw-restore patterns with non-opaque draw (Closed) Base URL: https://skia.googlesource.com/skia.git@unique-id-unflatten
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | gyp/gmslides.gypi » ('j') | src/core/SkRecordOpts.cpp » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "gm.h"
9 #include "SkCanvas.h"
10 #include "SkPath.h"
11 #include "SkPictureRecorder.h"
12
13 /** A call pattern that should be optimized to a single draw call. */
14 static void draw_save_layer_draw_restore(SkCanvas* canvas, int layerAlpha, int d rawAlpha,
15 bool isForOptimizedRecord) {
16 SkRect targetRect(SkRect::MakeWH(SK_Scalar1, SK_Scalar1));
17 SkPaint layerPaint;
18 layerPaint.setColor(SkColorSetARGB(layerAlpha, 0x0, 0x00, 0x0));
19 if (!isForOptimizedRecord) {
20 // When drawing without the picture optimization, eg. for example direct ly to a canvas, we
21 // can not save layer for every call. This takes too much time for a gm test. The drawing
mtklein 2015/01/14 13:28:30 ... can not save the full layer ... ?
22 // needs to constrain the saveLayer.
23 canvas->saveLayer(&targetRect, &layerPaint);
24 } else {
25 // The optimization can not handle rect constraints yet.
26 canvas->saveLayer(NULL, &layerPaint);
27 }
28 SkPaint drawPaint;
29 // Using just one color should not lose any generality. This way it is just easier to reason
30 // about the magnitude of the error. 255 should have the biggest error.
31 drawPaint.setColor(SkColorSetARGB(drawAlpha, 0, 255, 0));
32
33 canvas->drawRect(targetRect, drawPaint);
34 canvas->restore();
35 }
36
37 /** Draws all (layer alpha, draw alpha) combinations as pixel-wide rects. This should identify the
38 * combinations that show difference between "savelayer-draw-restore" sequence a nd optimized "draw"
39 * sequence. */
40 static void draw_all_save_layer_draw_restore_combinations(SkCanvas* canvas,
41 bool isForOptimizedRec ord) {
42 canvas->save();
43 for (int layerAlpha = 0; layerAlpha < 256; ++layerAlpha) {
44 canvas->save();
45 for (int drawAlpha = 0; drawAlpha < 256; ++drawAlpha) {
46 draw_save_layer_draw_restore(canvas, layerAlpha, drawAlpha, isForOpt imizedRecord);
47 canvas->translate(SK_Scalar1, 0);
48 }
49 canvas->restore();
50 canvas->translate(0, SK_Scalar1);
51 }
52 canvas->restore();
53 }
54
55
56 /** Xfermode that highlights small differences between the pixel values that are being drawn.
57 * HighlightSmallDifferencesXfermode shows difference between existing image and new image pixel
58 * values. The image is the component-wise manhattan distance between the what i s there in the
59 * backbuffer and the new shape. The distance is visualized as step colors: dist ance of 0 is black,
60 * 1 is dark gray (100), 2 is gray (200) and distance > 2 is white (255). In or der to debug this:
61 * This should produce black image (with a deterministic backend):
62 *
63 * SkCanvas canvas(...);
64 * SkPicture picture(...);
65 * picture.draw(canvas);
66 * SkPaint paint;
67 * paint.setXfermode(HighlightSmallDifferencesXfermode::Create());
68 * canvas.saveLayer(NULL, &paint);
69 * picture.draw(canvas);
70 * canvas.restore();
71 */
72 class HighlightSmallDifferencesXfermode : public SkXfermode {
73 public:
74 static HighlightSmallDifferencesXfermode* Create() {
75 return SkNEW(HighlightSmallDifferencesXfermode);
76 }
77
78 SK_TO_STRING_OVERRIDE()
79 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPixelXorXfermode)
80
81 protected:
82 HighlightSmallDifferencesXfermode() { }
83 void flatten(SkWriteBuffer&) const SK_OVERRIDE { }
84
85 SkPMColor xferColor(SkPMColor src, SkPMColor dst) const SK_OVERRIDE {
86 int d = SkAbs32(SkGetPackedR32(dst) - SkGetPackedR32(src))
87 + SkAbs32(SkGetPackedG32(dst) - SkGetPackedG32(src))
88 + SkAbs32(SkGetPackedB32(dst) - SkGetPackedB32(src));
89 d = SkClampMax(d * 100, 255);
90 return SkPackARGB32(0xFF, d, d, d);
91 }
92 #if SK_SUPPORT_GPU
93 bool asFragmentProcessor(GrFragmentProcessor** fp, GrTexture* background) co nst;
94 #endif
95 typedef SkXfermode INHERITED;
96 };
97
98 SkFlattenable* HighlightSmallDifferencesXfermode::CreateProc(SkReadBuffer& buffe r) {
99 return Create();
100 }
101
102 #ifndef SK_IGNORE_TO_STRING
103 void HighlightSmallDifferencesXfermode::toString(SkString* str) const {
104 str->append("HighlightSmallDifferencesXfermode: ()");
105 }
106 #endif
107
108 #if SK_SUPPORT_GPU
109
110 #include "GrFragmentProcessor.h"
111 #include "GrCoordTransform.h"
112 #include "GrInvariantOutput.h"
113 #include "GrProcessorUnitTest.h"
114 #include "gl/GrGLProcessor.h"
115 #include "gl/builders/GrGLProgramBuilder.h"
116
117 class HighlightSmallDifferencesXferEffect : public GrFragmentProcessor {
118 public:
119 static GrFragmentProcessor* Create(GrTexture* background) {
120 return SkNEW_ARGS(HighlightSmallDifferencesXferEffect, (background));
121 }
122
123 void getGLProcessorKey(const GrGLCaps& caps,
124 GrProcessorKeyBuilder* b) const SK_OVERRIDE {
125 GLProcessor::GenKey(*this, caps, b);
126 }
127
128 GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE {
129 return SkNEW_ARGS(GLProcessor, (*this));
130 }
131
132 const char* name() const SK_OVERRIDE { return "HighlightSmallDifferencesXfer Effect"; }
133
134 const GrTextureAccess& backgroundAccess() const { return fBackgroundAccess; }
135
136 class GLProcessor : public GrGLFragmentProcessor {
137 public:
138 GLProcessor(const GrFragmentProcessor&) {}
139
140 void emitCode(GrGLFPBuilder* builder,
141 const GrFragmentProcessor& fp,
142 const char* outputColor,
143 const char* inputColor,
144 const TransformedCoordsArray& coords,
145 const TextureSamplerArray& samplers) SK_OVERRIDE {
146 const GrTexture* backgroundTex =
147 fp.cast<HighlightSmallDifferencesXferEffect>().backgroundAcc ess().getTexture();
148 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder ();
149 const char* dstColor;
150 if (backgroundTex) {
151 dstColor = "bgColor";
152 fsBuilder->codeAppendf("\t\tvec4 %s = ", dstColor);
153 fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), c oords[0].getType());
154 fsBuilder->codeAppendf(";\n");
155 } else {
156 dstColor = fsBuilder->dstColor();
157 }
158 SkASSERT(dstColor);
159
160 // We don't try to optimize for this case at all
161 if (NULL == inputColor) {
162 fsBuilder->codeAppendf("\t\tconst vec4 ones = vec4(1);\n");
163 inputColor = "ones";
164 }
165 fsBuilder->codeAppendf("\t\t%s = vec4(vec3(dot(abs(%s.rgb - %s.rgb), vec3(1)) * 100.0),"
166 " 1.0);\n", outputColor, dstColor, inputColor );
167 }
168
169 static inline void GenKey(const GrProcessor& proc, const GrGLCaps&,
170 GrProcessorKeyBuilder* b) {
171 // The background may come from the dst or from a texture.
172 uint32_t key = proc.numTextures();
173 SkASSERT(key <= 1);
174 b->add32(key);
175 }
176
177 typedef GrGLFragmentProcessor INHERITED;
178 };
179
180 private:
181 HighlightSmallDifferencesXferEffect(GrTexture* background) {
182 this->initClassID<HighlightSmallDifferencesXferEffect>();
183 if (background) {
184 fBackgroundTransform.reset(kLocal_GrCoordSet, background,
185 GrTextureParams::kNone_FilterMode);
186 this->addCoordTransform(&fBackgroundTransform);
187 fBackgroundAccess.reset(background);
188 this->addTextureAccess(&fBackgroundAccess);
189 } else {
190 this->setWillReadDstColor();
191 }
192 }
193
194 bool onIsEqual(const GrFragmentProcessor& other) const SK_OVERRIDE {
195 return true;
196 }
197
198 void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
199 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
200 }
201
202 GrCoordTransform fBackgroundTransform;
203 GrTextureAccess fBackgroundAccess;
204
205 typedef GrFragmentProcessor INHERITED;
206 };
207
208 bool HighlightSmallDifferencesXfermode::asFragmentProcessor(GrFragmentProcessor* * fp,
209 GrTexture* background) const {
210 *fp = HighlightSmallDifferencesXferEffect::Create(background);
211 SkASSERT(*fp);
212 return true;
213 };
214
215 #endif
216
217 /**
218 Tests record optimizations. Draws shapes using a call patterns that get
219 optimized in SkRecord. Used to ensure that the optimization does not change t he
220 pixels (too drasticly).
221 */
222
223 class RecordOptsGM : public skiagm::GM {
224 public:
225 RecordOptsGM() {
226 }
227
228 protected:
229 SkString onShortName() SK_OVERRIDE {
230 return SkString("recordopts");
231 }
232
233 SkISize onISize() SK_OVERRIDE {
234 return SkISize::Make(256, 256);
235 }
236
237 void onOnceBeforeDraw() SK_OVERRIDE {
238 // Create a more optimal picture of unoptimal call sequence.
239 SkPictureRecorder recorder;
240 draw_all_save_layer_draw_restore_combinations(recorder.beginRecording(25 6, 256),
241 true /*isForOptimizedRecor d*/);
242 fSaveLayerDrawRestorePicture.reset(recorder.endRecordingAsPicture());
243
244 // Create a reference bitmap image from the same calls, without the opti mization.
245 // The reference must be a bitmap image instead, see below.
246 fSaveLayerDrawRestoreReferenceBitmap.allocN32Pixels(256, 256);
247 fSaveLayerDrawRestoreReferenceBitmap.eraseColor(SK_ColorBLACK);
248 SkCanvas referenceCanvas(fSaveLayerDrawRestoreReferenceBitmap);
249 draw_all_save_layer_draw_restore_combinations(&referenceCanvas,
250 false /*isForOptimizedReco rd*/);
251 referenceCanvas.flush();
252 }
253
254 void onDraw(SkCanvas* canvas) SK_OVERRIDE {
255 canvas->clear(SK_ColorTRANSPARENT);
256
257 // Test savelayer-draw-restore picture optimization.
258 // Draw optimized picture.
259 fSaveLayerDrawRestorePicture->playback(canvas);
260 // Visualize the difference between optimized picture and unoptimized co mmands by drawing
261 // the unoptimized commands on top of the existing picture using the
262 // HighlightSmallDifferences xfermode. If there would not be any differe nces the resulting
263 // bitmap would be empty.
264 SkPaint diffPaint;
265 diffPaint.setXfermode(HighlightSmallDifferencesXfermode::Create());
266 // Unfortunately we can not draw the unoptimized commands, because GPU b ackend can not
267 // execute so many save layers in time. Thus our difference image is cor rect only for the
mtklein 2015/01/14 13:28:30 If we're only going to get a useful diff with the
Kimmo Kinnunen 2015/01/14 14:07:20 Right. Well, with my gpu and the current code it g
mtklein 2015/01/14 14:53:10 Hmmm. I think I misunderstood the downside of the
268 // 8888 backend. For GPU backends, the difference image is the differenc e between optimized
269 // GPU picture and unoptimized 8888 commands.
270 canvas->drawBitmap(fSaveLayerDrawRestoreReferenceBitmap, 0, 0, &diffPain t);
271 }
272
273 private:
274 SkAutoTUnref<SkPicture> fSaveLayerDrawRestorePicture;
275 SkBitmap fSaveLayerDrawRestoreReferenceBitmap;
276
277 typedef skiagm::GM INHERITED;
278 };
279
280 DEF_GM( return SkNEW(RecordOptsGM); )
281
OLDNEW
« no previous file with comments | « no previous file | gyp/gmslides.gypi » ('j') | src/core/SkRecordOpts.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698