| /* | |
| * Copyright 2018 Google LLC | |
| * | |
| * 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 "bench/GpuTools.h" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkColorSpace.h" | |
| #include "include/core/SkImage.h" | |
| #include "include/core/SkSurface.h" | |
| #include "src/core/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 Backend::kGanesh == 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". | |
| skgpu::FlushAndSubmit(canvas->getSurface()); | |
| } | |
| } | |
| private: | |
| SkISize 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)) |