/* * Copyright 2023 Google LLC * * 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/SkCanvas.h" #include "include/core/SkSurface.h" #include "include/effects/SkGradientShader.h" #include "tools/DecodeUtils.h" #include "tools/Resources.h" #include "tools/ToolUtils.h" #if defined(SK_GRAPHITE) #include "include/gpu/graphite/Context.h" #include "include/gpu/graphite/Recorder.h" #include "include/gpu/graphite/Recording.h" #include "include/gpu/graphite/TextureInfo.h" #include "src/gpu/graphite/RecorderPriv.h" #include "src/gpu/graphite/Surface_Graphite.h" #include "tools/graphite/GraphiteToolUtils.h" #endif namespace skiagm { class GraphiteReplayGM : public GM { public: GraphiteReplayGM() = default; protected: void onOnceBeforeDraw() override { this->setBGColor(SK_ColorBLACK); fImage = ToolUtils::GetResourceAsImage("images/mandrill_128.png"); } SkString getName() const override { return SkString("graphite-replay"); } SkISize getISize() override { return SkISize::Make(kTileWidth * 3, kTileHeight * 2); } bool onAnimate(double nanos) override { fStartX = kTileWidth * (1.0f + sinf(nanos * 1e-9)) * 0.5f; return true; } DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override { #if defined(SK_GRAPHITE) skgpu::graphite::Recorder* recorder = canvas->recorder(); if (recorder) { this->drawGraphite(canvas, recorder); return DrawResult::kOk; } #endif return this->drawNonGraphite(canvas, errorMsg); } private: static constexpr int kImageSize = 128; static constexpr int kPadding = 2; static constexpr int kPaddedImageSize = kImageSize + kPadding * 2; static constexpr int kTileWidth = kPaddedImageSize * 2; static constexpr int kTileHeight = kPaddedImageSize * 2; float fStartX = 0.0f; sk_sp fImage; void drawContent(SkCanvas* canvas, int y) { SkPaint gradientPaint; constexpr SkPoint points[2] = {{0.0f, 0.0f}, {kImageSize, kImageSize}}; constexpr SkColor colors[4] = {SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED}; gradientPaint.setShader(SkGradientShader::MakeLinear( points, colors, nullptr, std::size(colors), SkTileMode::kClamp)); // Draw image. canvas->drawImage(fImage, kPadding, kPadding + y); // Draw gradient. canvas->save(); canvas->translate(kPaddedImageSize + kPadding, kPadding + y); canvas->drawRect(SkRect::MakeXYWH(0, 0, kImageSize, kImageSize), gradientPaint); canvas->restore(); } void drawTile(SkCanvas* canvas) { // Clip off the right 1/4 of the tile, after clearing. canvas->clear(SkColors::kRed); canvas->clipIRect(SkIRect::MakeWH(3 * kTileWidth / 4, kTileHeight)); // Draw content directly. drawContent(canvas, 0); // Draw content to a saved layer. SkPaint pAlpha; pAlpha.setAlphaf(0.5f); canvas->saveLayer(nullptr, &pAlpha); drawContent(canvas, kPaddedImageSize); canvas->restore(); } #if defined(SK_GRAPHITE) void drawGraphite(SkCanvas* canvas, skgpu::graphite::Recorder* canvasRecorder) { SkImageInfo tileImageInfo = canvas->imageInfo().makeDimensions(SkISize::Make(kTileWidth, kTileHeight)); skgpu::graphite::TextureInfo textureInfo = static_cast(canvas->getSurface()) ->backingTextureProxy() ->textureInfo(); skgpu::graphite::Context* context = canvasRecorder->priv().context(); std::unique_ptr recorder = context->makeRecorder(ToolUtils::CreateTestingRecorderOptions()); SkCanvas* recordingCanvas = recorder->makeDeferredCanvas(tileImageInfo, textureInfo); this->drawTile(recordingCanvas); std::unique_ptr recording = recorder->snap(); // Flush the initial clear added by MakeGraphite. std::unique_ptr canvasRecording = canvasRecorder->snap(); context->insertRecording({canvasRecording.get()}); for (int y = 0; y < 2; ++y) { for (int x = 0; x < 2; ++x) { context->insertRecording( {recording.get(), canvas->getSurface(), {x * kTileWidth + SkScalarRoundToInt(fStartX), y * kTileHeight}}); } } } #endif DrawResult drawNonGraphite(SkCanvas* canvas, SkString* errorMsg) { SkImageInfo tileImageInfo = canvas->imageInfo().makeDimensions(SkISize::Make(kTileWidth, kTileHeight)); sk_sp imageSurface = canvas->makeSurface(tileImageInfo); if (!imageSurface) { *errorMsg = "Cannot create new SkSurface."; return DrawResult::kSkip; } SkCanvas* imageCanvas = imageSurface->getCanvas(); this->drawTile(imageCanvas); sk_sp image = imageSurface->makeImageSnapshot(); for (int y = 0; y < 2; ++y) { for (int x = 0; x < 2; ++x) { canvas->drawImage(image, x * kTileWidth + fStartX, y * kTileHeight); } } return DrawResult::kOk; } }; DEF_GM(return new GraphiteReplayGM;) } // namespace skiagm