• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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