1 /* 2 * Copyright 2023 Google LLC 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "gm/gm.h" 9 10 #include "include/core/SkCanvas.h" 11 #include "include/core/SkSurface.h" 12 #include "include/effects/SkGradientShader.h" 13 #include "tools/DecodeUtils.h" 14 #include "tools/Resources.h" 15 #include "tools/ToolUtils.h" 16 17 #if defined(SK_GRAPHITE) 18 #include "include/gpu/graphite/Context.h" 19 #include "include/gpu/graphite/Recorder.h" 20 #include "include/gpu/graphite/Recording.h" 21 #include "include/gpu/graphite/TextureInfo.h" 22 #include "src/gpu/graphite/RecorderPriv.h" 23 #include "src/gpu/graphite/Surface_Graphite.h" 24 #include "tools/graphite/GraphiteToolUtils.h" 25 #endif 26 27 namespace skiagm { 28 29 class GraphiteReplayGM : public GM { 30 public: 31 GraphiteReplayGM() = default; 32 33 protected: onOnceBeforeDraw()34 void onOnceBeforeDraw() override { 35 this->setBGColor(SK_ColorBLACK); 36 fImage = ToolUtils::GetResourceAsImage("images/mandrill_128.png"); 37 } 38 getName() const39 SkString getName() const override { return SkString("graphite-replay"); } 40 getISize()41 SkISize getISize() override { return SkISize::Make(kTileWidth * 3, kTileHeight * 2); } 42 onAnimate(double nanos)43 bool onAnimate(double nanos) override { 44 fStartX = kTileWidth * (1.0f + sinf(nanos * 1e-9)) * 0.5f; 45 return true; 46 } 47 onDraw(SkCanvas * canvas,SkString * errorMsg)48 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override { 49 #if defined(SK_GRAPHITE) 50 skgpu::graphite::Recorder* recorder = canvas->recorder(); 51 if (recorder) { 52 this->drawGraphite(canvas, recorder); 53 return DrawResult::kOk; 54 } 55 #endif 56 return this->drawNonGraphite(canvas, errorMsg); 57 } 58 59 private: 60 static constexpr int kImageSize = 128; 61 static constexpr int kPadding = 2; 62 static constexpr int kPaddedImageSize = kImageSize + kPadding * 2; 63 static constexpr int kTileWidth = kPaddedImageSize * 2; 64 static constexpr int kTileHeight = kPaddedImageSize * 2; 65 66 float fStartX = 0.0f; 67 68 sk_sp<SkImage> fImage; 69 drawContent(SkCanvas * canvas,int y)70 void drawContent(SkCanvas* canvas, int y) { 71 SkPaint gradientPaint; 72 constexpr SkPoint points[2] = {{0.0f, 0.0f}, {kImageSize, kImageSize}}; 73 constexpr SkColor colors[4] = {SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED}; 74 gradientPaint.setShader(SkGradientShader::MakeLinear( 75 points, colors, nullptr, std::size(colors), SkTileMode::kClamp)); 76 77 // Draw image. 78 canvas->drawImage(fImage, kPadding, kPadding + y); 79 80 // Draw gradient. 81 canvas->save(); 82 canvas->translate(kPaddedImageSize + kPadding, kPadding + y); 83 canvas->drawRect(SkRect::MakeXYWH(0, 0, kImageSize, kImageSize), gradientPaint); 84 canvas->restore(); 85 } 86 drawTile(SkCanvas * canvas)87 void drawTile(SkCanvas* canvas) { 88 // Clip off the right 1/4 of the tile, after clearing. 89 canvas->clear(SkColors::kRed); 90 canvas->clipIRect(SkIRect::MakeWH(3 * kTileWidth / 4, kTileHeight)); 91 92 // Draw content directly. 93 drawContent(canvas, 0); 94 95 // Draw content to a saved layer. 96 SkPaint pAlpha; 97 pAlpha.setAlphaf(0.5f); 98 canvas->saveLayer(nullptr, &pAlpha); 99 drawContent(canvas, kPaddedImageSize); 100 canvas->restore(); 101 } 102 103 #if defined(SK_GRAPHITE) drawGraphite(SkCanvas * canvas,skgpu::graphite::Recorder * canvasRecorder)104 void drawGraphite(SkCanvas* canvas, skgpu::graphite::Recorder* canvasRecorder) { 105 SkImageInfo tileImageInfo = 106 canvas->imageInfo().makeDimensions(SkISize::Make(kTileWidth, kTileHeight)); 107 skgpu::graphite::TextureInfo textureInfo = 108 static_cast<skgpu::graphite::Surface*>(canvas->getSurface()) 109 ->backingTextureProxy() 110 ->textureInfo(); 111 112 skgpu::graphite::Context* context = canvasRecorder->priv().context(); 113 std::unique_ptr<skgpu::graphite::Recorder> recorder = 114 context->makeRecorder(ToolUtils::CreateTestingRecorderOptions()); 115 SkCanvas* recordingCanvas = recorder->makeDeferredCanvas(tileImageInfo, textureInfo); 116 this->drawTile(recordingCanvas); 117 std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap(); 118 119 // Flush the initial clear added by MakeGraphite. 120 std::unique_ptr<skgpu::graphite::Recording> canvasRecording = canvasRecorder->snap(); 121 context->insertRecording({canvasRecording.get()}); 122 123 for (int y = 0; y < 2; ++y) { 124 for (int x = 0; x < 2; ++x) { 125 context->insertRecording( 126 {recording.get(), 127 canvas->getSurface(), 128 {x * kTileWidth + SkScalarRoundToInt(fStartX), y * kTileHeight}}); 129 } 130 } 131 } 132 #endif 133 drawNonGraphite(SkCanvas * canvas,SkString * errorMsg)134 DrawResult drawNonGraphite(SkCanvas* canvas, SkString* errorMsg) { 135 SkImageInfo tileImageInfo = 136 canvas->imageInfo().makeDimensions(SkISize::Make(kTileWidth, kTileHeight)); 137 138 sk_sp<SkSurface> imageSurface = canvas->makeSurface(tileImageInfo); 139 if (!imageSurface) { 140 *errorMsg = "Cannot create new SkSurface."; 141 return DrawResult::kSkip; 142 } 143 144 SkCanvas* imageCanvas = imageSurface->getCanvas(); 145 this->drawTile(imageCanvas); 146 sk_sp<SkImage> image = imageSurface->makeImageSnapshot(); 147 148 for (int y = 0; y < 2; ++y) { 149 for (int x = 0; x < 2; ++x) { 150 canvas->drawImage(image, x * kTileWidth + fStartX, y * kTileHeight); 151 } 152 } 153 return DrawResult::kOk; 154 } 155 }; 156 157 DEF_GM(return new GraphiteReplayGM;) 158 159 } // namespace skiagm 160