Vulkan: Count active renderpasses in overlay.

Useful debugging information for benchmarks. Also helpful when working
with the command graph to ensure we don't regress performance.

Bug: angleproject:4029
Bug: angleproject:4320
Change-Id: Ibe224c40a3acaca9231bf3869486a0f8bba07ba0
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2036402
Reviewed-by: Tim Van Patten <timvp@google.com>
Reviewed-by: Tobin Ehlis <tobine@google.com>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/scripts/code_generation_hashes/overlay_widgets.json b/scripts/code_generation_hashes/overlay_widgets.json
index edfd26a..17b89b1 100644
--- a/scripts/code_generation_hashes/overlay_widgets.json
+++ b/scripts/code_generation_hashes/overlay_widgets.json
@@ -1,8 +1,8 @@
 {
   "src/libANGLE/Overlay_autogen.cpp":
-    "514b8108f62ef616c296dc511bb2f644",
+    "1c882462aacb436dbd88d6e7fdbe4473",
   "src/libANGLE/gen_overlay_widgets.py":
     "07252fbde304fd48559ae07f8f920a08",
   "src/libANGLE/overlay_widgets.json":
-    "552b1e2883a12c38d427c7fbd1c2bf22"
+    "c84d5c85c6bd21d30056ad2fb9213e38"
 }
\ No newline at end of file
diff --git a/src/libANGLE/Overlay.cpp b/src/libANGLE/Overlay.cpp
index 2de65d2..4a09331 100644
--- a/src/libANGLE/Overlay.cpp
+++ b/src/libANGLE/Overlay.cpp
@@ -26,6 +26,7 @@
     {"VulkanLastValidationMessage", WidgetId::VulkanLastValidationMessage},
     {"VulkanValidationMessageCount", WidgetId::VulkanValidationMessageCount},
     {"VulkanCommandGraphSize", WidgetId::VulkanCommandGraphSize},
+    {"VulkanRenderPassCount", WidgetId::VulkanRenderPassCount},
     {"VulkanSecondaryCommandBufferPoolWaste", WidgetId::VulkanSecondaryCommandBufferPoolWaste},
 };
 }  // namespace
diff --git a/src/libANGLE/Overlay.h b/src/libANGLE/Overlay.h
index 7662cf4..15af6a2 100644
--- a/src/libANGLE/Overlay.h
+++ b/src/libANGLE/Overlay.h
@@ -127,9 +127,19 @@
 };
 
 #if ANGLE_ENABLE_OVERLAY
-using OverlayType = Overlay;
+using OverlayType            = Overlay;
+using CountWidget            = overlay::Count;
+using PerSecondWidget        = overlay::PerSecond;
+using RunningGraphWidget     = overlay::RunningGraph;
+using RunningHistogramWidget = overlay::RunningHistogram;
+using TextWidget             = overlay::Text;
 #else   // !ANGLE_ENABLE_OVERLAY
-using OverlayType = DummyOverlay;
+using OverlayType            = DummyOverlay;
+using CountWidget            = const overlay::Dummy;
+using PerSecondWidget        = const overlay::Dummy;
+using RunningGraphWidget     = const overlay::Dummy;
+using RunningHistogramWidget = const overlay::Dummy;
+using TextWidget             = const overlay::Dummy;
 #endif  // ANGLE_ENABLE_OVERLAY
 
 }  // namespace gl
diff --git a/src/libANGLE/OverlayWidgets.cpp b/src/libANGLE/OverlayWidgets.cpp
index 50cfcc1..9ea17a9 100644
--- a/src/libANGLE/OverlayWidgets.cpp
+++ b/src/libANGLE/OverlayWidgets.cpp
@@ -205,6 +205,11 @@
                                              TextWidgetData *textWidget,
                                              GraphWidgetData *graphWidget,
                                              OverlayWidgetCounts *widgetCounts);
+    static void AppendVulkanRenderPassCount(const overlay::Widget *widget,
+                                            const gl::Extents &imageExtent,
+                                            TextWidgetData *textWidget,
+                                            GraphWidgetData *graphWidget,
+                                            OverlayWidgetCounts *widgetCounts);
     static void AppendVulkanSecondaryCommandBufferPoolWaste(const overlay::Widget *widget,
                                                             const gl::Extents &imageExtent,
                                                             TextWidgetData *textWidget,
@@ -335,6 +340,33 @@
     }
 }
 
