OLD | NEW |
(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 #include "SkTableColorFilter.h" |
| 13 #include "SkColorFilterImageFilter.h" |
| 14 #include "SkPictureImageFilter.h" |
| 15 |
| 16 static const int kTestRectSize = 50; |
| 17 static const int kDetectorGreenValue = 50; |
| 18 |
| 19 // Below are few functions to install "detector" color filters. The filter is th
ere to assert that |
| 20 // the color value it sees is the expected. It will trigger only with kDetectorG
reenValue, and |
| 21 // turn that value into full green. The idea is that if an optimization incorrec
tly changes |
| 22 // kDetectorGreenValue and then the incorrect value is observable by some part o
f the drawing |
| 23 // pipeline, that pixel will remain empty. |
| 24 |
| 25 static SkColorFilter* make_detector_color_filter() { |
| 26 uint8_t tableA[256] = { 0, }; |
| 27 uint8_t tableR[256] = { 0, }; |
| 28 uint8_t tableG[256] = { 0, }; |
| 29 uint8_t tableB[256] = { 0, }; |
| 30 tableA[255] = 255; |
| 31 tableG[kDetectorGreenValue] = 255; |
| 32 return SkTableColorFilter::CreateARGB(tableA, tableR, tableG, tableB); |
| 33 } |
| 34 |
| 35 // This detector detects that color filter phase of the pixel pipeline receives
the correct value. |
| 36 static void install_detector_color_filter(SkPaint* drawPaint) { |
| 37 drawPaint->setColorFilter(make_detector_color_filter())->unref(); |
| 38 } |
| 39 |
| 40 // This detector detects that image filter phase of the pixel pipeline receives
the correct value. |
| 41 static void install_detector_image_filter(SkPaint* drawPaint) { |
| 42 SkAutoTUnref<SkColorFilter> colorFilter(make_detector_color_filter()); |
| 43 SkImageFilter* imageFilter = |
| 44 SkColorFilterImageFilter::Create(colorFilter, drawPaint->getImageFil
ter()); |
| 45 drawPaint->setImageFilter(imageFilter)->unref(); |
| 46 } |
| 47 |
| 48 static void no_detector_install(SkPaint*) { |
| 49 } |
| 50 |
| 51 typedef void(*InstallDetectorFunc)(SkPaint*); |
| 52 |
| 53 |
| 54 // Draws an pattern that can be optimized by alpha folding outer savelayer alpha
value to |
| 55 // inner draw. Since we know that folding will happen to the inner draw, install
a detector |
| 56 // to make sure that optimization does not change anything observable. |
| 57 static void draw_save_layer_draw_rect_restore_sequence(SkCanvas* canvas, SkColor
shapeColor, |
| 58 InstallDetectorFunc insta
llDetector) { |
| 59 SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar
(kTestRectSize))); |
| 60 SkPaint layerPaint; |
| 61 layerPaint.setColor(SkColorSetARGB(128, 0, 0, 0)); |
| 62 canvas->saveLayer(&targetRect, &layerPaint); |
| 63 SkPaint drawPaint; |
| 64 drawPaint.setColor(shapeColor); |
| 65 installDetector(&drawPaint); |
| 66 canvas->drawRect(targetRect, drawPaint); |
| 67 canvas->restore(); |
| 68 } |
| 69 |
| 70 // Draws an pattern that can be optimized by alpha folding outer savelayer alpha
value to |
| 71 // inner draw. A variant where the draw is not uniform color. |
| 72 static void draw_save_layer_draw_bitmap_restore_sequence(SkCanvas* canvas, SkCol
or shapeColor, |
| 73 InstallDetectorFunc ins
tallDetector) { |
| 74 SkBitmap bitmap; |
| 75 bitmap.allocN32Pixels(kTestRectSize, kTestRectSize); |
| 76 bitmap.eraseColor(shapeColor); |
| 77 { |
| 78 // Make the bitmap non-uniform color, so that it can not be optimized as
uniform drawRect. |
| 79 SkCanvas canvas(bitmap); |
| 80 SkPaint p; |
| 81 p.setColor(SK_ColorWHITE); |
| 82 SkASSERT(shapeColor != SK_ColorWHITE); |
| 83 canvas.drawRect(SkRect::MakeWH(SkIntToScalar(7), SkIntToScalar(7)), p); |
| 84 canvas.flush(); |
| 85 } |
| 86 |
| 87 SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar
(kTestRectSize))); |
| 88 SkPaint layerPaint; |
| 89 layerPaint.setColor(SkColorSetARGB(129, 0, 0, 0)); |
| 90 canvas->saveLayer(&targetRect, &layerPaint); |
| 91 SkPaint drawPaint; |
| 92 installDetector(&drawPaint); |
| 93 canvas->drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0), &drawPain
t); |
| 94 canvas->restore(); |
| 95 } |
| 96 |
| 97 // Draws an pattern that can be optimized by alpha folding outer savelayer alpha
value to |
| 98 // inner savelayer. We know that alpha folding happens to inner savelayer, so ad
d detector there. |
| 99 static void draw_svg_opacity_and_filter_layer_sequence(SkCanvas* canvas, SkColor
shapeColor, |
| 100 InstallDetectorFunc insta
llDetector) { |
| 101 |
| 102 SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar
(kTestRectSize))); |
| 103 SkAutoTUnref<SkPicture> shape; |
| 104 { |
| 105 SkPictureRecorder recorder; |
| 106 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kTestRectSize +
2), |
| 107 SkIntToScalar(kTestRectSize +
2)); |
| 108 SkPaint shapePaint; |
| 109 shapePaint.setColor(shapeColor); |
| 110 canvas->drawRect(targetRect, shapePaint); |
| 111 shape.reset(recorder.endRecordingAsPicture()); |
| 112 } |
| 113 |
| 114 SkPaint layerPaint; |
| 115 layerPaint.setColor(SkColorSetARGB(130, 0, 0, 0)); |
| 116 canvas->saveLayer(&targetRect, &layerPaint); |
| 117 canvas->save(); |
| 118 canvas->clipRect(targetRect); |
| 119 SkPaint drawPaint; |
| 120 drawPaint.setImageFilter(SkPictureImageFilter::Create(shape))->unref
(); |
| 121 installDetector(&drawPaint); |
| 122 canvas->saveLayer(&targetRect, &drawPaint); |
| 123 canvas->restore(); |
| 124 canvas->restore(); |
| 125 canvas->restore(); |
| 126 } |
| 127 |
| 128 // Draws two columns of rectangles. The test is correct when: |
| 129 // - Left and right columns always identical |
| 130 // - First 3 rows are green, with a white dent in the middle row |
| 131 // - Next 6 rows are green, with a grey dent in the middle row |
| 132 // (the grey dent is from the color filter removing everything but the "good"
green, see below) |
| 133 // - Last 6 rows are grey |
| 134 DEF_SIMPLE_GM(recordopts, canvas, (kTestRectSize+1)*2, (kTestRectSize+1)*15) { |
| 135 canvas->clear(SK_ColorTRANSPARENT); |
| 136 |
| 137 typedef void (*TestVariantSequence)(SkCanvas*, SkColor, InstallDetectorFunc)
; |
| 138 TestVariantSequence funcs[] = { |
| 139 draw_save_layer_draw_rect_restore_sequence, |
| 140 draw_save_layer_draw_bitmap_restore_sequence, |
| 141 draw_svg_opacity_and_filter_layer_sequence, |
| 142 }; |
| 143 |
| 144 // Draw layer-related sequences that can be optimized by folding the opacity
layer alpha to |
| 145 // the inner draw operation. This tries to trigger the optimization, and rel
ies on gm diffs |
| 146 // to keep the color value correct over time. |
| 147 |
| 148 // Draws two green rects side by side: one is without the optimization, the
other is with |
| 149 // the optimization applied. |
| 150 |
| 151 SkColor shapeColor = SkColorSetARGB(255, 0, 255, 0); |
| 152 for (size_t k = 0; k < SK_ARRAY_COUNT(funcs); ++k) { |
| 153 canvas->save(); |
| 154 |
| 155 TestVariantSequence drawTestSequence = funcs[k]; |
| 156 drawTestSequence(canvas, shapeColor, no_detector_install); |
| 157 canvas->flush(); |
| 158 canvas->translate(SkIntToScalar(kTestRectSize) + SkIntToScalar(1), SkInt
ToScalar(0)); |
| 159 { |
| 160 SkPictureRecorder recorder; |
| 161 drawTestSequence(recorder.beginRecording(SkIntToScalar(kTestRectSize
), |
| 162 SkIntToScalar(kTestRectSize
)), |
| 163 shapeColor, no_detector_install); |
| 164 SkAutoTUnref<SkPicture> optimizedPicture(recorder.endRecordingAsPict
ure()); |
| 165 optimizedPicture->playback(canvas); |
| 166 canvas->flush(); |
| 167 } |
| 168 canvas->restore(); |
| 169 canvas->translate(SkIntToScalar(0), SkIntToScalar(kTestRectSize) + SkInt
ToScalar(1)); |
| 170 } |
| 171 |
| 172 // Draw the same layer related sequences, but manipulate the sequences so th
at the result is |
| 173 // incorrect if the alpha is folded or folded incorrectly. These test the ob
servable state |
| 174 // throughout the pixel pipeline, and thus may turn off the optimizations (t
his is why we |
| 175 // trigger the optimizations above). |
| 176 |
| 177 // Draws two green rects side by side: one is without the optimization, the
other is with |
| 178 // the possibility that optimization is applied. |
| 179 // At the end, draws the same patterns in translucent black. This tests that
the detectors |
| 180 // work, eg. that if the value the detector sees is wrong, the resulting ima
ge shows this. |
| 181 SkColor shapeColors[] = { |
| 182 SkColorSetARGB(255, 0, kDetectorGreenValue, 0), |
| 183 SkColorSetARGB(255, 0, kDetectorGreenValue + 1, 0) // This tests that de
tectors work. |
| 184 }; |
| 185 |
| 186 InstallDetectorFunc detectorInstallFuncs[] = { |
| 187 install_detector_image_filter, |
| 188 install_detector_color_filter |
| 189 }; |
| 190 |
| 191 for (size_t i = 0; i < SK_ARRAY_COUNT(shapeColors); ++i) { |
| 192 shapeColor = shapeColors[i]; |
| 193 for (size_t j = 0; j < SK_ARRAY_COUNT(shapeColors); ++j) { |
| 194 InstallDetectorFunc detectorInstallFunc = detectorInstallFuncs[j]; |
| 195 for (size_t k = 0; k < SK_ARRAY_COUNT(funcs); ++k) { |
| 196 TestVariantSequence drawTestSequence = funcs[k]; |
| 197 canvas->save(); |
| 198 drawTestSequence(canvas, shapeColor, detectorInstallFunc); |
| 199 canvas->flush(); |
| 200 canvas->translate(SkIntToScalar(kTestRectSize) + SkIntToScalar(1
), SkIntToScalar(0)); |
| 201 { |
| 202 SkPictureRecorder recorder; |
| 203 drawTestSequence(recorder.beginRecording(SkIntToScalar(kTest
RectSize), |
| 204 SkIntToScalar(kTest
RectSize)), |
| 205 shapeColor, detectorInstallFunc); |
| 206 SkAutoTUnref<SkPicture> optimizedPicture(recorder.endRecordi
ngAsPicture()); |
| 207 optimizedPicture->playback(canvas); |
| 208 canvas->flush(); |
| 209 } |
| 210 |
| 211 canvas->restore(); |
| 212 canvas->translate(SkIntToScalar(0), SkIntToScalar(kTestRectSize)
+ SkIntToScalar(1)); |
| 213 } |
| 214 |
| 215 } |
| 216 } |
| 217 } |
| 218 |
OLD | NEW |