diff options
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/OverlayWidgets.cpp')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/OverlayWidgets.cpp | 737 |
1 files changed, 737 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/OverlayWidgets.cpp b/gfx/angle/checkout/src/libANGLE/OverlayWidgets.cpp new file mode 100644 index 0000000000..f0581ce9d8 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/OverlayWidgets.cpp @@ -0,0 +1,737 @@ +// +// Copyright 2019 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. +// +// OverlayWidgets.cpp: +// Implements functions that interpret widget data. Data formats and limits correspond to the +// Vulkan implementation (as the only implementation). They are generic enough so other backends +// could respect them too, if they implement the overlay. +// + +#include "libANGLE/Overlay.h" +#include "libANGLE/Overlay_font_autogen.h" + +#include <functional> + +namespace gl +{ +namespace +{ +// Internally, every widget is either Text or Graph. +enum class WidgetInternalType +{ + Text, + Graph, + + InvalidEnum, + EnumCount = InvalidEnum, +}; + +// A map that says how the API-facing widget types map to internal types. +constexpr angle::PackedEnumMap<WidgetType, WidgetInternalType> kWidgetTypeToInternalMap = { + {WidgetType::Count, WidgetInternalType::Text}, + {WidgetType::Text, WidgetInternalType::Text}, + {WidgetType::PerSecond, WidgetInternalType::Text}, + {WidgetType::RunningGraph, WidgetInternalType::Graph}, + {WidgetType::RunningHistogram, WidgetInternalType::Graph}, +}; + +// Structures and limits matching uniform buffers in vulkan/shaders/src/OverlayDraw.comp. The size +// of text and graph widgets is chosen such that they could fit in uniform buffers with minimum +// required Vulkan size. +constexpr size_t kMaxRenderableTextWidgets = 32; +constexpr size_t kMaxRenderableGraphWidgets = 32; +constexpr size_t kMaxTextLength = 256; +constexpr size_t kMaxGraphDataSize = 256; + +constexpr angle::PackedEnumMap<WidgetInternalType, size_t> kWidgetInternalTypeMaxWidgets = { + {WidgetInternalType::Text, kMaxRenderableTextWidgets}, + {WidgetInternalType::Graph, kMaxRenderableGraphWidgets}, +}; + +ANGLE_ENABLE_STRUCT_PADDING_WARNINGS + +// Structure matching buffer in vulkan/shaders/src/OverlayCull.comp. +struct WidgetCoordinates +{ + uint32_t coordinates[kMaxRenderableTextWidgets + kMaxRenderableGraphWidgets][4]; +}; + +// Structures matching buffers in vulkan/shaders/src/OverlayDraw.comp. +struct TextWidgetData +{ + uint32_t coordinates[4]; + float color[4]; + uint32_t fontSize[3]; + uint32_t padding; + uint8_t text[kMaxTextLength]; +}; + +struct GraphWidgetData +{ + uint32_t coordinates[4]; + float color[4]; + uint32_t valueWidth; + uint32_t padding[3]; + uint32_t values[kMaxGraphDataSize]; +}; + +struct TextWidgets +{ + TextWidgetData widgets[kMaxRenderableTextWidgets]; +}; + +struct GraphWidgets +{ + GraphWidgetData widgets[kMaxRenderableGraphWidgets]; +}; + +ANGLE_DISABLE_STRUCT_PADDING_WARNINGS + +uint32_t GetWidgetCoord(int32_t src, uint32_t extent) +{ + int32_t dst = src < 0 ? extent + src : src; + + return std::min<uint32_t>(std::max(dst, 0), extent - 1); +} + +void GetWidgetCoordinates(const int32_t srcCoords[4], + const gl::Extents &imageExtent, + uint32_t dstCoordsOut[4]) +{ + dstCoordsOut[0] = GetWidgetCoord(srcCoords[0], imageExtent.width); + dstCoordsOut[1] = GetWidgetCoord(srcCoords[1], imageExtent.height); + dstCoordsOut[2] = GetWidgetCoord(srcCoords[2], imageExtent.width); + dstCoordsOut[3] = GetWidgetCoord(srcCoords[3], imageExtent.height); +} + +void GetWidgetColor(const float srcColor[4], float dstColor[4]) +{ + memcpy(dstColor, srcColor, 4 * sizeof(dstColor[0])); +} + +void GetTextFontSize(int srcFontSize, uint32_t dstFontSize[3]) +{ + // .xy contains the font glyph width/height + dstFontSize[0] = overlay::kFontGlyphWidth >> srcFontSize; + dstFontSize[1] = overlay::kFontGlyphHeight >> srcFontSize; + // .z contains the mip + dstFontSize[2] = srcFontSize; +} + +void GetGraphValueWidth(const int32_t srcCoords[4], size_t valueCount, uint32_t *dstValueWidth) +{ + const int32_t graphWidth = std::abs(srcCoords[2] - srcCoords[0]); + + // If valueCount doesn't divide graphWidth, the graph bars won't fit well in its frame. + // Fix initOverlayWidgets() in that case. + ASSERT(graphWidth % valueCount == 0); + + *dstValueWidth = graphWidth / valueCount; +} + +void GetTextString(const std::string &src, uint8_t textOut[kMaxTextLength]) +{ + for (size_t i = 0; i < src.length() && i < kMaxTextLength; ++i) + { + // The font image has 95 ASCII characters starting from ' '. + textOut[i] = src[i] - ' '; + } +} + +void GetGraphValues(const std::vector<uint64_t> srcValues, + size_t startIndex, + float scale, + uint32_t valuesOut[kMaxGraphDataSize]) +{ + ASSERT(srcValues.size() <= kMaxGraphDataSize); + + for (size_t i = 0; i < srcValues.size(); ++i) + { + size_t index = (startIndex + i) % srcValues.size(); + valuesOut[i] = static_cast<uint32_t>(srcValues[index] * scale); + } +} + +std::vector<uint64_t> CreateHistogram(const std::vector<uint64_t> values) +{ + std::vector<uint64_t> histogram(values.size(), 0); + + for (uint64_t rank : values) + { + ++histogram[static_cast<size_t>(rank)]; + } + + return histogram; +} + +using OverlayWidgetCounts = angle::PackedEnumMap<WidgetInternalType, uint32_t>; +using AppendWidgetDataFunc = void (*)(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts); +} // namespace + +namespace overlay_impl +{ +#define ANGLE_DECLARE_APPEND_WIDGET_PROC(WIDGET_ID) \ + static void Append##WIDGET_ID(const overlay::Widget *widget, const gl::Extents &imageExtent, \ + TextWidgetData *textWidget, GraphWidgetData *graphWidget, \ + OverlayWidgetCounts *widgetCounts); + +// This class interprets the generic data collected in every element into a human-understandable +// widget. This often means generating text specific to this item and scaling graph data to +// something sensible. +class AppendWidgetDataHelper +{ + public: + ANGLE_WIDGET_ID_X(ANGLE_DECLARE_APPEND_WIDGET_PROC) + + private: + static std::ostream &OutputPerSecond(std::ostream &out, const overlay::PerSecond *perSecond); + + static std::ostream &OutputText(std::ostream &out, const overlay::Text *text); + + static std::ostream &OutputCount(std::ostream &out, const overlay::Count *count); + + static void AppendTextCommon(const overlay::Widget *widget, + const gl::Extents &imageExtent, + const std::string &text, + TextWidgetData *textWidget, + OverlayWidgetCounts *widgetCounts); + + using FormatGraphTitleFunc = std::function<std::string(uint64_t curValue, uint64_t maxValue)>; + static void AppendRunningGraphCommon(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts, + FormatGraphTitleFunc formatFunc); + + using FormatHistogramTitleFunc = + std::function<std::string(size_t peakRange, size_t maxValueRange, size_t numRanges)>; + static void AppendRunningHistogramCommon(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts, + FormatHistogramTitleFunc formatFunc); + + static void AppendGraphCommon(const overlay::Widget *widget, + const gl::Extents &imageExtent, + const std::vector<uint64_t> runningValues, + size_t startIndex, + float scale, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts); +}; + +void AppendWidgetDataHelper::AppendTextCommon(const overlay::Widget *widget, + const gl::Extents &imageExtent, + const std::string &text, + TextWidgetData *textWidget, + OverlayWidgetCounts *widgetCounts) +{ + GetWidgetCoordinates(widget->coords, imageExtent, textWidget->coordinates); + GetWidgetColor(widget->color, textWidget->color); + GetTextFontSize(widget->fontSize, textWidget->fontSize); + GetTextString(text, textWidget->text); + + ++(*widgetCounts)[WidgetInternalType::Text]; +} + +void AppendWidgetDataHelper::AppendGraphCommon(const overlay::Widget *widget, + const gl::Extents &imageExtent, + const std::vector<uint64_t> runningValues, + size_t startIndex, + float scale, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + const overlay::RunningGraph *widgetAsGraph = static_cast<const overlay::RunningGraph *>(widget); + + GetWidgetCoordinates(widget->coords, imageExtent, graphWidget->coordinates); + GetWidgetColor(widget->color, graphWidget->color); + GetGraphValueWidth(widget->coords, widgetAsGraph->runningValues.size(), + &graphWidget->valueWidth); + GetGraphValues(runningValues, startIndex, scale, graphWidget->values); + + ++(*widgetCounts)[WidgetInternalType::Graph]; +} + +void AppendWidgetDataHelper::AppendRunningGraphCommon( + const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts, + AppendWidgetDataHelper::FormatGraphTitleFunc formatFunc) +{ + const overlay::RunningGraph *graph = static_cast<const overlay::RunningGraph *>(widget); + const overlay::Widget *matchToWidget = widget->matchToWidget; + + if (matchToWidget == nullptr) + { + matchToWidget = widget; + } + const overlay::RunningGraph *matchToGraph = + static_cast<const overlay::RunningGraph *>(matchToWidget); + + const uint64_t maxValue = + *std::max_element(graph->runningValues.begin(), graph->runningValues.end()); + const uint64_t maxValueInMatchToGraph = + *std::max_element(matchToGraph->runningValues.begin(), matchToGraph->runningValues.end()); + const int32_t graphHeight = std::abs(widget->coords[3] - widget->coords[1]); + const float graphScale = static_cast<float>(graphHeight) / maxValueInMatchToGraph; + + const size_t graphSize = graph->runningValues.size(); + const size_t currentIdx = graph->lastValueIndex - 1; + + const uint64_t curValue = graph->runningValues[(graphSize + currentIdx) % graphSize]; + + AppendGraphCommon(widget, imageExtent, graph->runningValues, graph->lastValueIndex + 1, + graphScale, graphWidget, widgetCounts); + + if ((*widgetCounts)[WidgetInternalType::Text] < + kWidgetInternalTypeMaxWidgets[WidgetInternalType::Text]) + { + std::string text = formatFunc(curValue, maxValue); + AppendTextCommon(&graph->description, imageExtent, text, textWidget, widgetCounts); + } +} + +// static +void AppendWidgetDataHelper::AppendRunningHistogramCommon(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts, + FormatHistogramTitleFunc formatFunc) +{ + const overlay::RunningHistogram *runningHistogram = + static_cast<const overlay::RunningHistogram *>(widget); + + std::vector<uint64_t> histogram = CreateHistogram(runningHistogram->runningValues); + auto peakRangeIt = std::max_element(histogram.rbegin(), histogram.rend()); + const uint64_t peakRangeValue = *peakRangeIt; + const int32_t graphHeight = std::abs(widget->coords[3] - widget->coords[1]); + const float graphScale = static_cast<float>(graphHeight) / peakRangeValue; + auto maxValueIter = std::find_if(histogram.rbegin(), histogram.rend(), + [](uint64_t value) { return value != 0; }); + + AppendGraphCommon(widget, imageExtent, histogram, 0, graphScale, graphWidget, widgetCounts); + + if ((*widgetCounts)[WidgetInternalType::Text] < + kWidgetInternalTypeMaxWidgets[WidgetInternalType::Text]) + { + size_t peakRange = std::distance(peakRangeIt, histogram.rend() - 1); + size_t maxValueRange = std::distance(maxValueIter, histogram.rend() - 1); + + std::string text = formatFunc(peakRange, maxValueRange, histogram.size()); + AppendTextCommon(&runningHistogram->description, imageExtent, text, textWidget, + widgetCounts); + } +} + +void AppendWidgetDataHelper::AppendFPS(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + const overlay::PerSecond *fps = static_cast<const overlay::PerSecond *>(widget); + std::ostringstream text; + text << "FPS: "; + OutputPerSecond(text, fps); + + AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts); +} + +void AppendWidgetDataHelper::AppendVulkanLastValidationMessage(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + const overlay::Text *lastValidationMessage = static_cast<const overlay::Text *>(widget); + std::ostringstream text; + text << "Last VVL Message: "; + OutputText(text, lastValidationMessage); + + AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts); +} + +void AppendWidgetDataHelper::AppendVulkanValidationMessageCount(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + const overlay::Count *validationMessageCount = static_cast<const overlay::Count *>(widget); + std::ostringstream text; + text << "VVL Message Count: "; + OutputCount(text, validationMessageCount); + + AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts); +} + +void AppendWidgetDataHelper::AppendVulkanRenderPassCount(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "RenderPass Count: " << maxValue; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanSecondaryCommandBufferPoolWaste( + const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](size_t peakRange, size_t maxValueRange, size_t numRanges) { + std::ostringstream text; + size_t peakPercent = (peakRange * 100 + 50) / numRanges; + text << "CB Pool Waste (Peak: " << peakPercent << "%)"; + return text.str(); + }; + + AppendRunningHistogramCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, + format); +} + +void AppendWidgetDataHelper::AppendVulkanRenderPassBufferCount(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "RP VkBuffers (Max: " << maxValue << ")"; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanWriteDescriptorSetCount(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "WriteDescriptorSet Count: " << maxValue; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanDescriptorSetAllocations(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "Descriptor Set Allocations: " << maxValue; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanShaderResourceDSHitRate(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "Shader Resource DS Hit Rate (Max: " << maxValue << "%)"; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanDynamicBufferAllocations(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "DynamicBuffer Allocations (Max: " << maxValue << ")"; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanTextureDescriptorCacheSize( + const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "Total Texture Descriptor Cache Size: " << curValue; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanUniformDescriptorCacheSize( + const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "Total Uniform Descriptor Cache Size: " << curValue; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanDescriptorCacheSize(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "Total Descriptor Cache Size: " << curValue; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanDescriptorCacheKeySize(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + const overlay::Count *countWidget = static_cast<const overlay::Count *>(widget); + std::ostringstream text; + double kb = static_cast<double>(countWidget->count) / 1000.0; + text << "DS Cache Key Size: " << std::fixed << std::setprecision(1) << kb << " kb"; + + AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts); +} + +void AppendWidgetDataHelper::AppendVulkanAttemptedSubmissions(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "Attempted submissions (peak): " << maxValue; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanActualSubmissions(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "Actual submissions (peak): " << maxValue; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanPipelineCacheLookups(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "Pipeline Cache Lookups (peak): " << maxValue; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanPipelineCacheMisses(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + auto format = [](uint64_t curValue, uint64_t maxValue) { + std::ostringstream text; + text << "Pipeline Cache Misses (peak): " << maxValue; + return text.str(); + }; + + AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); +} + +void AppendWidgetDataHelper::AppendVulkanTotalPipelineCacheHitTimeMs( + const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + const overlay::Count *totalTime = static_cast<const overlay::Count *>(widget); + std::ostringstream text; + text << "Total Pipeline Cache Hit Time: "; + OutputCount(text, totalTime); + text << "ms"; + + AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts); +} + +void AppendWidgetDataHelper::AppendVulkanTotalPipelineCacheMissTimeMs( + const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + const overlay::Count *totalTime = static_cast<const overlay::Count *>(widget); + std::ostringstream text; + text << "Total Pipeline Cache Miss Time: "; + OutputCount(text, totalTime); + text << "ms"; + + AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts); +} + +std::ostream &AppendWidgetDataHelper::OutputPerSecond(std::ostream &out, + const overlay::PerSecond *perSecond) +{ + return out << perSecond->lastPerSecondCount; +} + +std::ostream &AppendWidgetDataHelper::OutputText(std::ostream &out, const overlay::Text *text) +{ + return out << text->text; +} + +std::ostream &AppendWidgetDataHelper::OutputCount(std::ostream &out, const overlay::Count *count) +{ + return out << count->count; +} +} // namespace overlay_impl + +namespace +{ +#define ANGLE_APPEND_WIDGET_MAP_PROC(WIDGET_ID) \ + {WidgetId::WIDGET_ID, overlay_impl::AppendWidgetDataHelper::Append##WIDGET_ID}, + +constexpr angle::PackedEnumMap<WidgetId, AppendWidgetDataFunc> kWidgetIdToAppendDataFuncMap = { + ANGLE_WIDGET_ID_X(ANGLE_APPEND_WIDGET_MAP_PROC)}; +} // namespace + +namespace overlay +{ +const Text *Widget::getDescriptionWidget() const +{ + return nullptr; +} +RunningGraph::RunningGraph(size_t n) : runningValues(n, 0) {} +RunningGraph::~RunningGraph() = default; +const Text *RunningGraph::getDescriptionWidget() const +{ + return &description; +} +} // namespace overlay + +size_t OverlayState::getWidgetCoordinatesBufferSize() const +{ + return sizeof(WidgetCoordinates); +} + +size_t OverlayState::getTextWidgetsBufferSize() const +{ + return sizeof(TextWidgets); +} + +size_t OverlayState::getGraphWidgetsBufferSize() const +{ + return sizeof(GraphWidgets); +} + +void OverlayState::fillWidgetData(const gl::Extents &imageExtents, + uint8_t *textData, + uint8_t *graphData, + uint32_t *activeTextWidgetCountOut, + uint32_t *activeGraphWidgetCountOut) const +{ + TextWidgets *textWidgets = reinterpret_cast<TextWidgets *>(textData); + GraphWidgets *graphWidgets = reinterpret_cast<GraphWidgets *>(graphData); + + memset(textWidgets, overlay::kFontCharacters, sizeof(*textWidgets)); + memset(graphWidgets, 0, sizeof(*graphWidgets)); + + OverlayWidgetCounts widgetCounts = {}; + + for (WidgetId id : angle::AllEnums<WidgetId>()) + { + const std::unique_ptr<overlay::Widget> &widget = mOverlayWidgets[id]; + if (!widget->enabled) + { + continue; + } + + WidgetInternalType internalType = kWidgetTypeToInternalMap[widget->type]; + ASSERT(internalType != WidgetInternalType::InvalidEnum); + + if (widgetCounts[internalType] >= kWidgetInternalTypeMaxWidgets[internalType]) + { + continue; + } + + AppendWidgetDataFunc appendFunc = kWidgetIdToAppendDataFuncMap[id]; + ASSERT(appendFunc); + appendFunc(widget.get(), imageExtents, + &textWidgets->widgets[widgetCounts[WidgetInternalType::Text]], + &graphWidgets->widgets[widgetCounts[WidgetInternalType::Graph]], &widgetCounts); + } + + *activeTextWidgetCountOut = widgetCounts[WidgetInternalType::Text]; + *activeGraphWidgetCountOut = widgetCounts[WidgetInternalType::Graph]; +} + +} // namespace gl |