+void AppendWidgetDataHelper::AppendVulkanRenderPassCount(const overlay::Widget *widget,
+                                                         const gl::Extents &imageExtent,
+                                                         TextWidgetData *textWidget,
+                                                         GraphWidgetData *graphWidget,
+                                                         OverlayWidgetCounts *widgetCounts)
+{
+    const overlay::RunningGraph *renderPassCount =
+        static_cast<const overlay::RunningGraph *>(widget);
+
+    const size_t maxValue     = *std::max_element(renderPassCount->runningValues.begin(),
+                                              renderPassCount->runningValues.end());
+    const int32_t graphHeight = std::abs(widget->coords[3] - widget->coords[1]);
+    const float graphScale    = static_cast<float>(graphHeight) / maxValue;
+
+    AppendGraphCommon(widget, imageExtent, renderPassCount->runningValues,
+                      renderPassCount->lastValueIndex + 1, graphScale, graphWidget, widgetCounts);
+
+    if ((*widgetCounts)[WidgetInternalType::Text] <
+        kWidgetInternalTypeMaxWidgets[WidgetInternalType::Text])
+    {
+        std::ostringstream text;
+        text << "RenderPass Count (Max: " << maxValue << ")";
+        AppendTextCommon(&renderPassCount->description, imageExtent, text.str(), textWidget,
+                         widgetCounts);
+    }
+}
+
 void AppendWidgetDataHelper::AppendVulkanSecondaryCommandBufferPoolWaste(
     const overlay::Widget *widget,
     const gl::Extents &imageExtent,
@@ -393,6 +425,8 @@
      overlay_impl::AppendWidgetDataHelper::AppendVulkanValidationMessageCount},
     {WidgetId::VulkanCommandGraphSize,
      overlay_impl::AppendWidgetDataHelper::AppendVulkanCommandGraphSize},
+    {WidgetId::VulkanRenderPassCount,
+     overlay_impl::AppendWidgetDataHelper::AppendVulkanRenderPassCount},
     {WidgetId::VulkanSecondaryCommandBufferPoolWaste,
      overlay_impl::AppendWidgetDataHelper::AppendVulkanSecondaryCommandBufferPoolWaste},
 };
@@ -495,6 +529,7 @@
         }
 
         AppendWidgetDataFunc appendFunc = kWidgetIdToAppendDataFuncMap[id];
+        ASSERT(appendFunc);
         appendFunc(widget.get(), imageExtents,
                    &textWidgets->widgets[widgetCounts[WidgetInternalType::Text]],
                    &graphWidgets->widgets[widgetCounts[WidgetInternalType::Graph]], &widgetCounts);
diff --git a/src/libANGLE/OverlayWidgets.h b/src/libANGLE/OverlayWidgets.h
index 085f2f4..7352834 100644
--- a/src/libANGLE/OverlayWidgets.h
+++ b/src/libANGLE/OverlayWidgets.h
@@ -59,6 +59,8 @@
     VulkanValidationMessageCount,
     // Number of nodes in command graph (RunningGraph).
     VulkanCommandGraphSize,
+    // Number of RenderPasses in a frame (RunningGraph).
+    VulkanRenderPassCount,
     // Secondary Command Buffer pool memory waste (RunningHistogram).
     VulkanSecondaryCommandBufferPoolWaste,
 
diff --git a/src/libANGLE/Overlay_autogen.cpp b/src/libANGLE/Overlay_autogen.cpp
index f202d0e..18c803d 100644
--- a/src/libANGLE/Overlay_autogen.cpp
+++ b/src/libANGLE/Overlay_autogen.cpp
@@ -1,7 +1,7 @@
 // GENERATED FILE - DO NOT EDIT.
 // Generated by gen_overlay_widgets.py using data from overlay_widgets.json.
 //
-// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
@@ -147,6 +147,49 @@
     }
 
     {
+        RunningGraph *widget = new RunningGraph(60);
+        {
+            const int32_t fontSize = GetFontSize(0, kLargeFont);
+            const int32_t offsetX  = 10;
+            const int32_t offsetY  = 100;
+            const int32_t width    = 5 * static_cast<uint32_t>(widget->runningValues.size());
+            const int32_t height   = 100;
+
+            widget->type      = WidgetType::RunningGraph;
+            widget->fontSize  = fontSize;
+            widget->coords[0] = offsetX;
+            widget->coords[1] = offsetY;
+            widget->coords[2] = offsetX + width;
+            widget->coords[3] = offsetY + height;
+            widget->color[0]  = 0.294117647059;
+            widget->color[1]  = 0.78431372549;
+            widget->color[2]  = 0.0;
+            widget->color[3]  = 0.78431372549;
+        }
+        mState.mOverlayWidgets[WidgetId::VulkanRenderPassCount].reset(widget);
+        {
+            const int32_t fontSize = GetFontSize(kFontLayerSmall, kLargeFont);
+            const int32_t offsetX =
+                mState.mOverlayWidgets[WidgetId::VulkanRenderPassCount]->coords[0];
+            const int32_t offsetY =
+                mState.mOverlayWidgets[WidgetId::VulkanRenderPassCount]->coords[1];
+            const int32_t width  = 40 * kFontGlyphWidths[fontSize];
+            const int32_t height = kFontGlyphHeights[fontSize];
+
+            widget->description.type      = WidgetType::Text;
+            widget->description.fontSize  = fontSize;
+            widget->description.coords[0] = offsetX;
+            widget->description.coords[1] = std::max(offsetY - height, 1);
+            widget->description.coords[2] = offsetX + width;
+            widget->description.coords[3] = offsetY;
+            widget->description.color[0]  = 0.294117647059;
+            widget->description.color[1]  = 0.78431372549;
+            widget->description.color[2]  = 0.0;
+            widget->description.color[3]  = 1.0;
+        }
+    }
+
+    {
         RunningHistogram *widget = new RunningHistogram(50);
         {
             const int32_t fontSize = GetFontSize(0, kLargeFont);
diff --git a/src/libANGLE/overlay_widgets.json b/src/libANGLE/overlay_widgets.json
index 0f65f75..d5fbe25 100644
--- a/src/libANGLE/overlay_widgets.json
+++ b/src/libANGLE/overlay_widgets.json
@@ -67,6 +67,20 @@
             }
         },
         {
+            "name": "VulkanRenderPassCount",
+            "type": "RunningGraph(60)",
+            "color": [75, 200, 0, 200],
+            "coords": [10, 100],
+            "bar_width": 5,
+            "height": 100,
+            "description": {
+                "color": [75, 200, 0, 255],
+                "coords": ["VulkanRenderPassCount.left.align", "VulkanRenderPassCount.top.adjacent"],
+                "font": "small",
+                "length": 40
+            }
+        },
+        {
             "name": "VulkanSecondaryCommandBufferPoolWaste",
             "type": "RunningHistogram(50)",
             "color": [255, 200, 75, 200],
diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.cpp b/src/libANGLE/renderer/vulkan/CommandGraph.cpp
index 79a2c16..0452487 100644
--- a/src/libANGLE/renderer/vulkan/CommandGraph.cpp
+++ b/src/libANGLE/renderer/vulkan/CommandGraph.cpp
@@ -474,6 +474,8 @@
 angle::Result CommandGraphNode::beginInsideRenderPassRecording(ContextVk *context,
                                                                CommandBuffer **commandsOut)
 {
+    context->getCommandGraph()->tickRenderPassCount();
+
     ASSERT(!mHasChildren);
 
     // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
@@ -939,7 +941,8 @@
 CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *poolAllocator)
     : mEnableGraphDiagnostics(enableGraphDiagnostics),
       mPoolAllocator(poolAllocator),
-      mLastBarrierIndex(kInvalidNodeIndex)
+      mLastBarrierIndex(kInvalidNodeIndex),
+      mRenderPassCount(0)
 {
     // Push so that allocations made from here will be recycled in clear() below.
     mPoolAllocator->push();
@@ -998,6 +1001,7 @@
     ASSERT(!mNodes.empty());
 
     updateOverlay(context);
+    mRenderPassCount = 0;
 
     size_t previousBarrierIndex       = 0;
     CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
@@ -1321,9 +1325,15 @@
 
     overlay->getRunningGraphWidget(gl::WidgetId::VulkanCommandGraphSize)->add(mNodes.size());
 
-    overlay->getRunningHistogramWidget(gl::WidgetId::VulkanSecondaryCommandBufferPoolWaste)
-        ->set(CalculateSecondaryCommandBufferPoolWaste(mNodes));
-    overlay->getRunningHistogramWidget(gl::WidgetId::VulkanSecondaryCommandBufferPoolWaste)->next();
+    gl::RunningHistogramWidget *poolWaste =
+        overlay->getRunningHistogramWidget(gl::WidgetId::VulkanSecondaryCommandBufferPoolWaste);
+    poolWaste->set(CalculateSecondaryCommandBufferPoolWaste(mNodes));
+    poolWaste->next();
+
+    gl::RunningGraphWidget *renderPassCount =
+        overlay->getRunningGraphWidget(gl::WidgetId::VulkanRenderPassCount);
+    renderPassCount->add(mRenderPassCount);
+    renderPassCount->next();
 }
 
 CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.h b/src/libANGLE/renderer/vulkan/CommandGraph.h
index ca679cb..ae1bea1 100644
--- a/src/libANGLE/renderer/vulkan/CommandGraph.h
+++ b/src/libANGLE/renderer/vulkan/CommandGraph.h
@@ -608,6 +608,7 @@
     void makeHostVisibleBufferWriteAvailable();
     // External memory synchronization:
     void syncExternalMemory();
+    void tickRenderPassCount() { mRenderPassCount++; }
 
   private:
     CommandGraphNode *allocateBarrierNode(CommandGraphNodeFunction function,
@@ -672,6 +673,7 @@
     // issued.
     static constexpr size_t kInvalidNodeIndex = std::numeric_limits<std::size_t>::max();
     size_t mLastBarrierIndex;
+    uint32_t mRenderPassCount;
 };
 
 // CommandGraphResource inlines.
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
index e820f47..3666bab 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
@@ -1298,6 +1298,15 @@
 angle::Result ContextVk::submitFrame(const VkSubmitInfo &submitInfo,
                                      vk::PrimaryCommandBuffer &&commandBuffer)
 {
+    // Update overlay if active.
+    if (!commandGraphEnabled())
+    {
+        gl::RunningGraphWidget *renderPassCount =
+            mState.getOverlay()->getRunningGraphWidget(gl::WidgetId::VulkanRenderPassCount);
+        renderPassCount->add(mRenderPassCommands.getAndResetCounter());
+        renderPassCount->next();
+    }
+
     ANGLE_TRY(ensureSubmitFenceInitialized());
     ANGLE_TRY(mCommandQueue.submitFrame(this, mContextPriority, submitInfo, mSubmitFence,
                                         &mCurrentGarbage, &mCommandPool, std::move(commandBuffer)));
@@ -3797,7 +3806,7 @@
     mCommandBuffer.reset();
 }
 
-RenderPassCommandBuffer::RenderPassCommandBuffer() = default;
+RenderPassCommandBuffer::RenderPassCommandBuffer() : mCounter(0) {}
 
 RenderPassCommandBuffer::~RenderPassCommandBuffer()
 {
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.h b/src/libANGLE/renderer/vulkan/ContextVk.h
index ba8bf2d..f2dfffb 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.h
+++ b/src/libANGLE/renderer/vulkan/ContextVk.h
@@ -172,7 +172,15 @@
     bool empty() const { return mCommandBuffer.empty(); }
     void reset();
 
+    uint32_t getAndResetCounter()
+    {
+        uint32_t count = mCounter;
+        mCounter       = 0;
+        return count;
+    }
+
   private:
+    uint32_t mCounter;
     vk::RenderPassDesc mRenderPassDesc;
     vk::AttachmentOpsArray mAttachmentOps;
     vk::Framebuffer mFramebuffer;