blob: 4f0757ef2313df1e8e9a2236d08f505bbe4f2090 [file] [log] [blame]
Jim Van Verth22098812019-08-07 11:22:13 -04001/*
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"
Robert Phillips30ebcf72020-07-09 13:25:17 -040012#include "include/gpu/GrDirectContext.h"
Jim Van Verth22098812019-08-07 11:22:13 -040013#include "samplecode/Sample.h"
14#include "tools/timer/TimeUtils.h"
15
16/**
17 * This sample exercises heavy texture updates and uploads.
18 */
19class 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:
Robert Phillips30ebcf72020-07-09 13:25:17 -040034 RenderTargetTexture(GrDirectContext* direct, int size) {
Ben Wagnerae4bb982020-09-24 14:49:00 -040035 SkSurfaceProps surfaceProps(0, kRGB_H_SkPixelGeometry);
Jim Van Verth22098812019-08-07 11:22:13 -040036 SkImageInfo imageInfo = SkImageInfo::Make(size, size, kRGBA_8888_SkColorType,
37 kPremul_SkAlphaType);
Robert Phillips30ebcf72020-07-09 13:25:17 -040038 fSurface = SkSurface::MakeRenderTarget(direct, SkBudgeted::kNo, imageInfo, 0,
Jim Van Verth22098812019-08-07 11:22:13 -040039 &surfaceProps);
40 }
41
42 sk_sp<SkImage> getImage() {
43 return fSurface->makeImageSnapshot();
44 }
45
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;
Robert Phillips30ebcf72020-07-09 13:25:17 -040058 GrDirectContext* fCachedContext = nullptr;
Jim Van Verth22098812019-08-07 11:22:13 -040059 SkScalar fActiveTileIndex = 0;
60
61 SkString name() override {
62 return SkString("TextureUpload");
63 }
64
65 bool onChar(SkUnichar uni) override {
66 if ('m' == uni) {
67 fDrawTexturesToScreen = !fDrawTexturesToScreen;
68 return true;
69 } else if ('>' == uni) {
Brian Osman788b9162020-02-07 10:36:46 -050070 fTileSize = std::min(kMaxTileSize, 2*fTileSize);
Jim Van Verth22098812019-08-07 11:22:13 -040071 fTileRows = kMaxTileSize/fTileSize;
72 fTileCols = kMaxTileSize/fTileSize;
73 fCachedContext = nullptr;
74 } else if ('<' == uni) {
Brian Osman788b9162020-02-07 10:36:46 -050075 fTileSize = std::max(kMinTileSize, fTileSize/2);
Jim Van Verth22098812019-08-07 11:22:13 -040076 fTileRows = kMaxTileSize/fTileSize;
77 fTileCols = kMaxTileSize/fTileSize;
78 fCachedContext = nullptr;
79 }
80 return false;
81 }
82
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
90 void onOnceBeforeDraw() override {
91 this->setBGColor(0xFFFFFFFF);
92 this->setSize(1024, 1024);
93 }
94
Robert Phillips30ebcf72020-07-09 13:25:17 -040095 void initializeTextures(GrDirectContext* direct) {
Jim Van Verth22098812019-08-07 11:22:13 -040096 fTextures.reset();
97 int textureCount = fTileRows * fTileCols;
98 for (int i = 0; i < textureCount; i++) {
Robert Phillips30ebcf72020-07-09 13:25:17 -040099 fTextures.emplace_back(new RenderTargetTexture(direct, fTileSize));
Jim Van Verth22098812019-08-07 11:22:13 -0400100 }
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
108 void onDrawContent(SkCanvas* canvas) override {
109#if SK_SUPPORT_GPU
Robert Phillips30ebcf72020-07-09 13:25:17 -0400110 auto direct = GrAsDirectContext(canvas->recordingContext());
111 if (direct) {
Jim Van Verth22098812019-08-07 11:22:13 -0400112 // One-time context-specific setup.
Robert Phillips30ebcf72020-07-09 13:25:17 -0400113 if (direct != fCachedContext) {
114 fCachedContext = direct;
115 this->initializeTextures(direct);
Jim Van Verth22098812019-08-07 11:22:13 -0400116 }
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(),
Mike Reed34c56a52021-01-22 15:26:41 -0500134 x * fTileSize, y * fTileSize);
Jim Van Verth22098812019-08-07 11:22:13 -0400135 }
136 }
137 }
138 }
139#endif
140 }
141
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
Jim Van Verth22098812019-08-07 11:22:13 -0400151
152DEF_SAMPLE( return new TextureUploadSample(); )
153