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