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