| /* | 
 |  * 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/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" | 
 | #endif | 
 |  | 
 | namespace skiagm { | 
 |  | 
 | class GraphiteReplayGM : public GM { | 
 | public: | 
 |     GraphiteReplayGM() { | 
 |         this->setBGColor(SK_ColorBLACK); | 
 |         fImage = GetResourceAsImage("images/mandrill_128.png"); | 
 |     } | 
 |  | 
 | protected: | 
 |     SkString onShortName() override { return SkString("graphite-replay"); } | 
 |  | 
 |     SkISize onISize() 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<SkImage> 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<skgpu::graphite::Surface*>(canvas->getSurface()) | 
 |                         ->backingTextureProxy() | 
 |                         ->textureInfo(); | 
 |  | 
 |         skgpu::graphite::Context* context = canvasRecorder->priv().context(); | 
 |         std::unique_ptr<skgpu::graphite::Recorder> recorder = | 
 |                 context->makeRecorder(ToolUtils::CreateTestingRecorderOptions()); | 
 |         SkCanvas* recordingCanvas = recorder->makeDeferredCanvas(tileImageInfo, textureInfo); | 
 |         this->drawTile(recordingCanvas); | 
 |         std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap(); | 
 |  | 
 |         // Flush the initial clear added by MakeGraphite. | 
 |         std::unique_ptr<skgpu::graphite::Recording> 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<SkSurface> imageSurface = canvas->makeSurface(tileImageInfo); | 
 |         if (!imageSurface) { | 
 |             *errorMsg = "Cannot create new SkSurface."; | 
 |             return DrawResult::kSkip; | 
 |         } | 
 |  | 
 |         SkCanvas* imageCanvas = imageSurface->getCanvas(); | 
 |         this->drawTile(imageCanvas); | 
 |         sk_sp<SkImage> 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 |