1 /* 2 * Copyright 2019 Google Inc. and Adobe Inc. 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 "include/core/SkCanvas.h" 9 #include "include/core/SkPaint.h" 10 #include "include/core/SkSurface.h" 11 #include "include/core/SkTypes.h" 12 #include "include/gpu/ganesh/GrDirectContext.h" 13 #include "include/gpu/ganesh/SkSurfaceGanesh.h" 14 #include "tools/timer/TimeUtils.h" 15 #include "tools/viewer/Slide.h" 16 17 using namespace skia_private; 18 19 /** 20 * This sample exercises heavy texture updates and uploads. 21 */ 22 class TextureUploadSlide : public Slide { 23 public: TextureUploadSlide()24 TextureUploadSlide() { fName = "TextureUpload"; } 25 onChar(SkUnichar uni)26 bool onChar(SkUnichar uni) override { 27 if ('m' == uni) { 28 fDrawTexturesToScreen = !fDrawTexturesToScreen; 29 return true; 30 } else if ('>' == uni) { 31 fTileSize = std::min(kMaxTileSize, 2*fTileSize); 32 fTileRows = kMaxTileSize/fTileSize; 33 fTileCols = kMaxTileSize/fTileSize; 34 fCachedContext = nullptr; 35 } else if ('<' == uni) { 36 fTileSize = std::max(kMinTileSize, fTileSize/2); 37 fTileRows = kMaxTileSize/fTileSize; 38 fTileCols = kMaxTileSize/fTileSize; 39 fCachedContext = nullptr; 40 } 41 return false; 42 } 43 getDimensions() const44 SkISize getDimensions() const override { return {1024, 1024}; } 45 draw(SkCanvas * canvas)46 void draw(SkCanvas* canvas) override { 47 canvas->clear(0xFFFFFFFF); 48 #if defined(SK_GANESH) 49 auto direct = GrAsDirectContext(canvas->recordingContext()); 50 if (direct) { 51 // One-time context-specific setup. 52 if (direct != fCachedContext) { 53 fCachedContext = direct; 54 this->initializeTextures(direct); 55 } 56 57 // Upload new texture data for all textures, simulating a full page of tiles 58 // needing refresh. 59 int textureCount = fTileRows * fTileCols; 60 for (int i = 0; i < textureCount; i++) { 61 fTextures[i]->uploadRasterSurface(i == fActiveTileIndex ? fBlueSurface 62 : fGraySurface); 63 } 64 65 // Scale grid. 66 canvas->scale(kGridScale, kGridScale); 67 68 if (fDrawTexturesToScreen) { 69 for (int y = 0; y < fTileRows; y++) { 70 for (int x = 0; x < fTileCols; x++) { 71 int currentIndex = y * fTileCols + x; 72 canvas->drawImage(fTextures[currentIndex]->getImage(), 73 x * fTileSize, y * fTileSize); 74 } 75 } 76 } 77 } 78 #endif 79 } 80 animate(double nanos)81 bool animate(double nanos) override { 82 constexpr SkScalar kDesiredDurationSecs = 16.0f; 83 float numTiles = fTileRows*fTileCols; 84 fActiveTileIndex = floorf(TimeUtils::Scaled(1e-9 * nanos, 85 numTiles/kDesiredDurationSecs, numTiles)); 86 return true; 87 } 88 89 private: 90 class RenderTargetTexture : public SkRefCnt { 91 public: RenderTargetTexture(GrDirectContext * direct,int size)92 RenderTargetTexture(GrDirectContext* direct, int size) { 93 SkSurfaceProps surfaceProps(0, kRGB_H_SkPixelGeometry); 94 SkImageInfo imageInfo = SkImageInfo::Make(size, size, kRGBA_8888_SkColorType, 95 kPremul_SkAlphaType); 96 fSurface = SkSurfaces::RenderTarget( 97 direct, skgpu::Budgeted::kNo, imageInfo, 0, &surfaceProps); 98 } 99 getImage()100 sk_sp<SkImage> getImage() { 101 return fSurface->makeImageSnapshot(); 102 } 103 uploadRasterSurface(sk_sp<SkSurface> rasterSurface)104 void uploadRasterSurface(sk_sp<SkSurface> rasterSurface) { 105 SkPixmap pixmap; 106 rasterSurface->peekPixels(&pixmap); 107 fSurface->writePixels(pixmap, 0, 0); 108 } 109 110 private: 111 sk_sp<SkSurface> fSurface; 112 sk_sp<SkImage> fCachedImage; 113 }; 114 115 inline static constexpr int kMinTileSize = 128; 116 inline static constexpr int kMaxTileSize = 2048; 117 inline static constexpr float kGridScale = 0.25f; 118 119 bool fDrawTexturesToScreen = true; 120 int fTileSize = 256; 121 int fTileRows = 8; 122 int fTileCols = 8; 123 124 sk_sp<SkSurface> fBlueSurface; 125 sk_sp<SkSurface> fGraySurface; 126 127 TArray<sk_sp<RenderTargetTexture>> fTextures; 128 129 GrDirectContext* fCachedContext = nullptr; 130 131 SkScalar fActiveTileIndex = 0; 132 getFilledRasterSurface(SkColor color,int size)133 sk_sp<SkSurface> getFilledRasterSurface(SkColor color, int size) { 134 sk_sp<SkSurface> surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(size, size))); 135 SkCanvas* canvas = surface->getCanvas(); 136 canvas->clear(color); 137 return surface; 138 } initializeTextures(GrDirectContext * direct)139 void initializeTextures(GrDirectContext* direct) { 140 fTextures.clear(); 141 int textureCount = fTileRows * fTileCols; 142 for (int i = 0; i < textureCount; i++) { 143 fTextures.emplace_back(new RenderTargetTexture(direct, fTileSize)); 144 } 145 146 // Construct two simple rasters of differing colors to serve 147 // as cpu rasterized data to refresh textures with. 148 fBlueSurface = this->getFilledRasterSurface(SK_ColorBLUE, fTileSize); 149 fGraySurface = this->getFilledRasterSurface(SK_ColorGRAY, fTileSize); 150 } 151 }; 152 153 154 DEF_SLIDE( return new TextureUploadSlide(); ) 155 156