1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // OverlayWidgets.cpp:
7 //    Implements functions that interpret widget data.  Data formats and limits correspond to the
8 //    Vulkan implementation (as the only implementation).  They are generic enough so other backends
9 //    could respect them too, if they implement the overlay.
10 //
11 
12 #include "libANGLE/Overlay.h"
13 #include "libANGLE/Overlay_font_autogen.h"
14 
15 #include <functional>
16 
17 namespace gl
18 {
19 namespace
20 {
21 // Internally, every widget is either Text or Graph.
22 enum class WidgetInternalType
23 {
24     Text,
25     Graph,
26 
27     InvalidEnum,
28     EnumCount = InvalidEnum,
29 };
30 
31 // A map that says how the API-facing widget types map to internal types.
32 constexpr angle::PackedEnumMap<WidgetType, WidgetInternalType> kWidgetTypeToInternalMap = {
33     {WidgetType::Count, WidgetInternalType::Text},
34     {WidgetType::Text, WidgetInternalType::Text},
35     {WidgetType::PerSecond, WidgetInternalType::Text},
36     {WidgetType::RunningGraph, WidgetInternalType::Graph},
37     {WidgetType::RunningHistogram, WidgetInternalType::Graph},
38 };
39 
40 // Structures and limits matching uniform buffers in vulkan/shaders/src/OverlayDraw.comp.  The size
41 // of text and graph widgets is chosen such that they could fit in uniform buffers with minimum
42 // required Vulkan size.
43 constexpr size_t kMaxRenderableTextWidgets  = 32;
44 constexpr size_t kMaxRenderableGraphWidgets = 32;
45 constexpr size_t kMaxTextLength             = 256;
46 constexpr size_t kMaxGraphDataSize          = 256;
47 
48 constexpr angle::PackedEnumMap<WidgetInternalType, size_t> kWidgetInternalTypeMaxWidgets = {
49     {WidgetInternalType::Text, kMaxRenderableTextWidgets},
50     {WidgetInternalType::Graph, kMaxRenderableGraphWidgets},
51 };
52 
53 constexpr angle::PackedEnumMap<WidgetInternalType, size_t> kWidgetInternalTypeWidgetOffsets = {
54     {WidgetInternalType::Text, 0},
55     {WidgetInternalType::Graph, kMaxRenderableTextWidgets},
56 };
57 
58 ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
59 
60 // Structure matching buffer in vulkan/shaders/src/OverlayCull.comp.
61 struct WidgetCoordinates
62 {
63     uint32_t coordinates[kMaxRenderableTextWidgets + kMaxRenderableGraphWidgets][4];
64 };
65 
66 // Structures matching buffers in vulkan/shaders/src/OverlayDraw.comp.
67 struct TextWidgetData
68 {
69     uint32_t coordinates[4];
70     float color[4];
71     uint32_t fontSize[3];
72     uint32_t padding;
73     uint8_t text[kMaxTextLength];
74 };
75 
76 struct GraphWidgetData
77 {
78     uint32_t coordinates[4];
79     float color[4];
80     uint32_t valueWidth;
81     uint32_t padding[3];
82     uint32_t values[kMaxGraphDataSize];
83 };
84 
85 struct TextWidgets
86 {
87     TextWidgetData widgets[kMaxRenderableTextWidgets];
88 };
89 
90 struct GraphWidgets
91 {
92     GraphWidgetData widgets[kMaxRenderableGraphWidgets];
93 };
94 
95 ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
96 
GetWidgetCoord(int32_t src,uint32_t extent)97 uint32_t GetWidgetCoord(int32_t src, uint32_t extent)
98 {
99     int32_t dst = src < 0 ? extent + src : src;
100 
101     return std::min<uint32_t>(std::max(dst, 0), extent - 1);
102 }
103 
GetWidgetCoordinates(const int32_t srcCoords[4],const gl::Extents & imageExtent,uint32_t dstCoordsOut[4])104 void GetWidgetCoordinates(const int32_t srcCoords[4],
105                           const gl::Extents &imageExtent,
106                           uint32_t dstCoordsOut[4])
107 {
108     dstCoordsOut[0] = GetWidgetCoord(srcCoords[0], imageExtent.width);
109     dstCoordsOut[1] = GetWidgetCoord(srcCoords[1], imageExtent.height);
110     dstCoordsOut[2] = GetWidgetCoord(srcCoords[2], imageExtent.width);
111     dstCoordsOut[3] = GetWidgetCoord(srcCoords[3], imageExtent.height);
112 }
113 
GetWidgetColor(const float srcColor[4],float dstColor[4])114 void GetWidgetColor(const float srcColor[4], float dstColor[4])
115 {
116     memcpy(dstColor, srcColor, 4 * sizeof(dstColor[0]));
117 }
118 
GetTextFontSize(int srcFontSize,uint32_t dstFontSize[3])119 void GetTextFontSize(int srcFontSize, uint32_t dstFontSize[3])
120 {
121     // .xy contains the font glyph width/height
122     dstFontSize[0] = overlay::kFontGlyphWidths[srcFontSize];
123     dstFontSize[1] = overlay::kFontGlyphHeights[srcFontSize];
124     // .z contains the layer
125     dstFontSize[2] = srcFontSize;
126 }
127 
GetGraphValueWidth(const int32_t srcCoords[4],size_t valueCount,uint32_t * dstValueWidth)128 void GetGraphValueWidth(const int32_t srcCoords[4], size_t valueCount, uint32_t *dstValueWidth)
129 {
130     const int32_t graphWidth = std::abs(srcCoords[2] - srcCoords[0]);
131 
132     // If valueCount doesn't divide graphWidth, the graph bars won't fit well in its frame.
133     // Fix initOverlayWidgets() in that case.
134     ASSERT(graphWidth % valueCount == 0);
135 
136     *dstValueWidth = graphWidth / valueCount;
137 }
138 
GetTextString(const std::string & src,uint8_t textOut[kMaxTextLength])139 void GetTextString(const std::string &src, uint8_t textOut[kMaxTextLength])
140 {
141     for (size_t i = 0; i < src.length() && i < kMaxTextLength; ++i)
142     {
143         // The font image has 96 ASCII characters starting from ' '.
144         textOut[i] = src[i] - ' ';
145     }
146 }
147 
GetGraphValues(const std::vector<size_t> srcValues,size_t startIndex,float scale,uint32_t valuesOut[kMaxGraphDataSize])148 void GetGraphValues(const std::vector<size_t> srcValues,
149                     size_t startIndex,
150                     float scale,
151                     uint32_t valuesOut[kMaxGraphDataSize])
152 {
153     ASSERT(srcValues.size() <= kMaxGraphDataSize);
154 
155     for (size_t i = 0; i < srcValues.size(); ++i)
156     {
157         size_t index = (startIndex + i) % srcValues.size();
158         valuesOut[i] = static_cast<uint32_t>(srcValues[index] * scale);
159     }
160 }
161 
CreateHistogram(const std::vector<size_t> values)162 std::vector<size_t> CreateHistogram(const std::vector<size_t> values)
163 {
164     std::vector<size_t> histogram(values.size(), 0);
165 
166     for (size_t rank : values)
167     {
168         ++histogram[rank];
169     }
170 
171     return histogram;
172 }
173 
174 using OverlayWidgetCounts  = angle::PackedEnumMap<WidgetInternalType, size_t>;
175 using AppendWidgetDataFunc = void (*)(const overlay::Widget *widget,
176                                       const gl::Extents &imageExtent,
177                                       TextWidgetData *textWidget,
178                                       GraphWidgetData *graphWidget,
179                                       OverlayWidgetCounts *widgetCounts);
180 }  // namespace
181 
182 namespace overlay_impl
183 {
184 #define ANGLE_DECLARE_APPEND_WIDGET_PROC(WIDGET_ID)                                              \
185     static void Append##WIDGET_ID(const overlay::Widget *widget, const gl::Extents &imageExtent, \
186                                   TextWidgetData *textWidget, GraphWidgetData *graphWidget,      \
187                                   OverlayWidgetCounts *widgetCounts);
188 
189 // This class interprets the generic data collected in every element into a human-understandable
190 // widget.  This often means generating text specific to this item and scaling graph data to
191 // something sensible.
192 class AppendWidgetDataHelper
193 {
194   public:
195     ANGLE_WIDGET_ID_X(ANGLE_DECLARE_APPEND_WIDGET_PROC)
196 
197   private:
198     static std::ostream &OutputPerSecond(std::ostream &out, const overlay::PerSecond *perSecond);
199 
200     static std::ostream &OutputText(std::ostream &out, const overlay::Text *text);
201 
202     static std::ostream &OutputCount(std::ostream &out, const overlay::Count *count);
203 
204     static void AppendTextCommon(const overlay::Widget *widget,
205                                  const gl::Extents &imageExtent,
206                                  const std::string &text,
207                                  TextWidgetData *textWidget,
208                                  OverlayWidgetCounts *widgetCounts);
209 
210     using FormatGraphTitleFunc = std::function<std::string(size_t maxValue)>;
211     static void AppendRunningGraphCommon(const overlay::Widget *widget,
212                                          const gl::Extents &imageExtent,
213                                          TextWidgetData *textWidget,
214                                          GraphWidgetData *graphWidget,
215                                          OverlayWidgetCounts *widgetCounts,
216                                          FormatGraphTitleFunc formatFunc);
217 
218     using FormatHistogramTitleFunc =
219         std::function<std::string(size_t peakRange, size_t maxValueRange, size_t numRanges)>;
220     static void AppendRunningHistogramCommon(const overlay::Widget *widget,
221                                              const gl::Extents &imageExtent,
222                                              TextWidgetData *textWidget,
223                                              GraphWidgetData *graphWidget,
224                                              OverlayWidgetCounts *widgetCounts,
225                                              FormatHistogramTitleFunc formatFunc);
226 
227     static void AppendGraphCommon(const overlay::Widget *widget,
228                                   const gl::Extents &imageExtent,
229                                   const std::vector<size_t> runningValues,
230                                   size_t startIndex,
231                                   float scale,
232                                   GraphWidgetData *graphWidget,
233                                   OverlayWidgetCounts *widgetCounts);
234 };
235 
AppendTextCommon(const overlay::Widget * widget,const gl::Extents & imageExtent,const std::string & text,TextWidgetData * textWidget,OverlayWidgetCounts * widgetCounts)236 void AppendWidgetDataHelper::AppendTextCommon(const overlay::Widget *widget,
237                                               const gl::Extents &imageExtent,
238                                               const std::string &text,
239                                               TextWidgetData *textWidget,
240                                               OverlayWidgetCounts *widgetCounts)
241 {
242     GetWidgetCoordinates(widget->coords, imageExtent, textWidget->coordinates);
243     GetWidgetColor(widget->color, textWidget->color);
244     GetTextFontSize(widget->fontSize, textWidget->fontSize);
245     GetTextString(text, textWidget->text);
246 
247     ++(*widgetCounts)[WidgetInternalType::Text];
248 }
249 
AppendGraphCommon(const overlay::Widget * widget,const gl::Extents & imageExtent,const std::vector<size_t> runningValues,size_t startIndex,float scale,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)250 void AppendWidgetDataHelper::AppendGraphCommon(const overlay::Widget *widget,
251                                                const gl::Extents &imageExtent,
252                                                const std::vector<size_t> runningValues,
253                                                size_t startIndex,
254                                                float scale,
255                                                GraphWidgetData *graphWidget,
256                                                OverlayWidgetCounts *widgetCounts)
257 {
258     const overlay::RunningGraph *widgetAsGraph = static_cast<const overlay::RunningGraph *>(widget);
259 
260     GetWidgetCoordinates(widget->coords, imageExtent, graphWidget->coordinates);
261     GetWidgetColor(widget->color, graphWidget->color);
262     GetGraphValueWidth(widget->coords, widgetAsGraph->runningValues.size(),
263                        &graphWidget->valueWidth);
264     GetGraphValues(runningValues, startIndex, scale, graphWidget->values);
265 
266     ++(*widgetCounts)[WidgetInternalType::Graph];
267 }
268 
AppendRunningGraphCommon(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts,AppendWidgetDataHelper::FormatGraphTitleFunc formatFunc)269 void AppendWidgetDataHelper::AppendRunningGraphCommon(
270     const overlay::Widget *widget,
271     const gl::Extents &imageExtent,
272     TextWidgetData *textWidget,
273     GraphWidgetData *graphWidget,
274     OverlayWidgetCounts *widgetCounts,
275     AppendWidgetDataHelper::FormatGraphTitleFunc formatFunc)
276 {
277     const overlay::RunningGraph *graph = static_cast<const overlay::RunningGraph *>(widget);
278 
279     const size_t maxValue =
280         *std::max_element(graph->runningValues.begin(), graph->runningValues.end());
281     const int32_t graphHeight = std::abs(widget->coords[3] - widget->coords[1]);
282     const float graphScale    = static_cast<float>(graphHeight) / maxValue;
283 
284     AppendGraphCommon(widget, imageExtent, graph->runningValues, graph->lastValueIndex + 1,
285                       graphScale, graphWidget, widgetCounts);
286 
287     if ((*widgetCounts)[WidgetInternalType::Text] <
288         kWidgetInternalTypeMaxWidgets[WidgetInternalType::Text])
289     {
290         std::string text = formatFunc(maxValue);
291         AppendTextCommon(&graph->description, imageExtent, text, textWidget, widgetCounts);
292     }
293 }
294 
295 // static
AppendRunningHistogramCommon(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts,FormatHistogramTitleFunc formatFunc)296 void AppendWidgetDataHelper::AppendRunningHistogramCommon(const overlay::Widget *widget,
297                                                           const gl::Extents &imageExtent,
298                                                           TextWidgetData *textWidget,
299                                                           GraphWidgetData *graphWidget,
300                                                           OverlayWidgetCounts *widgetCounts,
301                                                           FormatHistogramTitleFunc formatFunc)
302 {
303     const overlay::RunningHistogram *runningHistogram =
304         static_cast<const overlay::RunningHistogram *>(widget);
305 
306     std::vector<size_t> histogram = CreateHistogram(runningHistogram->runningValues);
307     auto peakRangeIt              = std::max_element(histogram.rbegin(), histogram.rend());
308     const size_t peakRangeValue   = *peakRangeIt;
309     const int32_t graphHeight     = std::abs(widget->coords[3] - widget->coords[1]);
310     const float graphScale        = static_cast<float>(graphHeight) / peakRangeValue;
311     auto maxValueIter =
312         std::find_if(histogram.rbegin(), histogram.rend(), [](size_t value) { return value != 0; });
313 
314     AppendGraphCommon(widget, imageExtent, histogram, 0, graphScale, graphWidget, widgetCounts);
315 
316     if ((*widgetCounts)[WidgetInternalType::Text] <
317         kWidgetInternalTypeMaxWidgets[WidgetInternalType::Text])
318     {
319         size_t peakRange     = std::distance(peakRangeIt, histogram.rend() - 1);
320         size_t maxValueRange = std::distance(maxValueIter, histogram.rend() - 1);
321 
322         std::string text = formatFunc(peakRange, maxValueRange, histogram.size());
323         AppendTextCommon(&runningHistogram->description, imageExtent, text, textWidget,
324                          widgetCounts);
325     }
326 }
327 
AppendFPS(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)328 void AppendWidgetDataHelper::AppendFPS(const overlay::Widget *widget,
329                                        const gl::Extents &imageExtent,
330                                        TextWidgetData *textWidget,
331                                        GraphWidgetData *graphWidget,
332                                        OverlayWidgetCounts *widgetCounts)
333 {
334     const overlay::PerSecond *fps = static_cast<const overlay::PerSecond *>(widget);
335     std::ostringstream text;
336     text << "FPS: ";
337     OutputPerSecond(text, fps);
338 
339     AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts);
340 }
341 
AppendVulkanLastValidationMessage(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)342 void AppendWidgetDataHelper::AppendVulkanLastValidationMessage(const overlay::Widget *widget,
343                                                                const gl::Extents &imageExtent,
344                                                                TextWidgetData *textWidget,
345                                                                GraphWidgetData *graphWidget,
346                                                                OverlayWidgetCounts *widgetCounts)
347 {
348     const overlay::Text *lastValidationMessage = static_cast<const overlay::Text *>(widget);
349     std::ostringstream text;
350     text << "Last VVL Message: ";
351     OutputText(text, lastValidationMessage);
352 
353     AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts);
354 }
355 
AppendVulkanValidationMessageCount(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)356 void AppendWidgetDataHelper::AppendVulkanValidationMessageCount(const overlay::Widget *widget,
357                                                                 const gl::Extents &imageExtent,
358                                                                 TextWidgetData *textWidget,
359                                                                 GraphWidgetData *graphWidget,
360                                                                 OverlayWidgetCounts *widgetCounts)
361 {
362     const overlay::Count *validationMessageCount = static_cast<const overlay::Count *>(widget);
363     std::ostringstream text;
364     text << "VVL Message Count: ";
365     OutputCount(text, validationMessageCount);
366 
367     AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts);
368 }
369 
AppendVulkanRenderPassCount(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)370 void AppendWidgetDataHelper::AppendVulkanRenderPassCount(const overlay::Widget *widget,
371                                                          const gl::Extents &imageExtent,
372                                                          TextWidgetData *textWidget,
373                                                          GraphWidgetData *graphWidget,
374                                                          OverlayWidgetCounts *widgetCounts)
375 {
376     auto format = [](size_t maxValue) {
377         std::ostringstream text;
378         text << "RenderPass Count (Max: " << maxValue << ")";
379         return text.str();
380     };
381 
382     AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format);
383 }
384 
AppendVulkanSecondaryCommandBufferPoolWaste(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)385 void AppendWidgetDataHelper::AppendVulkanSecondaryCommandBufferPoolWaste(
386     const overlay::Widget *widget,
387     const gl::Extents &imageExtent,
388     TextWidgetData *textWidget,
389     GraphWidgetData *graphWidget,
390     OverlayWidgetCounts *widgetCounts)
391 {
392     auto format = [](size_t peakRange, size_t maxValueRange, size_t numRanges) {
393         std::ostringstream text;
394         size_t peakPercent = (peakRange * 100 + 50) / numRanges;
395         text << "CB Pool Waste (Peak: " << peakPercent << "%)";
396         return text.str();
397     };
398 
399     AppendRunningHistogramCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts,
400                                  format);
401 }
402 
AppendVulkanRenderPassBufferCount(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)403 void AppendWidgetDataHelper::AppendVulkanRenderPassBufferCount(const overlay::Widget *widget,
404                                                                const gl::Extents &imageExtent,
405                                                                TextWidgetData *textWidget,
406                                                                GraphWidgetData *graphWidget,
407                                                                OverlayWidgetCounts *widgetCounts)
408 {
409     auto format = [](size_t peakRange, size_t maxValueRange, size_t numRanges) {
410         std::ostringstream text;
411         text << "RP VkBuffers (Peak: " << peakRange << ", Max: " << maxValueRange << ")";
412         return text.str();
413     };
414 
415     AppendRunningHistogramCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts,
416                                  format);
417 }
418 
AppendVulkanWriteDescriptorSetCount(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)419 void AppendWidgetDataHelper::AppendVulkanWriteDescriptorSetCount(const overlay::Widget *widget,
420                                                                  const gl::Extents &imageExtent,
421                                                                  TextWidgetData *textWidget,
422                                                                  GraphWidgetData *graphWidget,
423                                                                  OverlayWidgetCounts *widgetCounts)
424 {
425     auto format = [](size_t maxValue) {
426         std::ostringstream text;
427         text << "WriteDescriptorSet Count (Max: " << maxValue << ")";
428         return text.str();
429     };
430 
431     AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format);
432 }
433 
AppendVulkanDescriptorSetAllocations(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)434 void AppendWidgetDataHelper::AppendVulkanDescriptorSetAllocations(const overlay::Widget *widget,
435                                                                   const gl::Extents &imageExtent,
436                                                                   TextWidgetData *textWidget,
437                                                                   GraphWidgetData *graphWidget,
438                                                                   OverlayWidgetCounts *widgetCounts)
439 {
440     auto format = [](size_t maxValue) {
441         std::ostringstream text;
442         text << "Descriptor Set Allocations (Max: " << maxValue << ")";
443         return text.str();
444     };
445 
446     AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format);
447 }
448 
AppendVulkanShaderBufferDSHitRate(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)449 void AppendWidgetDataHelper::AppendVulkanShaderBufferDSHitRate(const overlay::Widget *widget,
450                                                                const gl::Extents &imageExtent,
451                                                                TextWidgetData *textWidget,
452                                                                GraphWidgetData *graphWidget,
453                                                                OverlayWidgetCounts *widgetCounts)
454 {
455     auto format = [](size_t maxValue) {
456         std::ostringstream text;
457         text << "Shader Buffer DS Hit Rate (Max: " << maxValue << "%)";
458         return text.str();
459     };
460 
461     AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format);
462 }
463 
AppendVulkanDynamicBufferAllocations(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)464 void AppendWidgetDataHelper::AppendVulkanDynamicBufferAllocations(const overlay::Widget *widget,
465                                                                   const gl::Extents &imageExtent,
466                                                                   TextWidgetData *textWidget,
467                                                                   GraphWidgetData *graphWidget,
468                                                                   OverlayWidgetCounts *widgetCounts)
469 {
470     auto format = [](size_t maxValue) {
471         std::ostringstream text;
472         text << "DynamicBuffer Allocations (Max: " << maxValue << ")";
473         return text.str();
474     };
475 
476     AppendRunningGraphCommon(widget, imageExtent, textWidget, graphWidget, widgetCounts, format);
477 }
478 
OutputPerSecond(std::ostream & out,const overlay::PerSecond * perSecond)479 std::ostream &AppendWidgetDataHelper::OutputPerSecond(std::ostream &out,
480                                                       const overlay::PerSecond *perSecond)
481 {
482     return out << perSecond->lastPerSecondCount;
483 }
484 
OutputText(std::ostream & out,const overlay::Text * text)485 std::ostream &AppendWidgetDataHelper::OutputText(std::ostream &out, const overlay::Text *text)
486 {
487     return out << text->text;
488 }
489 
OutputCount(std::ostream & out,const overlay::Count * count)490 std::ostream &AppendWidgetDataHelper::OutputCount(std::ostream &out, const overlay::Count *count)
491 {
492     return out << count->count;
493 }
494 }  // namespace overlay_impl
495 
496 namespace
497 {
498 #define ANGLE_APPEND_WIDGET_MAP_PROC(WIDGET_ID) \
499     {WidgetId::WIDGET_ID, overlay_impl::AppendWidgetDataHelper::Append##WIDGET_ID},
500 
501 constexpr angle::PackedEnumMap<WidgetId, AppendWidgetDataFunc> kWidgetIdToAppendDataFuncMap = {
502     ANGLE_WIDGET_ID_X(ANGLE_APPEND_WIDGET_MAP_PROC)};
503 }  // namespace
504 
505 namespace overlay
506 {
RunningGraph(size_t n)507 RunningGraph::RunningGraph(size_t n) : runningValues(n, 0) {}
508 RunningGraph::~RunningGraph() = default;
509 }  // namespace overlay
510 
getWidgetCoordinatesBufferSize() const511 size_t OverlayState::getWidgetCoordinatesBufferSize() const
512 {
513     return sizeof(WidgetCoordinates);
514 }
515 
getTextWidgetsBufferSize() const516 size_t OverlayState::getTextWidgetsBufferSize() const
517 {
518     return sizeof(TextWidgets);
519 }
520 
getGraphWidgetsBufferSize() const521 size_t OverlayState::getGraphWidgetsBufferSize() const
522 {
523     return sizeof(GraphWidgets);
524 }
525 
fillEnabledWidgetCoordinates(const gl::Extents & imageExtents,uint8_t * enabledWidgetsPtr) const526 void OverlayState::fillEnabledWidgetCoordinates(const gl::Extents &imageExtents,
527                                                 uint8_t *enabledWidgetsPtr) const
528 {
529     WidgetCoordinates *enabledWidgets = reinterpret_cast<WidgetCoordinates *>(enabledWidgetsPtr);
530     memset(enabledWidgets, 0, sizeof(*enabledWidgets));
531 
532     OverlayWidgetCounts widgetCounts = {};
533 
534     for (const std::unique_ptr<overlay::Widget> &widget : mOverlayWidgets)
535     {
536         if (!widget->enabled)
537         {
538             continue;
539         }
540 
541         WidgetInternalType internalType = kWidgetTypeToInternalMap[widget->type];
542         ASSERT(internalType != WidgetInternalType::InvalidEnum);
543 
544         if (widgetCounts[internalType] >= kWidgetInternalTypeMaxWidgets[internalType])
545         {
546             continue;
547         }
548 
549         size_t writeIndex =
550             kWidgetInternalTypeWidgetOffsets[internalType] + widgetCounts[internalType]++;
551 
552         GetWidgetCoordinates(widget->coords, imageExtents, enabledWidgets->coordinates[writeIndex]);
553 
554         // Graph widgets have a text widget attached as well.
555         if (internalType == WidgetInternalType::Graph)
556         {
557             WidgetInternalType textType = WidgetInternalType::Text;
558             if (widgetCounts[textType] >= kWidgetInternalTypeMaxWidgets[textType])
559             {
560                 continue;
561             }
562 
563             const overlay::RunningGraph *widgetAsGraph =
564                 static_cast<const overlay::RunningGraph *>(widget.get());
565             writeIndex = kWidgetInternalTypeWidgetOffsets[textType] + widgetCounts[textType]++;
566 
567             GetWidgetCoordinates(widgetAsGraph->description.coords, imageExtents,
568                                  enabledWidgets->coordinates[writeIndex]);
569         }
570     }
571 }
572 
fillWidgetData(const gl::Extents & imageExtents,uint8_t * textData,uint8_t * graphData) const573 void OverlayState::fillWidgetData(const gl::Extents &imageExtents,
574                                   uint8_t *textData,
575                                   uint8_t *graphData) const
576 {
577     TextWidgets *textWidgets   = reinterpret_cast<TextWidgets *>(textData);
578     GraphWidgets *graphWidgets = reinterpret_cast<GraphWidgets *>(graphData);
579 
580     memset(textWidgets, overlay::kFontCharacters, sizeof(*textWidgets));
581     memset(graphWidgets, 0, sizeof(*graphWidgets));
582 
583     OverlayWidgetCounts widgetCounts = {};
584 
585     for (WidgetId id : angle::AllEnums<WidgetId>())
586     {
587         const std::unique_ptr<overlay::Widget> &widget = mOverlayWidgets[id];
588         if (!widget->enabled)
589         {
590             continue;
591         }
592 
593         WidgetInternalType internalType = kWidgetTypeToInternalMap[widget->type];
594         ASSERT(internalType != WidgetInternalType::InvalidEnum);
595 
596         if (widgetCounts[internalType] >= kWidgetInternalTypeMaxWidgets[internalType])
597         {
598             continue;
599         }
600 
601         AppendWidgetDataFunc appendFunc = kWidgetIdToAppendDataFuncMap[id];
602         ASSERT(appendFunc);
603         appendFunc(widget.get(), imageExtents,
604                    &textWidgets->widgets[widgetCounts[WidgetInternalType::Text]],
605                    &graphWidgets->widgets[widgetCounts[WidgetInternalType::Graph]], &widgetCounts);
606     }
607 }
608 
609 }  // namespace gl
610