| // |
| // 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<size_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<size_t> CreateHistogram(const std::vector<size_t> values) |
| { |
| std::vector<size_t> histogram(values.size(), 0); |
| |
| for (size_t rank : values) |
| { |
| ++histogram[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(size_t curValue, size_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<size_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<size_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 size_t maxValue = |
| *std::max_element(graph->runningValues.begin(), graph->runningValues.end()); |
| const size_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 size_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<size_t> histogram = CreateHistogram(runningHistogram->runningValues); |
| auto peakRangeIt = std::max_element(histogram.rbegin(), histogram.rend()); |
| const size_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(), [](size_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 = [](size_t curValue, size_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 = [](size_t peakRange, size_t maxValueRange, size_t numRanges) { |
| std::ostringstream text; |
| text << "RP VkBuffers (Peak: " << peakRange << ", Max: " << maxValueRange << ")"; |
| return text.str(); |
| }; |
| |
| AppendRunningHistogramCommon(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 = [](size_t curValue, size_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 = [](size_t curValue, size_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 = [](size_t curValue, size_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 = [](size_t curValue, size_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 = [](size_t curValue, size_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 = [](size_t curValue, size_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 = [](size_t curValue, size_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 = [](size_t curValue, size_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 = [](size_t curValue, size_t maxValue) { |
| std::ostringstream text; |
| text << "Actual submissions (peak): " << maxValue; |
| return text.str(); |
| }; |
| |
| AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format); |
| } |
| |
| 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 |
| { |
| RunningGraph::RunningGraph(size_t n) : runningValues(n, 0) {} |
| RunningGraph::~RunningGraph() = default; |
| } // 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 |