Some more improvements/fixes to the VulkanViewer

* display GM name in title bar
* add ms timer for update loop
* add ms/frame meter
* fix vsync
* add some notes for later

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

Review URL: https://codereview.chromium.org/1873453002
diff --git a/gyp/vulkanviewer.gyp b/gyp/vulkanviewer.gyp
index d58613d..fb67e55 100644
--- a/gyp/vulkanviewer.gyp
+++ b/gyp/vulkanviewer.gyp
@@ -24,6 +24,7 @@
         '../src/gpu',
         '../src/images',
         '../src/image',
+        '../tools/timer',
       ],
       'sources': [
         '../gm/gm.cpp',
diff --git a/tools/vulkan/Application.h b/tools/vulkan/Application.h
index 623496d..4504d17 100644
--- a/tools/vulkan/Application.h
+++ b/tools/vulkan/Application.h
@@ -14,7 +14,7 @@
 
     virtual ~Application() {}
 
-    virtual void onIdle(float dt) = 0;
+    virtual void onIdle(double ms) = 0;
 };
 
 #endif
diff --git a/tools/vulkan/VulkanTestContext.cpp b/tools/vulkan/VulkanTestContext.cpp
index f9f037d..05ebfe7 100644
--- a/tools/vulkan/VulkanTestContext.cpp
+++ b/tools/vulkan/VulkanTestContext.cpp
@@ -66,7 +66,7 @@
             break;
         }
     }
-    SkASSERT(0 <= fPresentQueueIndex && fPresentQueueIndex < queueCount);
+    SkASSERT(fPresentQueueIndex < queueCount);
 
     VkBool32 supported;
     VkResult res = GR_VK_CALL(fBackendContext->fInterface,
@@ -184,13 +184,14 @@
                                         VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
                                         VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
 
-    // FIFO is the only mode universally supported
+    // If mailbox mode is available, use it, as it is the lowest-latency non-
+    // tearing mode. If not, fall back to FIFO which is always available.
     VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
-    bool vsync = false;
     for (uint32_t i = 0; i < presentModeCount; ++i) {
-        if ((vsync && VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) ||
-            (!vsync && VK_PRESENT_MODE_IMMEDIATE_KHR == presentModes[i])) {
+        // use mailbox
+        if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
             mode = presentModes[i];
+            break;
         }
     }
 
@@ -447,9 +448,10 @@
                                                   &backbuffer->fImageIndex));
     if (VK_ERROR_SURFACE_LOST_KHR == res) {
         // need to figure out how to create a new vkSurface without the platformData*
+        // maybe use attach somehow? but need a Window
         return nullptr;
     }
-    if (VK_ERROR_OUT_OF_DATE_KHR == res || VK_ERROR_SURFACE_LOST_KHR == res) {
+    if (VK_ERROR_OUT_OF_DATE_KHR == res) {
         // tear swapchain down and try again
         if (!this->createSwapchain(0, 0)) {
             return nullptr;
diff --git a/tools/vulkan/Window.cpp b/tools/vulkan/Window.cpp
index 86f1814..2741f4d 100644
--- a/tools/vulkan/Window.cpp
+++ b/tools/vulkan/Window.cpp
@@ -61,6 +61,8 @@
         canvas->flush();
 
         fTestContext->swapBuffers();
+    } else {
+        // try recreating testcontext
     }
 
 }
diff --git a/tools/vulkan/Window.h b/tools/vulkan/Window.h
index dbfe4e1..f7b4f13 100644
--- a/tools/vulkan/Window.h
+++ b/tools/vulkan/Window.h
@@ -27,12 +27,12 @@
         int fStencilBits;
     };
 
