| /* |
| * Copyright 2018 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include <memory> |
| |
| #include "bench/Benchmark.h" |
| |
| #include "include/core/SkCanvas.h" |
| #include "include/core/SkImage.h" |
| #include "include/core/SkSurface.h" |
| #include "include/utils/SkRandom.h" |
| |
| /** |
| * Draws a small set of small images multiple times each with no overlaps so that each image could |
| * be batched. This was originally added to detect regressions as TextureOp is refactored to |
| * use "dynamic state" for texture bindings. Everything is kept small as we're mostly interested in |
| * CPU overhead. |
| */ |
| class ImageCycle : public Benchmark { |
| public: |
| /** |
| * imageCnt is the number of images and repeat cnt is how many times each image is drawn per |
| * logical "frame." |
| */ |
| ImageCycle(int imageCnt, int repeatCnt) : fImageCnt(imageCnt), fRepeatCnt(repeatCnt) { |
| fName.appendf("image_cycle_image_cnt_%d_repeat_cnt_%d", fImageCnt, fRepeatCnt); |
| } |
| |
| bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; } |
| |
| protected: |
| const char* onGetName() override { return fName.c_str(); } |
| |
| void onPerCanvasPreDraw(SkCanvas* canvas) override { |
| auto ii = SkImageInfo::Make(kImageSize.fWidth, kImageSize.fHeight, kRGBA_8888_SkColorType, |
| kPremul_SkAlphaType, nullptr); |
| SkRandom random; |
| fImages = std::make_unique<sk_sp<SkImage>[]>(fImageCnt); |
| for (int i = 0; i < fImageCnt; ++i) { |
| auto surf = canvas->makeSurface(ii); |
| SkColor color = random.nextU(); |
| surf->getCanvas()->clear(color); |
| SkPaint paint; |
| paint.setColor(~color); |
| paint.setBlendMode(SkBlendMode::kSrc); |
| surf->getCanvas()->drawRect( |
| SkRect::MakeLTRB(1, 1, kImageSize.fWidth - 1, kImageSize.fHeight - 1), paint); |
| fImages[i] = surf->makeImageSnapshot(); |
| } |
| } |
| |
| void onPerCanvasPostDraw(SkCanvas*) override { fImages.reset(); } |
| |
| void onDraw(int loops, SkCanvas* canvas) override { |
| SkPaint paint; |
| paint.setAntiAlias(true); |
| static constexpr SkScalar kPad = 2; |
| // To avoid tripping up bounds tracking we position the draws such that all the |
| // draws of image 0 are above those of image 1, etc. |
| static const int imagesPerRow = |
| SkScalarFloorToInt(kDeviceSize.fWidth / (kImageSize.fWidth + kPad)); |
| int rowsPerImage = SkScalarCeilToInt((SkScalar)fRepeatCnt / imagesPerRow); |
| for (int l = 0; l < loops; ++l) { |
| for (int r = 0; r < fRepeatCnt; ++r) { |
| for (int i = 0; i < fImageCnt; ++i) { |
| SkScalar imageYOffset = i * rowsPerImage * (kImageSize.fHeight + kPad); |
| SkScalar rowYOffset = (r / imagesPerRow) * (kImageSize.fHeight + kPad); |
| SkScalar x = (r % imagesPerRow) * (kImageSize.fWidth + kPad); |
| canvas->drawImage(fImages[i].get(), x, imageYOffset + rowYOffset, |
| SkSamplingOptions(), &paint); |
| } |
| } |
| // Prevent any batching between "frames". |
| if (auto surf = canvas->getSurface()) { |
| surf->flushAndSubmit(); |
| } |
| } |
| } |
| |
| private: |
| SkIPoint onGetSize() override { return {kDeviceSize.fWidth, kDeviceSize.fHeight}; } |
| |
| inline static constexpr SkISize kImageSize{4, 4}; |
| inline static constexpr SkISize kDeviceSize{64, 64}; |
| |
| std::unique_ptr<sk_sp<SkImage>[]> fImages; |
| SkString fName; |
| int fImageCnt; |
| int fRepeatCnt; |
| |
| using INHERITED = Benchmark; |
| }; |
| |
| DEF_BENCH(return new ImageCycle(5, 10)); |