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