• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 namespace gl
16 {
17 namespace
18 {
19 // Internally, every widget is either Text or Graph.
20 enum class WidgetInternalType
21 {
22     Text,
23     Graph,
24 
25     InvalidEnum,
26     EnumCount = InvalidEnum,
27 };
28 
29 // A map that says how the API-facing widget types map to internal types.
30 constexpr angle::PackedEnumMap<WidgetType, WidgetInternalType> kWidgetTypeToInternalMap = {
31     {WidgetType::Count, WidgetInternalType::Text},
32     {WidgetType::Text, WidgetInternalType::Text},
33     {WidgetType::PerSecond, WidgetInternalType::Text},
34     {WidgetType::RunningGraph, WidgetInternalType::Graph},
35     {WidgetType::RunningHistogram, WidgetInternalType::Graph},
36 };
37 
38 // Structures and limits matching uniform buffers in vulkan/shaders/src/OverlayDraw.comp.  The size
39 // of text and graph widgets is chosen such that they could fit in uniform buffers with minimum
40 // required Vulkan size.
41 constexpr size_t kMaxRenderableTextWidgets  = 32;
42 constexpr size_t kMaxRenderableGraphWidgets = 32;
43 constexpr size_t kMaxTextLength             = 256;
44 constexpr size_t kMaxGraphDataSize          = 64;
45 
46 constexpr angle::PackedEnumMap<WidgetInternalType, size_t> kWidgetInternalTypeMaxWidgets = {
47     {WidgetInternalType::Text, kMaxRenderableTextWidgets},
48     {WidgetInternalType::Graph, kMaxRenderableGraphWidgets},
49 };
50 
51 constexpr angle::PackedEnumMap<WidgetInternalType, size_t> kWidgetInternalTypeWidgetOffsets = {
52     {WidgetInternalType::Text, 0},
53     {WidgetInternalType::Graph, kMaxRenderableTextWidgets},
54 };
55 
56 ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
57 
58 // Structure matching buffer in vulkan/shaders/src/OverlayCull.comp.
59 struct WidgetCoordinates
60 {
61     uint32_t coordinates[kMaxRenderableTextWidgets + kMaxRenderableGraphWidgets][4];
62 };
63 
64 // Structures matching buffers in vulkan/shaders/src/OverlayDraw.comp.
65 struct TextWidgetData
66 {
67     uint32_t coordinates[4];
68     float color[4];
69     uint32_t fontSize[3];
70     uint32_t padding;
71     uint8_t text[kMaxTextLength];
72 };
73 
74 struct GraphWidgetData
75 {
76     uint32_t coordinates[4];
77     float color[4];
78     uint32_t valueWidth;
79     uint32_t padding[3];
80     uint32_t values[kMaxGraphDataSize];
81 };
82 
83 struct TextWidgets
84 {
85     TextWidgetData widgets[kMaxRenderableTextWidgets];
86 };
87 
88 struct GraphWidgets
89 {
90     GraphWidgetData widgets[kMaxRenderableGraphWidgets];
91 };
92 
93 ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
94 
GetWidgetCoord(int32_t src,uint32_t extent)95 uint32_t GetWidgetCoord(int32_t src, uint32_t extent)
96 {
97     int32_t dst = src < 0 ? extent + src : src;
98 
99     return std::min<uint32_t>(std::max(dst, 0), extent - 1);
100 }
101 
GetWidgetCoordinates(const int32_t srcCoords[4],const gl::Extents & imageExtent,uint32_t dstCoordsOut[4])102 void GetWidgetCoordinates(const int32_t srcCoords[4],
103                           const gl::Extents &imageExtent,
104                           uint32_t dstCoordsOut[4])
105 {
106     dstCoordsOut[0] = GetWidgetCoord(srcCoords[0], imageExtent.width);
107     dstCoordsOut[1] = GetWidgetCoord(srcCoords[1], imageExtent.height);
108     dstCoordsOut[2] = GetWidgetCoord(srcCoords[2], imageExtent.width);
109     dstCoordsOut[3] = GetWidgetCoord(srcCoords[3], imageExtent.height);
110 }
111 
GetWidgetColor(const float srcColor[4],float dstColor[4])112 void GetWidgetColor(const float srcColor[4], float dstColor[4])
113 {
114     memcpy(dstColor, srcColor, 4 * sizeof(dstColor[0]));
115 }
116 
GetTextFontSize(int srcFontSize,uint32_t dstFontSize[3])117 void GetTextFontSize(int srcFontSize, uint32_t dstFontSize[3])
118 {
119     // .xy contains the font glyph width/height
120     dstFontSize[0] = overlay::kFontGlyphWidths[srcFontSize];
121     dstFontSize[1] = overlay::kFontGlyphHeights[srcFontSize];
122     // .z contains the layer
123     dstFontSize[2] = srcFontSize;
124 }
125 
GetGraphValueWidth(const int32_t srcCoords[4],size_t valueCount,uint32_t * dstValueWidth)126 void GetGraphValueWidth(const int32_t srcCoords[4], size_t valueCount, uint32_t *dstValueWidth)
127 {
128     const int32_t graphWidth = std::abs(srcCoords[2] - srcCoords[0]);
129 
130     // If valueCount doesn't divide graphWidth, the graph bars won't fit well in its frame.
131     // Fix initOverlayWidgets() in that case.
132     ASSERT(graphWidth % valueCount == 0);
133 
134     *dstValueWidth = graphWidth / valueCount;
135 }
136 
GetTextString(const std::string & src,uint8_t textOut[kMaxTextLength])137 void GetTextString(const std::string &src, uint8_t textOut[kMaxTextLength])
138 {
139     for (size_t i = 0; i < src.length() && i < kMaxTextLength; ++i)
140     {
141         // The font image has 96 ASCII characters starting from ' '.
142         textOut[i] = src[i] - ' ';
143     }
144 }
145 
GetGraphValues(const std::vector<size_t> srcValues,size_t startIndex,float scale,uint32_t valuesOut[kMaxGraphDataSize])146 void GetGraphValues(const std::vector<size_t> srcValues,
147                     size_t startIndex,
148                     float scale,
149                     uint32_t valuesOut[kMaxGraphDataSize])
150 {
151     ASSERT(srcValues.size() <= kMaxGraphDataSize);
152 
153     for (size_t i = 0; i < srcValues.size(); ++i)
154     {
155         size_t index = (startIndex + i) % srcValues.size();
156         valuesOut[i] = static_cast<uint32_t>(srcValues[index] * scale);
157     }
158 }
159 
CreateHistogram(const std::vector<size_t> values)160 std::vector<size_t> CreateHistogram(const std::vector<size_t> values)
161 {
162     std::vector<size_t> histogram(values.size(), 0);
163 
164     for (size_t rank : values)
165     {
166         ++histogram[rank];
167     }
168 
169     return histogram;
170 }
171 
172 using OverlayWidgetCounts  = angle::PackedEnumMap<WidgetInternalType, size_t>;
173 using AppendWidgetDataFunc = void (*)(const overlay::Widget *widget,
174                                       const gl::Extents &imageExtent,
175                                       TextWidgetData *textWidget,
176                                       GraphWidgetData *graphWidget,
177                                       OverlayWidgetCounts *widgetCounts);
178 }  // namespace
179 
180 namespace overlay_impl
181 {
182 // This class interprets the generic data collected in every element into a human-understandable
183 // widget.  This often means generating text specific to this item and scaling graph data to
184 // something sensible.
185 class AppendWidgetDataHelper
186 {
187   public:
188     static void AppendFPS(const overlay::Widget *widget,
189                           const gl::Extents &imageExtent,
190                           TextWidgetData *textWidget,
191                           GraphWidgetData *graphWidget,
192                           OverlayWidgetCounts *widgetCounts);
193     static void AppendVulkanLastValidationMessage(const overlay::Widget *widget,
194                                                   const gl::Extents &imageExtent,
195                                                   TextWidgetData *textWidget,
196                                                   GraphWidgetData *graphWidget,
197                                                   OverlayWidgetCounts *widgetCounts);
198     static void AppendVulkanValidationMessageCount(const overlay::Widget *widget,
199                                                    const gl::Extents &imageExtent,
200                                                    TextWidgetData *textWidget,
201                                                    GraphWidgetData *graphWidget,
202                                                    OverlayWidgetCounts *widgetCounts);
203     static void AppendVulkanCommandGraphSize(const overlay::Widget *widget,
204                                              const gl::Extents &imageExtent,
205                                              TextWidgetData *textWidget,
206                                              GraphWidgetData *graphWidget,
207                                              OverlayWidgetCounts *widgetCounts);
208     static void AppendVulkanRenderPassCount(const overlay::Widget *widget,
209                                             const gl::Extents &imageExtent,
210                                             TextWidgetData *textWidget,
211                                             GraphWidgetData *graphWidget,
212                                             OverlayWidgetCounts *widgetCounts);
213     static void AppendVulkanSecondaryCommandBufferPoolWaste(const overlay::Widget *widget,
214                                                             const gl::Extents &imageExtent,
215                                                             TextWidgetData *textWidget,
216                                                             GraphWidgetData *graphWidget,
217                                                             OverlayWidgetCounts *widgetCounts);
218 
219   private:
220     static std::ostream &OutputPerSecond(std::ostream &out, const overlay::PerSecond *perSecond);
221 
222     static std::ostream &OutputText(std::ostream &out, const overlay::Text *text);
223 
224     static std::ostream &OutputCount(std::ostream &out, const overlay::Count *count);
225 
226     static void AppendTextCommon(const overlay::Widget *widget,
227                                  const gl::Extents &imageExtent,
228                                  const std::string &text,
229                                  TextWidgetData *textWidget,
230                                  OverlayWidgetCounts *widgetCounts);
231 
232     static void AppendGraphCommon(const overlay::Widget *widget,
233                                   const gl::Extents &imageExtent,
234                                   const std::vector<size_t> runningValues,
235                                   size_t startIndex,
236                                   float scale,
237                                   GraphWidgetData *graphWidget,
238                                   OverlayWidgetCounts *widgetCounts);
239 };
240 
AppendTextCommon(const overlay::Widget * widget,const gl::Extents & imageExtent,const std::string & text,TextWidgetData * textWidget,OverlayWidgetCounts * widgetCounts)241 void AppendWidgetDataHelper::AppendTextCommon(const overlay::Widget *widget,
242                                               const gl::Extents &imageExtent,
243                                               const std::string &text,
244                                               TextWidgetData *textWidget,
245                                               OverlayWidgetCounts *widgetCounts)
246 {
247     GetWidgetCoordinates(widget->coords, imageExtent, textWidget->coordinates);
248     GetWidgetColor(widget->color, textWidget->color);
249     GetTextFontSize(widget->fontSize, textWidget->fontSize);
250     GetTextString(text, textWidget->text);
251 
252     ++(*widgetCounts)[WidgetInternalType::Text];
253 }
254 
AppendGraphCommon(const overlay::Widget * widget,const gl::Extents & imageExtent,const std::vector<size_t> runningValues,size_t startIndex,float scale,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)255 void AppendWidgetDataHelper::AppendGraphCommon(const overlay::Widget *widget,
256                                                const gl::Extents &imageExtent,
257                                                const std::vector<size_t> runningValues,
258                                                size_t startIndex,
259                                                float scale,
260                                                GraphWidgetData *graphWidget,
261                                                OverlayWidgetCounts *widgetCounts)
262 {
263     const overlay::RunningGraph *widgetAsGraph = static_cast<const overlay::RunningGraph *>(widget);
264 
265     GetWidgetCoordinates(widget->coords, imageExtent, graphWidget->coordinates);
266     GetWidgetColor(widget->color, graphWidget->color);
267     GetGraphValueWidth(widget->coords, widgetAsGraph->runningValues.size(),
268                        &graphWidget->valueWidth);
269     GetGraphValues(runningValues, startIndex, scale, graphWidget->values);
270 
271     ++(*widgetCounts)[WidgetInternalType::Graph];
272 }
273 
AppendFPS(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)274 void AppendWidgetDataHelper::AppendFPS(const overlay::Widget *widget,
275                                        const gl::Extents &imageExtent,
276                                        TextWidgetData *textWidget,
277                                        GraphWidgetData *graphWidget,
278                                        OverlayWidgetCounts *widgetCounts)
279 {
280     const overlay::PerSecond *fps = static_cast<const overlay::PerSecond *>(widget);
281     std::ostringstream text;
282     text << "FPS: ";
283     OutputPerSecond(text, fps);
284 
285     AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts);
286 }
287 
AppendVulkanLastValidationMessage(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)288 void AppendWidgetDataHelper::AppendVulkanLastValidationMessage(const overlay::Widget *widget,
289                                                                const gl::Extents &imageExtent,
290                                                                TextWidgetData *textWidget,
291                                                                GraphWidgetData *graphWidget,
292                                                                OverlayWidgetCounts *widgetCounts)
293 {
294     const overlay::Text *lastValidationMessage = static_cast<const overlay::Text *>(widget);
295     std::ostringstream text;
296     text << "Last VVL Message: ";
297     OutputText(text, lastValidationMessage);
298 
299     AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts);
300 }
301 
AppendVulkanValidationMessageCount(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)302 void AppendWidgetDataHelper::AppendVulkanValidationMessageCount(const overlay::Widget *widget,
303                                                                 const gl::Extents &imageExtent,
304                                                                 TextWidgetData *textWidget,
305                                                                 GraphWidgetData *graphWidget,
306                                                                 OverlayWidgetCounts *widgetCounts)
307 {
308     const overlay::Count *validationMessageCount = static_cast<const overlay::Count *>(widget);
309     std::ostringstream text;
310     text << "VVL Message Count: ";
311     OutputCount(text, validationMessageCount);
312 
313     AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts);
314 }
315 
AppendVulkanCommandGraphSize(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)316 void AppendWidgetDataHelper::AppendVulkanCommandGraphSize(const overlay::Widget *widget,
317                                                           const gl::Extents &imageExtent,
318                                                           TextWidgetData *textWidget,
319                                                           GraphWidgetData *graphWidget,
320                                                           OverlayWidgetCounts *widgetCounts)
321 {
322     const overlay::RunningGraph *commandGraphSize =
323         static_cast<const overlay::RunningGraph *>(widget);
324 
325     const size_t maxValue     = *std::max_element(commandGraphSize->runningValues.begin(),
326                                               commandGraphSize->runningValues.end());
327     const int32_t graphHeight = std::abs(widget->coords[3] - widget->coords[1]);
328     const float graphScale    = static_cast<float>(graphHeight) / maxValue;
329 
330     AppendGraphCommon(widget, imageExtent, commandGraphSize->runningValues,
331                       commandGraphSize->lastValueIndex + 1, graphScale, graphWidget, widgetCounts);
332 
333     if ((*widgetCounts)[WidgetInternalType::Text] <
334         kWidgetInternalTypeMaxWidgets[WidgetInternalType::Text])
335     {
336         std::ostringstream text;
337         text << "Command Graph Size (Max: " << maxValue << ")";
338         AppendTextCommon(&commandGraphSize->description, imageExtent, text.str(), textWidget,
339                          widgetCounts);
340     }
341 }
342 
AppendVulkanRenderPassCount(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)343 void AppendWidgetDataHelper::AppendVulkanRenderPassCount(const overlay::Widget *widget,
344                                                          const gl::Extents &imageExtent,
345                                                          TextWidgetData *textWidget,
346                                                          GraphWidgetData *graphWidget,
347                                                          OverlayWidgetCounts *widgetCounts)
348 {
349     const overlay::RunningGraph *renderPassCount =
350         static_cast<const overlay::RunningGraph *>(widget);
351 
352     const size_t maxValue     = *std::max_element(renderPassCount->runningValues.begin(),
353                                               renderPassCount->runningValues.end());
354     const int32_t graphHeight = std::abs(widget->coords[3] - widget->coords[1]);
355     const float graphScale    = static_cast<float>(graphHeight) / maxValue;
356 
357     AppendGraphCommon(widget, imageExtent, renderPassCount->runningValues,
358                       renderPassCount->lastValueIndex + 1, graphScale, graphWidget, widgetCounts);
359 
360     if ((*widgetCounts)[WidgetInternalType::Text] <
361         kWidgetInternalTypeMaxWidgets[WidgetInternalType::Text])
362     {
363         std::ostringstream text;
364         text << "RenderPass Count (Max: " << maxValue << ")";
365         AppendTextCommon(&renderPassCount->description, imageExtent, text.str(), textWidget,
366                          widgetCounts);
367     }
368 }
369 
AppendVulkanSecondaryCommandBufferPoolWaste(const overlay::Widget * widget,const gl::Extents & imageExtent,TextWidgetData * textWidget,GraphWidgetData * graphWidget,OverlayWidgetCounts * widgetCounts)370 void AppendWidgetDataHelper::AppendVulkanSecondaryCommandBufferPoolWaste(
371     const overlay::Widget *widget,
372     const gl::Extents &imageExtent,
373     TextWidgetData *textWidget,
374     GraphWidgetData *graphWidget,
375     OverlayWidgetCounts *widgetCounts)
376 {
377     const overlay::RunningHistogram *secondaryCommandBufferPoolWaste =
378         static_cast<const overlay::RunningHistogram *>(widget);
379 
380     std::vector<size_t> histogram = CreateHistogram(secondaryCommandBufferPoolWaste->runningValues);
381     auto maxValueIter             = std::max_element(histogram.rbegin(), histogram.rend());
382     const size_t maxValue         = *maxValueIter;
383     const int32_t graphHeight     = std::abs(widget->coords[3] - widget->coords[1]);
384     const float graphScale        = static_cast<float>(graphHeight) / maxValue;
385 
386     AppendGraphCommon(widget, imageExtent, histogram, 0, graphScale, graphWidget, widgetCounts);
387 
388     if ((*widgetCounts)[WidgetInternalType::Text] <
389         kWidgetInternalTypeMaxWidgets[WidgetInternalType::Text])
390     {
391         std::ostringstream text;
392         size_t peak        = std::distance(maxValueIter, histogram.rend() - 1);
393         size_t peakPercent = (peak * 100 + 50) / histogram.size();
394 
395         text << "CB Pool Waste (Peak: " << peakPercent << "%)";
396         AppendTextCommon(&secondaryCommandBufferPoolWaste->description, imageExtent, text.str(),
397                          textWidget, widgetCounts);
398     }
399 }
400 
OutputPerSecond(std::ostream & out,const overlay::PerSecond * perSecond)401 std::ostream &AppendWidgetDataHelper::OutputPerSecond(std::ostream &out,
402                                                       const overlay::PerSecond *perSecond)
403 {
404     return out << perSecond->lastPerSecondCount;
405 }
406 
OutputText(std::ostream & out,const overlay::Text * text)407 std::ostream &AppendWidgetDataHelper::OutputText(std::ostream &out, const overlay::Text *text)
408 {
409     return out << text->text;
410 }
411 
OutputCount(std::ostream & out,const overlay::Count * count)412 std::ostream &AppendWidgetDataHelper::OutputCount(std::ostream &out, const overlay::Count *count)
413 {
414     return out << count->count;
415 }
416 }  // namespace overlay_impl
417 
418 namespace
419 {
420 constexpr angle::PackedEnumMap<WidgetId, AppendWidgetDataFunc> kWidgetIdToAppendDataFuncMap = {
421     {WidgetId::FPS, overlay_impl::AppendWidgetDataHelper::AppendFPS},
422     {WidgetId::VulkanLastValidationMessage,
423      overlay_impl::AppendWidgetDataHelper::AppendVulkanLastValidationMessage},
424     {WidgetId::VulkanValidationMessageCount,
425      overlay_impl::AppendWidgetDataHelper::AppendVulkanValidationMessageCount},
426     {WidgetId::VulkanRenderPassCount,
427      overlay_impl::AppendWidgetDataHelper::AppendVulkanRenderPassCount},
428     {WidgetId::VulkanSecondaryCommandBufferPoolWaste,
429      overlay_impl::AppendWidgetDataHelper::AppendVulkanSecondaryCommandBufferPoolWaste},
430 };
431 }
432 
433 namespace overlay
434 {
RunningGraph(size_t n)435 RunningGraph::RunningGraph(size_t n) : runningValues(n, 0) {}
436 RunningGraph::~RunningGraph() = default;
437 }  // namespace overlay
438 
getWidgetCoordinatesBufferSize() const439 size_t OverlayState::getWidgetCoordinatesBufferSize() const
440 {
441     return sizeof(WidgetCoordinates);
442 }
443 
getTextWidgetsBufferSize() const444 size_t OverlayState::getTextWidgetsBufferSize() const
445 {
446     return sizeof(TextWidgets);
447 }
448 
getGraphWidgetsBufferSize() const449 size_t OverlayState::getGraphWidgetsBufferSize() const
450 {
451     return sizeof(GraphWidgets);
452 }
453 
fillEnabledWidgetCoordinates(const gl::Extents & imageExtents,uint8_t * enabledWidgetsPtr) const454 void OverlayState::fillEnabledWidgetCoordinates(const gl::Extents &imageExtents,
455                                                 uint8_t *enabledWidgetsPtr) const
456 {
457     WidgetCoordinates *enabledWidgets = reinterpret_cast<WidgetCoordinates *>(enabledWidgetsPtr);
458     memset(enabledWidgets, 0, sizeof(*enabledWidgets));
459 
460     OverlayWidgetCounts widgetCounts = {};
461 
462     for (const std::unique_ptr<overlay::Widget> &widget : mOverlayWidgets)
463     {
464         if (!widget->enabled)
465         {
466             continue;
467         }
468 
469         WidgetInternalType internalType = kWidgetTypeToInternalMap[widget->type];
470         ASSERT(internalType != WidgetInternalType::InvalidEnum);
471 
472         if (widgetCounts[internalType] >= kWidgetInternalTypeMaxWidgets[internalType])
473         {
474             continue;
475         }
476 
477         size_t writeIndex =
478             kWidgetInternalTypeWidgetOffsets[internalType] + widgetCounts[internalType]++;
479 
480         GetWidgetCoordinates(widget->coords, imageExtents, enabledWidgets->coordinates[writeIndex]);
481 
482         // Graph widgets have a text widget attached as well.
483         if (internalType == WidgetInternalType::Graph)
484         {
485             WidgetInternalType textType = WidgetInternalType::Text;
486             if (widgetCounts[textType] >= kWidgetInternalTypeMaxWidgets[textType])
487             {
488                 continue;
489             }
490 
491             const overlay::RunningGraph *widgetAsGraph =
492                 static_cast<const overlay::RunningGraph *>(widget.get());
493             writeIndex = kWidgetInternalTypeWidgetOffsets[textType] + widgetCounts[textType]++;
494 
495             GetWidgetCoordinates(widgetAsGraph->description.coords, imageExtents,
496                                  enabledWidgets->coordinates[writeIndex]);
497         }
498     }
499 }
500 
fillWidgetData(const gl::Extents & imageExtents,uint8_t * textData,uint8_t * graphData) const501 void OverlayState::fillWidgetData(const gl::Extents &imageExtents,
502                                   uint8_t *textData,
503                                   uint8_t *graphData) const
504 {
505     TextWidgets *textWidgets   = reinterpret_cast<TextWidgets *>(textData);
506     GraphWidgets *graphWidgets = reinterpret_cast<GraphWidgets *>(graphData);
507 
508     memset(textWidgets, overlay::kFontCharacters, sizeof(*textWidgets));
509     memset(graphWidgets, 0, sizeof(*graphWidgets));
510 
511     OverlayWidgetCounts widgetCounts = {};
512 
513     for (WidgetId id : angle::AllEnums<WidgetId>())
514     {
515         const std::unique_ptr<overlay::Widget> &widget = mOverlayWidgets[id];
516         if (!widget->enabled)
517         {
518             continue;
519         }
520 
521         WidgetInternalType internalType = kWidgetTypeToInternalMap[widget->type];
522         ASSERT(internalType != WidgetInternalType::InvalidEnum);
523 
524         if (widgetCounts[internalType] >= kWidgetInternalTypeMaxWidgets[internalType])
525         {
526             continue;
527         }
528 
529         AppendWidgetDataFunc appendFunc = kWidgetIdToAppendDataFuncMap[id];
530         ASSERT(appendFunc);
531         appendFunc(widget.get(), imageExtents,
532                    &textWidgets->widgets[widgetCounts[WidgetInternalType::Text]],
533                    &graphWidgets->widgets[widgetCounts[WidgetInternalType::Graph]], &widgetCounts);
534     }
535 }
536 
537 }  // namespace gl
538