-    enum BackEndTypes {
+    enum BackEndType {
         kNativeGL_BackendType,
         kVulkan_BackendType
     };
 
-    virtual bool attach(BackEndTypes attachType, int msaaSampleCount, AttachmentInfo*) = 0;
+    virtual bool attach(BackEndType attachType, int msaaSampleCount, AttachmentInfo*) = 0;
     void detach();
 
     // input handling
diff --git a/tools/vulkan/viewer/VulkanViewer.cpp b/tools/vulkan/viewer/VulkanViewer.cpp
index 27e7b1c..5c6e780 100644
--- a/tools/vulkan/viewer/VulkanViewer.cpp
+++ b/tools/vulkan/viewer/VulkanViewer.cpp
@@ -31,8 +31,10 @@
     return vv->onPaint(canvas);
 }
 
-VulkanViewer::VulkanViewer(int argc, char** argv, void* platformData) :
-    fGMs(skiagm::GMRegistry::Head()){
+VulkanViewer::VulkanViewer(int argc, char** argv, void* platformData)
+    : fGMs(skiagm::GMRegistry::Head())
+    , fCurrentMeasurement(0) {
+    memset(fMeasurements, 0, sizeof(fMeasurements));
 
     fWindow = Window::CreateNativeWindow(platformData);
     fWindow->attach(Window::kVulkan_BackendType, 0, nullptr);
@@ -41,7 +43,10 @@
     fWindow->registerKeyFunc(on_key_handler, this);
     fWindow->registerPaintFunc(on_paint_handler, this);
 
-    fWindow->setTitle("VulkanViewer");
+    SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(nullptr));
+    SkString title("VulkanViewer: ");
+    title.append(gm->getName());
+    fWindow->setTitle(title.c_str());
     fWindow->show();
 }
 
@@ -54,7 +59,11 @@
     if (Window::kDown_InputState == state && (modifiers & Window::kFirstPress_ModifierKey) &&
         key == Window::kRight_Key) {
         fGMs = fGMs->next();
-    } 
+        SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(nullptr));
+        SkString title("VulkanViewer: ");
+        title.append(gm->getName());
+        fWindow->setTitle(title.c_str());
+    }
 
     return true;
 }
@@ -63,12 +72,59 @@
     SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(nullptr));
 
     canvas->save();
-
     gm->draw(canvas);
+    canvas->restore();
+
+    drawStats(canvas);
+}
+
+void VulkanViewer::drawStats(SkCanvas* canvas) {
+    static const float kPixelPerMS = 2.0f;
+    static const int kDisplayWidth = 130;
+    static const int kDisplayHeight = 100;
+    static const int kDisplayPadding = 10;
+    static const int kGraphPadding = 3;
+    static const SkScalar kBaseMS = 1000.f / 60.f;  // ms/frame to hit 60 fps
+
+    SkISize canvasSize = canvas->getDeviceSize();
+    SkRect rect = SkRect::MakeXYWH(SkIntToScalar(canvasSize.fWidth-kDisplayWidth-kDisplayPadding),
+                                   SkIntToScalar(kDisplayPadding),
+                                   SkIntToScalar(kDisplayWidth), SkIntToScalar(kDisplayHeight));
+    SkPaint paint;
+    canvas->save();
+
+    canvas->clipRect(rect);
+    paint.setColor(SK_ColorBLACK);
+    canvas->drawRect(rect, paint);
+    // draw the 16ms line
+    paint.setColor(SK_ColorLTGRAY);
+    canvas->drawLine(rect.fLeft, rect.fBottom - kBaseMS*kPixelPerMS,
+                     rect.fRight, rect.fBottom - kBaseMS*kPixelPerMS, paint);
+    paint.setColor(SK_ColorRED);
+    paint.setStyle(SkPaint::kStroke_Style);
+    canvas->drawRect(rect, paint);
+
+    int x = SkScalarTruncToInt(rect.fLeft) + kGraphPadding;
+    const int xStep = 2;
+    const int startY = SkScalarTruncToInt(rect.fBottom);
+    int i = fCurrentMeasurement;
+    do {
+        int endY = startY - (int)(fMeasurements[i] * kPixelPerMS + 0.5);  // round to nearest value
+        canvas->drawLine(SkIntToScalar(x), SkIntToScalar(startY),
+                         SkIntToScalar(x), SkIntToScalar(endY), paint);
+        i++;
+        i &= (kMeasurementCount - 1);  // fast mod
+        x += xStep;
+    } while (i != fCurrentMeasurement);
 
     canvas->restore();
 }
 
