skia2/gm/recordopts.cpp
Ben Wagner 7fde8e1728 IWYU for gms.
This almost gets gms to be iwyu clean. The last bit is around gm.cpp
and the tracing framework and its use of atomic. Will also need a way
of keeping things from regressing, which is difficult due to needing to
do this outside-in.

Change-Id: I1393531e99da8b0f1a29f55c53c86d53f459af7d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/211593
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
2019-05-02 17:48:53 +00:00

232 lines
10 KiB
C++

/*
* 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));
}
}
}
}