More cleanup in the Vulkan viewer

* add animation support for GMs
* don't load all SkPictures at start, only as needed
* don't update constantly, only for animation or stats
* hide/show stats
* scale slides up/down

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1873733003

Review URL: https://codereview.chromium.org/1873733003
This commit is contained in:
jvanverth 2016-04-08 12:51:45 -07:00 committed by Commit bot
parent 377add7426
commit c265a92741
13 changed files with 225 additions and 83 deletions

View File

@ -73,6 +73,7 @@ protected:
canvas->translate(80.0f, 0.0f);
}
canvas->restore();
}
}

View File

@ -67,7 +67,8 @@ void Window::onPaint() {
}
void Window::onResize(uint32_t w, uint32_t h) {
fWidth = w;
fHeight = h;
fTestContext->resize(w, h);
}

View File

@ -21,6 +21,7 @@ public:
virtual void setTitle(const char*) = 0;
virtual void show() = 0;
virtual void inval() = 0;
struct AttachmentInfo {
int fSampleCount;
@ -122,9 +123,15 @@ public:
void onPaint();
void onResize(uint32_t width, uint32_t height);
uint32_t width() { return fWidth; }
uint32_t height() { return fHeight; }
protected:
Window();
uint32_t fWidth;
uint32_t fHeight;
OnCharFunc fCharFunc;
void* fCharUserData;
OnKeyFunc fKeyFunc;

View File

@ -26,3 +26,7 @@ void GMSlide::draw(SkCanvas* canvas) {
fGM->drawBackground(canvas);
fGM->drawContent(canvas);
}
bool GMSlide::animate(const SkAnimTimer& timer) {
return fGM->animate(timer);
}

View File

@ -17,6 +17,7 @@ public:
~GMSlide() override;
void draw(SkCanvas* canvas) override;
bool animate(const SkAnimTimer&) override;
private:
skiagm::GM* fGM;

View File

@ -8,25 +8,51 @@
#include "SKPSlide.h"
#include "SkCanvas.h"
#include "SkCommonFlags.h"
#include "SkOSFile.h"
#include "SkStream.h"
SKPSlide::SKPSlide(const char* name, sk_sp<const SkPicture> pic)
: fPic(pic)
, fCullRect(fPic->cullRect().roundOut()) {
SKPSlide::SKPSlide(const SkString& name, const SkString& path) : fPath(path) {
fName = name;
}
SKPSlide::~SKPSlide() {}
void SKPSlide::draw(SkCanvas* canvas) {
bool isOffset = SkToBool(fCullRect.left() | fCullRect.top());
if (isOffset) {
canvas->save();
canvas->translate(SkIntToScalar(-fCullRect.left()), SkIntToScalar(-fCullRect.top()));
}
if (fPic.get()) {
bool isOffset = SkToBool(fCullRect.left() | fCullRect.top());
if (isOffset) {
canvas->save();
canvas->translate(SkIntToScalar(-fCullRect.left()), SkIntToScalar(-fCullRect.top()));
}
canvas->drawPicture(fPic.get());
canvas->drawPicture(fPic.get());
if (isOffset) {
canvas->restore();
if (isOffset) {
canvas->restore();
}
}
}
static sk_sp<SkPicture> read_picture(const char path[]) {
SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(path));
if (stream.get() == nullptr) {
SkDebugf("Could not read %s.\n", path);
return nullptr;
}
auto pic = SkPicture::MakeFromStream(stream.get());
if (!pic) {
SkDebugf("Could not read %s as an SkPicture.\n", path);
}
return pic;
}
void SKPSlide::load() {
fPic = read_picture(fPath.c_str());
fCullRect = fPic->cullRect().roundOut();
}
void SKPSlide::unload() {
fPic.reset(nullptr);
}

View File

@ -13,12 +13,15 @@
class SKPSlide : public Slide {
public:
SKPSlide(const char* name, sk_sp<const SkPicture> pic);
SKPSlide(const SkString& name, const SkString& path);
~SKPSlide() override;
void draw(SkCanvas* canvas) override;
void load() override;
void unload() override;
private:
SkString fPath;
sk_sp<const SkPicture> fPic;
SkIRect fCullRect;
};

View File

@ -12,12 +12,17 @@
#include "SkString.h"
class SkCanvas;
class SkAnimTimer;
class Slide : public SkRefCnt {
public:
virtual ~Slide() {}
virtual void draw(SkCanvas* canvas) = 0;
virtual bool animate(const SkAnimTimer&) { return false; }
virtual void load() {}
virtual void unload() {}
SkString getName() { return fName; }
protected:

View File

@ -27,6 +27,12 @@ static bool on_key_handler(Window::Key key, Window::InputState state, uint32_t m
return vv->onKey(key, state, modifiers);
}
static bool on_char_handler(SkUnichar c, uint32_t modifiers, void* userData) {
VulkanViewer* vv = reinterpret_cast<VulkanViewer*>(userData);
return vv->onChar(c, modifiers);
}
static void on_paint_handler(SkCanvas* canvas, void* userData) {
VulkanViewer* vv = reinterpret_cast<VulkanViewer*>(userData);
@ -46,12 +52,10 @@ DEFINE_string2(match, m, nullptr,
"it is skipped unless some list entry starts with ~");
DEFINE_string(skps, "skps", "Directory to read skps from.");
VulkanViewer::VulkanViewer(int argc, char** argv, void* platformData) : fCurrentMeasurement(0) {
VulkanViewer::VulkanViewer(int argc, char** argv, void* platformData)
: fCurrentMeasurement(0)
, fDisplayStats(false)
{
memset(fMeasurements, 0, sizeof(fMeasurements));
SkDebugf("Command line arguments: ");
@ -67,48 +71,20 @@ VulkanViewer::VulkanViewer(int argc, char** argv, void* platformData) : fCurrent
// register callbacks
fWindow->registerKeyFunc(on_key_handler, this);
fWindow->registerCharFunc(on_char_handler, this);
fWindow->registerPaintFunc(on_paint_handler, this);
// set up slides
this->initSlides();
// set up first frame
SkString title("VulkanViewer: ");
title.append(fSlides[0]->getName());
fCurrentSlide = 0;
fWindow->setTitle(title.c_str());
setupCurrentSlide(-1);
fLocalMatrix.reset();
fWindow->show();
}
static sk_sp<SkPicture> read_picture(const char path[]) {
if (SkCommandLineFlags::ShouldSkip(FLAGS_match, path)) {
return nullptr;
}
SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(path));
if (stream.get() == nullptr) {
SkDebugf("Could not read %s.\n", path);
return nullptr;
}
auto pic = SkPicture::MakeFromStream(stream.get());
if (!pic) {
SkDebugf("Could not read %s as an SkPicture.\n", path);
}
return pic;
}
static sk_sp<SKPSlide> loadSKP(const SkString& path) {
sk_sp<SkPicture> pic = read_picture(path.c_str());
if (!pic) {
return nullptr;
}
SkString name = SkOSPath::Basename(path.c_str());
return sk_sp<SKPSlide>(new SKPSlide(name.c_str(), pic));
}
void VulkanViewer::initSlides() {
const skiagm::GMRegistry* gms(skiagm::GMRegistry::Head());
while (gms) {
@ -132,17 +108,25 @@ void VulkanViewer::initSlides() {
// SKPs
for (int i = 0; i < FLAGS_skps.count(); i++) {
if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
if (SkCommandLineFlags::ShouldSkip(FLAGS_match, FLAGS_skps[i])) {
continue;
}
SkString path(FLAGS_skps[i]);
sk_sp<SKPSlide> slide = loadSKP(path);
sk_sp<SKPSlide> slide(new SKPSlide(SkOSPath::Basename(path.c_str()), path));
if (slide) {
fSlides.push_back(slide);
}
} else {
SkOSFile::Iter it(FLAGS_skps[i], ".skp");
SkString path;
while (it.next(&path)) {
SkString skpName = SkOSPath::Join(FLAGS_skps[i], path.c_str());
sk_sp<SKPSlide> slide = loadSKP(skpName);
SkString skpName;
while (it.next(&skpName)) {
if (SkCommandLineFlags::ShouldSkip(FLAGS_match, skpName.c_str())) {
continue;
}
SkString path = SkOSPath::Join(FLAGS_skps[i], skpName.c_str());
sk_sp<SKPSlide> slide(new SKPSlide(skpName, path));
if (slide) {
fSlides.push_back(slide);
}
@ -157,39 +141,124 @@ VulkanViewer::~VulkanViewer() {
delete fWindow;
}
void VulkanViewer::setupCurrentSlide(int previousSlide) {
SkString title("VulkanViewer: ");
title.append(fSlides[fCurrentSlide]->getName());
fSlides[fCurrentSlide]->load();
if (previousSlide >= 0) {
fSlides[previousSlide]->unload();
}
fWindow->setTitle(title.c_str());
fWindow->inval();
}
#define MAX_ZOOM_LEVEL 8
#define MIN_ZOOM_LEVEL -8
void VulkanViewer::changeZoomLevel(float delta) {
fZoomLevel += delta;
if (fZoomLevel > 0) {
fZoomLevel = SkMinScalar(fZoomLevel, MAX_ZOOM_LEVEL);
fZoomScale = fZoomLevel + SK_Scalar1;
} else if (fZoomLevel < 0) {
fZoomLevel = SkMaxScalar(fZoomLevel, MIN_ZOOM_LEVEL);
fZoomScale = SK_Scalar1 / (SK_Scalar1 - fZoomLevel);
} else {
fZoomScale = SK_Scalar1;
}
this->updateMatrix();
}
void VulkanViewer::updateMatrix(){
SkMatrix m;
m.reset();
if (fZoomLevel) {
SkPoint center;
//m = this->getLocalMatrix();//.invert(&m);
m.mapXY(fZoomCenterX, fZoomCenterY, &center);
SkScalar cx = center.fX;
SkScalar cy = center.fY;
m.setTranslate(-cx, -cy);
m.postScale(fZoomScale, fZoomScale);
m.postTranslate(cx, cy);
}
// TODO: add gesture support
// Apply any gesture matrix
//m.preConcat(fGesture.localM());
//m.preConcat(fGesture.globalM());
fLocalMatrix = m;
}
bool VulkanViewer::onKey(Window::Key key, Window::InputState state, uint32_t modifiers) {
if (Window::kDown_InputState == state && (modifiers & Window::kFirstPress_ModifierKey)) {
if (key == Window::kRight_Key) {
fCurrentSlide++;
if (fCurrentSlide >= fSlides.count()) {
fCurrentSlide = 0;
if (Window::kDown_InputState == state) {
switch (key) {
case Window::kRight_Key: {
int previousSlide = fCurrentSlide;
fCurrentSlide++;
if (fCurrentSlide >= fSlides.count()) {
fCurrentSlide = 0;
}
setupCurrentSlide(previousSlide);
return true;
}
SkString title("VulkanViewer: ");
title.append(fSlides[fCurrentSlide]->getName());
fWindow->setTitle(title.c_str());
} else if (key == Window::kLeft_Key) {
fCurrentSlide--;
if (fCurrentSlide < 0) {
fCurrentSlide = fSlides.count()-1;
case Window::kLeft_Key: {
int previousSlide = fCurrentSlide;
fCurrentSlide--;
if (fCurrentSlide < 0) {
fCurrentSlide = fSlides.count() - 1;
}
SkString title("VulkanViewer: ");
title.append(fSlides[fCurrentSlide]->getName());
fWindow->setTitle(title.c_str());
setupCurrentSlide(previousSlide);
return true;
}
SkString title("VulkanViewer: ");
title.append(fSlides[fCurrentSlide]->getName());
fWindow->setTitle(title.c_str());
case Window::kUp_Key: {
this->changeZoomLevel(1.f / 32.f);
return true;
}
case Window::kDown_Key: {
this->changeZoomLevel(-1.f / 32.f);
return true;
}
default:
break;
}
}
return true;
return false;
}
bool VulkanViewer::onChar(SkUnichar c, uint32_t modifiers) {
if ('s' == c) {
fDisplayStats = !fDisplayStats;
return true;
}
return false;
}
void VulkanViewer::onPaint(SkCanvas* canvas) {
canvas->clear(SK_ColorWHITE);
canvas->save();
fSlides[fCurrentSlide]->draw(canvas);
canvas->restore();
int count = canvas->save();
canvas->setMatrix(fLocalMatrix);
drawStats(canvas);
fSlides[fCurrentSlide]->draw(canvas);
canvas->restoreToCount(count);
if (fDisplayStats) {
drawStats(canvas);
}
}
void VulkanViewer::drawStats(SkCanvas* canvas) {
@ -240,5 +309,8 @@ void VulkanViewer::onIdle(double ms) {
fCurrentMeasurement &= (kMeasurementCount - 1); // fast mod
SkASSERT(fCurrentMeasurement < kMeasurementCount);
fWindow->onPaint();
fAnimTimer.updateTime();
if (fDisplayStats || fSlides[fCurrentSlide]->animate(fAnimTimer)) {
fWindow->inval();
}
}

View File

@ -11,6 +11,7 @@
#include "../Application.h"
#include "../Window.h"
#include "gm.h"
#include "SkAnimTimer.h"
#include "Slide.h"
class SkCanvas;
@ -21,23 +22,38 @@ public:
~VulkanViewer() override;
bool onKey(Window::Key key, Window::InputState state, uint32_t modifiers);
bool onChar(SkUnichar, uint32_t modifiers);
void onPaint(SkCanvas* canvas);
void onIdle(double ms) override;
private:
void initSlides();
void setupCurrentSlide(int previousSlide);
void drawStats(SkCanvas* canvas);
void changeZoomLevel(float delta);
void updateMatrix();
Window* fWindow;
static const int kMeasurementCount = 64; // should be power of 2 for fast mod
double fMeasurements[kMeasurementCount];
int fCurrentMeasurement;
SkAnimTimer fAnimTimer;
SkTArray<sk_sp<Slide>> fSlides;
int fCurrentSlide;
bool fDisplayStats;
// transform data
SkMatrix fLocalMatrix;
SkScalar fZoomCenterX;
SkScalar fZoomCenterY;
SkScalar fZoomLevel;
SkScalar fZoomScale;
};

View File

@ -275,3 +275,7 @@ bool Window_win::attach(BackEndType attachType, int msaaSampleCount, AttachmentI
return (SkToBool(fTestContext));
}
void Window_win::inval() {
InvalidateRect(fHWnd, nullptr, false);
}

View File

@ -23,6 +23,8 @@ public:
bool attach(BackEndType attachType, int msaaSampleCount, AttachmentInfo*) override;
void inval() override;
private:
HINSTANCE fHInstance;
HWND fHWnd;

View File

@ -72,11 +72,11 @@ static int main_common(HINSTANCE hInstance, int show, int argc, char**argv) {
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
previousTime = currentTime;
currentTime = now_ms();
app->onIdle(currentTime - previousTime);
} else {
previousTime = currentTime;
currentTime = now_ms();
app->onIdle(currentTime - previousTime);
}
}
delete app;