-void VulkanViewer::onIdle(float dt) {
+void VulkanViewer::onIdle(double ms) {
+    // Record measurements
+    fMeasurements[fCurrentMeasurement++] = ms;
+    fCurrentMeasurement &= (kMeasurementCount - 1);  // fast mod
+    SkASSERT(fCurrentMeasurement < kMeasurementCount);
+
     fWindow->onPaint();
 }
diff --git a/tools/vulkan/viewer/VulkanViewer.h b/tools/vulkan/viewer/VulkanViewer.h
index 29cbbef..b012cf1 100644
--- a/tools/vulkan/viewer/VulkanViewer.h
+++ b/tools/vulkan/viewer/VulkanViewer.h
@@ -22,11 +22,17 @@
     bool onKey(Window::Key key, Window::InputState state, uint32_t modifiers);
     void onPaint(SkCanvas* canvas);
 
-    void onIdle(float dt) override;
+    void onIdle(double ms) override;
 
 private:
+    void drawStats(SkCanvas* canvas);
+
     Window*      fWindow;
 
+    static const int kMeasurementCount = 64;  // should be power of 2 for fast mod
+    double fMeasurements[kMeasurementCount];
+    int fCurrentMeasurement;
+
     const skiagm::GMRegistry* fGMs;
 };
 
diff --git a/tools/vulkan/win/Window_win.cpp b/tools/vulkan/win/Window_win.cpp
index 0c9e802..0623839 100644
--- a/tools/vulkan/win/Window_win.cpp
+++ b/tools/vulkan/win/Window_win.cpp
@@ -262,7 +262,7 @@
 }
 
 
-bool Window_win::attach(BackEndTypes attachType, int msaaSampleCount, AttachmentInfo*) {
+bool Window_win::attach(BackEndType attachType, int msaaSampleCount, AttachmentInfo*) {
     if (kVulkan_BackendType != attachType) {
         return false;
     }
diff --git a/tools/vulkan/win/Window_win.h b/tools/vulkan/win/Window_win.h
index 4a5b7ff..6b95b56 100644
--- a/tools/vulkan/win/Window_win.h
+++ b/tools/vulkan/win/Window_win.h
@@ -21,7 +21,7 @@
     void setTitle(const char*) override;
     void show() override;
 
-    bool attach(BackEndTypes attachType, int msaaSampleCount, AttachmentInfo*) override;
+    bool attach(BackEndType attachType, int msaaSampleCount, AttachmentInfo*) override;
 
 private:
     HINSTANCE fHInstance;
diff --git a/tools/vulkan/win/main_win.cpp b/tools/vulkan/win/main_win.cpp
index 34e522a..883b96d 100644
--- a/tools/vulkan/win/main_win.cpp
+++ b/tools/vulkan/win/main_win.cpp
@@ -9,6 +9,7 @@
 #include <tchar.h>
 
 #include "SkTypes.h"
+#include "Timer.h"
 #include "Window_win.h"
 #include "../Application.h"
 
@@ -24,6 +25,8 @@
 #endif
 }
 
+static double now_ms() { return SkTime::GetNSecs() * 1e-6; }
+
 // This file can work with GUI or CONSOLE subsystem types since we define _tWinMain and main().
 
 static int main_common(HINSTANCE hInstance, int show, int argc, char**argv);
@@ -60,6 +63,10 @@
     Application* app = Application::Create(argc, argv, (void*)hInstance);
 
     MSG msg = { 0 };
+
+    double currentTime = 0.0;
+    double previousTime = 0.0;
+
     // Main message loop
     while (WM_QUIT != msg.message) {
         if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
@@ -67,7 +74,9 @@
             DispatchMessage(&msg);
         } 
         
-        app->onIdle(0.0f);
+        previousTime = currentTime;
+        currentTime = now_ms();
+        app->onIdle(currentTime - previousTime);
     }
 
     delete app;