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/GrContext.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 static constexpr int kMinTileSize = 128; 21 static constexpr int kMaxTileSize = 2048; 22 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(GrContext * context,int size)34 RenderTargetTexture(GrContext* context, int size) { 35 SkSurfaceProps surfaceProps(SkSurfaceProps::kLegacyFontHost_InitType); 36 SkImageInfo imageInfo = SkImageInfo::Make(size, size, kRGBA_8888_SkColorType, 37 kPremul_SkAlphaType); 38 fSurface = SkSurface::MakeRenderTarget(context, 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 GrContext* 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 = SkTMin(kMaxTileSize, 2*fTileSize); 71 fTileRows = kMaxTileSize/fTileSize; 72 fTileCols = kMaxTileSize/fTileSize; 73 fCachedContext = nullptr; 74 } else if ('<' == uni) { 75 fTileSize = SkTMax(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(GrContext * context)95 void initializeTextures(GrContext* context) { 96 fTextures.reset(); 97 int textureCount = fTileRows * fTileCols; 98 for (int i = 0; i < textureCount; i++) { 99 fTextures.emplace_back(new RenderTargetTexture(context, 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 SkPaint paint; 111 112 GrContext* context = canvas->getGrContext(); 113 if (context) { 114 // One-time context-specific setup. 115 if (context != fCachedContext) { 116 fCachedContext = context; 117 this->initializeTextures(context); 118 } 119 120 // Upload new texture data for all textures, simulating a full page of tiles 121 // needing refresh. 122 int textureCount = fTileRows * fTileCols; 123 for (int i = 0; i < textureCount; i++) { 124 fTextures[i]->uploadRasterSurface(i == fActiveTileIndex ? fBlueSurface 125 : fGraySurface); 126 } 127 128 // Scale grid. 129 canvas->scale(kGridScale, kGridScale); 130 131 if (fDrawTexturesToScreen) { 132 for (int y = 0; y < fTileRows; y++) { 133 for (int x = 0; x < fTileCols; x++) { 134 int currentIndex = y * fTileCols + x; 135 canvas->drawImage(fTextures[currentIndex]->getImage(), 136 x * fTileSize, y * fTileSize, &paint); 137 } 138 } 139 } 140 } 141 #endif 142 } 143 onAnimate(double nanos)144 bool onAnimate(double nanos) override { 145 constexpr SkScalar kDesiredDurationSecs = 16.0f; 146 float numTiles = fTileRows*fTileCols; 147 fActiveTileIndex = floorf(TimeUtils::Scaled(1e-9 * nanos, 148 numTiles/kDesiredDurationSecs, numTiles)); 149 return true; 150 } 151 }; 152 153 const int TextureUploadSample::kMinTileSize; 154 const int TextureUploadSample::kMaxTileSize; 155 156 DEF_SAMPLE( return new TextureUploadSample(); ) 157 158