123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- /*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "gm/gm.h"
- #include "include/core/SkBitmap.h"
- #include "include/core/SkCanvas.h"
- #include "include/core/SkColor.h"
- #include "include/core/SkColorFilter.h"
- #include "include/core/SkImageFilter.h"
- #include "include/core/SkPaint.h"
- #include "include/core/SkPicture.h"
- #include "include/core/SkPictureRecorder.h"
- #include "include/core/SkRect.h"
- #include "include/core/SkRefCnt.h"
- #include "include/core/SkScalar.h"
- #include "include/core/SkTypes.h"
- #include "include/effects/SkColorFilterImageFilter.h"
- #include "include/effects/SkPictureImageFilter.h"
- #include "include/effects/SkTableColorFilter.h"
- #include "include/gpu/GrContext.h"
- constexpr int kTestRectSize = 50;
- constexpr int kDetectorGreenValue = 50;
- // Below are few functions to install "detector" color filters. The filter is there to assert that
- // the color value it sees is the expected. It will trigger only with kDetectorGreenValue, and
- // turn that value into full green. The idea is that if an optimization incorrectly changes
- // kDetectorGreenValue and then the incorrect value is observable by some part of the drawing
- // pipeline, that pixel will remain empty.
- static sk_sp<SkColorFilter> make_detector_color_filter() {
- uint8_t tableA[256] = { 0, };
- uint8_t tableR[256] = { 0, };
- uint8_t tableG[256] = { 0, };
- uint8_t tableB[256] = { 0, };
- tableA[255] = 255;
- tableG[kDetectorGreenValue] = 255;
- return SkTableColorFilter::MakeARGB(tableA, tableR, tableG, tableB);
- }
- // This detector detects that color filter phase of the pixel pipeline receives the correct value.
- static void install_detector_color_filter(SkPaint* drawPaint) {
- drawPaint->setColorFilter(make_detector_color_filter());
- }
- // This detector detects that image filter phase of the pixel pipeline receives the correct value.
- static void install_detector_image_filter(SkPaint* drawPaint) {
- drawPaint->setImageFilter(SkColorFilterImageFilter::Make(make_detector_color_filter(),
- drawPaint->refImageFilter()));
- }
- static void no_detector_install(SkPaint*) {
- }
- typedef void(*InstallDetectorFunc)(SkPaint*);
- // Draws an pattern that can be optimized by alpha folding outer savelayer alpha value to
- // inner draw. Since we know that folding will happen to the inner draw, install a detector
- // to make sure that optimization does not change anything observable.
- static void draw_save_layer_draw_rect_restore_sequence(SkCanvas* canvas, SkColor shapeColor,
- InstallDetectorFunc installDetector) {
- SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar(kTestRectSize)));
- SkPaint layerPaint;
- layerPaint.setColor(SkColorSetARGB(128, 0, 0, 0));
- canvas->saveLayer(&targetRect, &layerPaint);
- SkPaint drawPaint;
- drawPaint.setColor(shapeColor);
- installDetector(&drawPaint);
- canvas->drawRect(targetRect, drawPaint);
- canvas->restore();
- }
- // Draws an pattern that can be optimized by alpha folding outer savelayer alpha value to
- // inner draw. A variant where the draw is not uniform color.
- static void draw_save_layer_draw_bitmap_restore_sequence(SkCanvas* canvas, SkColor shapeColor,
- InstallDetectorFunc installDetector) {
- SkBitmap bitmap;
- bitmap.allocN32Pixels(kTestRectSize, kTestRectSize);
- bitmap.eraseColor(shapeColor);
- {
- // Make the bitmap non-uniform color, so that it can not be optimized as uniform drawRect.
- SkCanvas canvas(bitmap);
- SkPaint p;
- p.setColor(SK_ColorWHITE);
- SkASSERT(shapeColor != SK_ColorWHITE);
- canvas.drawRect(SkRect::MakeWH(SkIntToScalar(7), SkIntToScalar(7)), p);
- }
- SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar(kTestRectSize)));
- SkPaint layerPaint;
- layerPaint.setColor(SkColorSetARGB(129, 0, 0, 0));
- canvas->saveLayer(&targetRect, &layerPaint);
- SkPaint drawPaint;
- installDetector(&drawPaint);
- canvas->drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0), &drawPaint);
- canvas->restore();
- }
- // Draws an pattern that can be optimized by alpha folding outer savelayer alpha value to
- // inner savelayer. We know that alpha folding happens to inner savelayer, so add detector there.
- static void draw_svg_opacity_and_filter_layer_sequence(SkCanvas* canvas, SkColor shapeColor,
- InstallDetectorFunc installDetector) {
- SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar(kTestRectSize)));
- sk_sp<SkPicture> shape;
- {
- SkPictureRecorder recorder;
- SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kTestRectSize + 2),
- SkIntToScalar(kTestRectSize + 2));
- SkPaint shapePaint;
- shapePaint.setColor(shapeColor);
- canvas->drawRect(targetRect, shapePaint);
- shape = recorder.finishRecordingAsPicture();
- }
- SkPaint layerPaint;
- layerPaint.setColor(SkColorSetARGB(130, 0, 0, 0));
- canvas->saveLayer(&targetRect, &layerPaint);
- canvas->save();
- canvas->clipRect(targetRect);
- SkPaint drawPaint;
- drawPaint.setImageFilter(SkPictureImageFilter::Make(shape));
- installDetector(&drawPaint);
- canvas->saveLayer(&targetRect, &drawPaint);
- canvas->restore();
- canvas->restore();
- canvas->restore();
- }
- // Draws two columns of rectangles. The test is correct when:
- // - Left and right columns always identical
- // - First 3 rows are green, with a white dent in the middle row
- // - Next 6 rows are green, with a grey dent in the middle row
- // (the grey dent is from the color filter removing everything but the "good" green, see below)
- // - Last 6 rows are grey
- DEF_SIMPLE_GM(recordopts, canvas, (kTestRectSize+1)*2, (kTestRectSize+1)*15) {
- GrContext* context = canvas->getGrContext();
- canvas->clear(SK_ColorTRANSPARENT);
- typedef void (*TestVariantSequence)(SkCanvas*, SkColor, InstallDetectorFunc);
- TestVariantSequence funcs[] = {
- draw_save_layer_draw_rect_restore_sequence,
- draw_save_layer_draw_bitmap_restore_sequence,
- draw_svg_opacity_and_filter_layer_sequence,
- };
- // Draw layer-related sequences that can be optimized by folding the opacity layer alpha to
- // the inner draw operation. This tries to trigger the optimization, and relies on gm diffs
- // to keep the color value correct over time.
- // Draws two green rects side by side: one is without the optimization, the other is with
- // the optimization applied.
- SkColor shapeColor = SkColorSetARGB(255, 0, 255, 0);
- for (size_t k = 0; k < SK_ARRAY_COUNT(funcs); ++k) {
- canvas->save();
- TestVariantSequence drawTestSequence = funcs[k];
- drawTestSequence(canvas, shapeColor, no_detector_install);
- if (context) {
- context->flush();
- }
- canvas->translate(SkIntToScalar(kTestRectSize) + SkIntToScalar(1), SkIntToScalar(0));
- {
- SkPictureRecorder recorder;
- drawTestSequence(recorder.beginRecording(SkIntToScalar(kTestRectSize),
- SkIntToScalar(kTestRectSize)),
- shapeColor, no_detector_install);
- recorder.finishRecordingAsPicture()->playback(canvas);
- if (context) {
- context->flush();
- }
- }
- canvas->restore();
- canvas->translate(SkIntToScalar(0), SkIntToScalar(kTestRectSize) + SkIntToScalar(1));
- }
- // Draw the same layer related sequences, but manipulate the sequences so that the result is
- // incorrect if the alpha is folded or folded incorrectly. These test the observable state
- // throughout the pixel pipeline, and thus may turn off the optimizations (this is why we
- // trigger the optimizations above).
- // Draws two green rects side by side: one is without the optimization, the other is with
- // the possibility that optimization is applied.
- // At the end, draws the same patterns in translucent black. This tests that the detectors
- // work, eg. that if the value the detector sees is wrong, the resulting image shows this.
- SkColor shapeColors[] = {
- SkColorSetARGB(255, 0, kDetectorGreenValue, 0),
- SkColorSetARGB(255, 0, (kDetectorGreenValue + 1), 0) // This tests that detectors work.
- };
- InstallDetectorFunc detectorInstallFuncs[] = {
- install_detector_image_filter,
- install_detector_color_filter
- };
- for (size_t i = 0; i < SK_ARRAY_COUNT(shapeColors); ++i) {
- shapeColor = shapeColors[i];
- for (size_t j = 0; j < SK_ARRAY_COUNT(detectorInstallFuncs); ++j) {
- InstallDetectorFunc detectorInstallFunc = detectorInstallFuncs[j];
- for (size_t k = 0; k < SK_ARRAY_COUNT(funcs); ++k) {
- TestVariantSequence drawTestSequence = funcs[k];
- canvas->save();
- drawTestSequence(canvas, shapeColor, detectorInstallFunc);
- if (context) {
- context->flush();
- }
- canvas->translate(SkIntToScalar(kTestRectSize) + SkIntToScalar(1), SkIntToScalar(0));
- {
- SkPictureRecorder recorder;
- drawTestSequence(recorder.beginRecording(SkIntToScalar(kTestRectSize),
- SkIntToScalar(kTestRectSize)),
- shapeColor, detectorInstallFunc);
- recorder.finishRecordingAsPicture()->playback(canvas);
- if (context) {
- context->flush();
- }
- }
- canvas->restore();
- canvas->translate(SkIntToScalar(0), SkIntToScalar(kTestRectSize) + SkIntToScalar(1));
- }
- }
- }
- }
|