blob: 933748cf828e8b5a9c714e0f35b9e904523a2936 [file] [log] [blame]
/*
* Copyright 2019 Google Inc. and Adobe Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkCanvas.h"
#include "include/core/SkPaint.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTypes.h"
#include "include/gpu/GrDirectContext.h"
#include "samplecode/Sample.h"
#include "tools/timer/TimeUtils.h"
/**
* This sample exercises heavy texture updates and uploads.
*/
class TextureUploadSample : public Sample {
inline static constexpr int kMinTileSize = 128;
inline static constexpr int kMaxTileSize = 2048;
inline static constexpr float kGridScale = 0.25f;
bool fDrawTexturesToScreen = true;
int fTileSize = 256;
int fTileRows = 8;
int fTileCols = 8;
sk_sp<SkSurface> fBlueSurface;
sk_sp<SkSurface> fGraySurface;
class RenderTargetTexture : public SkRefCnt {
public:
RenderTargetTexture(GrDirectContext* direct, int size) {
SkSurfaceProps surfaceProps(0, kRGB_H_SkPixelGeometry);
SkImageInfo imageInfo = SkImageInfo::Make(size, size, kRGBA_8888_SkColorType,
kPremul_SkAlphaType);
fSurface = SkSurface::MakeRenderTarget(direct, SkBudgeted::kNo, imageInfo, 0,
&surfaceProps);
}
sk_sp<SkImage> getImage() {
return fSurface->makeImageSnapshot();
}
void uploadRasterSurface(sk_sp<SkSurface> rasterSurface) {
SkPixmap pixmap;
rasterSurface->peekPixels(&pixmap);
fSurface->writePixels(pixmap, 0, 0);
}
private:
sk_sp<SkSurface> fSurface;
sk_sp<SkImage> fCachedImage;
};
SkTArray<sk_sp<RenderTargetTexture>> fTextures;
GrDirectContext* fCachedContext = nullptr;
SkScalar fActiveTileIndex = 0;
SkString name() override {
return SkString("TextureUpload");
}
bool onChar(SkUnichar uni) override {
if ('m' == uni) {
fDrawTexturesToScreen = !fDrawTexturesToScreen;
return true;
} else if ('>' == uni) {
fTileSize = std::min(kMaxTileSize, 2*fTileSize);
fTileRows = kMaxTileSize/fTileSize;
fTileCols = kMaxTileSize/fTileSize;
fCachedContext = nullptr;
} else if ('<' == uni) {
fTileSize = std::max(kMinTileSize, fTileSize/2);
fTileRows = kMaxTileSize/fTileSize;
fTileCols = kMaxTileSize/fTileSize;
fCachedContext = nullptr;
}
return false;
}
sk_sp<SkSurface> getFilledRasterSurface(SkColor color, int size) {
sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(size, size));
SkCanvas* canvas = surface->getCanvas();
canvas->clear(color);
return surface;
}
void onOnceBeforeDraw() override {
this->setBGColor(0xFFFFFFFF);
this->setSize(1024, 1024);
}
void initializeTextures(GrDirectContext* direct) {
fTextures.reset();
int textureCount = fTileRows * fTileCols;
for (int i = 0; i < textureCount; i++) {
fTextures.emplace_back(new RenderTargetTexture(direct, fTileSize));
}
// Construct two simple rasters of differing colors to serve
// as cpu rasterized data to refresh textures with.
fBlueSurface = this->getFilledRasterSurface(SK_ColorBLUE, fTileSize);
fGraySurface = this->getFilledRasterSurface(SK_ColorGRAY, fTileSize);
}
void onDrawContent(SkCanvas* canvas) override {
#if SK_SUPPORT_GPU
auto direct = GrAsDirectContext(canvas->recordingContext());
if (direct) {
// One-time context-specific setup.
if (direct != fCachedContext) {
fCachedContext = direct;
this->initializeTextures(direct);
}
// Upload new texture data for all textures, simulating a full page of tiles
// needing refresh.
int textureCount = fTileRows * fTileCols;
for (int i = 0; i < textureCount; i++) {
fTextures[i]->uploadRasterSurface(i == fActiveTileIndex ? fBlueSurface
: fGraySurface);
}
// Scale grid.
canvas->scale(kGridScale, kGridScale);
if (fDrawTexturesToScreen) {
for (int y = 0; y < fTileRows; y++) {
for (int x = 0; x < fTileCols; x++) {
int currentIndex = y * fTileCols + x;
canvas->drawImage(fTextures[currentIndex]->getImage(),
x * fTileSize, y * fTileSize);
}
}
}
}
#endif
}
bool onAnimate(double nanos) override {
constexpr SkScalar kDesiredDurationSecs = 16.0f;
float numTiles = fTileRows*fTileCols;
fActiveTileIndex = floorf(TimeUtils::Scaled(1e-9 * nanos,
numTiles/kDesiredDurationSecs, numTiles));
return true;
}
};
DEF_SAMPLE( return new TextureUploadSample(); )