From e54d0f90d1a165404236fd7abd1b05ddd041a686 Mon Sep 17 00:00:00 2001 From: Shahbaz Youssefi Date: Sun, 30 Jun 2019 03:26:18 -0400 Subject: [PATCH] Vulkan: Debug overlay A debug overlay system for the Vulkan backend designed with efficiency and runtime configurability in mind. Overlay widgets are of two fundamental types: - Text widgets: A single line of text with small, medium or large font. - Graph widgets: A bar graph of data. Built on these, various overlay widget types are defined that gather statistics. Five such types are defined with one widget per type as example: - Count: A widget that counts something. VulkanValidationMessageCount is an overlay widget of this type that shows the number of validation messages received from the validation layers. - Text: A generic text. VulkanLastValidationMessage is an overlay widget of this type that shows the last validation message. - PerSecond: A value that gets reset every second automatically. FPS is an overlay widget of this type that simply gets incremented on every swap(). - RunningGraph: A graph of last N values. VulkanCommandGraphSize is an overlay of this type. On every vkQueueSubmit, the number of nodes in the command graph is accumulated. On every present(), the value is taken as the number of nodes for the whole duration of the frame. - RunningHistogram: A histogram of last N values. Input values are in the [0, 1] range and they are ranked to N buckets for histogram calculation. VulkanSecondaryCommandBufferPoolWaste is an overlay widget of this type. On vkQueueSubmit, the memory waste from command buffer pool allocations is recorded in the histogram. Overlay font is placed in libANGLE/overlay/ which gen_overlay_fonts.py processes to create an array of bits, which is processed at runtime to create the actual font image (an image with 3 layers). The overlay widget layout is defined in overlay_widgets.json which gen_overlay_widgets.py processes to generate an array of widgetss, each of its respective type, and sets their properties, such as color and bounding box. The json file allows widgets to align against other widgets as well as against the framebuffer edges. Two compute shaders are implemented to efficiently render the UI: - OverlayCull: This shader creates a bitset of Text and Graph widgets whose bounding boxes intersect a corresponding subgroup processed by OverlayDraw. This is done only when the enabled overlay widgets are changed (a feature that is not yet implemented) or the surface is resized. - OverlayDraw: Using the bitsets generated by OverlayCull, values that are uniform for each workgroup (set to be equal to hardware subgroup size), this shader loops over enabled widgets that can possibly intersect the pixel being processed and renders and blends in texts and graphs. This is done once per frame on present(). Currently, to enable overlay widgets an environment variable is used. For example: $ export ANGLE_OVERLAY=FPS:VulkanSecondaryCommandBufferPoolWaste $ ./hello_triangle --use-angle=vulkan Possible future work: - On Android, add settings in developer options and enable widgets based on those. - Spawn a small server in ANGLE and write an application that sends enable/disable commands remotely. - Implement overlay for other backends. Bug: angleproject:3757 Change-Id: If9c6974d1935c18f460ec569e79b41188bd7afcc Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1729440 Commit-Queue: Shahbaz Youssefi Reviewed-by: Jamie Madill --- BUILD.gn | 4 + gni/angle.gni | 3 + samples/sample_util/SampleApplication.cpp | 2 +- .../Vulkan_internal_shader_programs.json | 26 +- .../code_generation_hashes/overlay_fonts.json | 10 + .../overlay_widgets.json | 8 + scripts/run_code_generation.py | 4 + src/libANGLE/Context.cpp | 9 +- src/libANGLE/Context.h | 2 + src/libANGLE/Overlay.cpp | 109 + src/libANGLE/Overlay.h | 137 + src/libANGLE/OverlayWidgets.cpp | 504 +++ src/libANGLE/OverlayWidgets.h | 181 ++ src/libANGLE/Overlay_autogen.cpp | 193 ++ src/libANGLE/Overlay_font_autogen.cpp | 2728 +++++++++++++++++ src/libANGLE/Overlay_font_autogen.h | 29 + src/libANGLE/State.cpp | 4 +- src/libANGLE/State.h | 7 + src/libANGLE/Surface.cpp | 6 + src/libANGLE/gen_overlay_fonts.py | 291 ++ src/libANGLE/gen_overlay_widgets.py | 320 ++ src/libANGLE/overlay/DejaVuSansMono-Bold.ttf | Bin 0 -> 331992 bytes src/libANGLE/overlay_widgets.json | 85 + src/libANGLE/renderer/GLImplFactory.h | 5 + src/libANGLE/renderer/OverlayImpl.h | 49 + src/libANGLE/renderer/d3d/d3d11/Context11.cpp | 7 + src/libANGLE/renderer/d3d/d3d11/Context11.h | 3 + src/libANGLE/renderer/d3d/d3d9/Context9.cpp | 7 + src/libANGLE/renderer/d3d/d3d9/Context9.h | 3 + src/libANGLE/renderer/gl/ContextGL.cpp | 7 + src/libANGLE/renderer/gl/ContextGL.h | 3 + src/libANGLE/renderer/null/ContextNULL.cpp | 6 + src/libANGLE/renderer/null/ContextNULL.h | 3 + src/libANGLE/renderer/vulkan/CommandGraph.cpp | 47 +- src/libANGLE/renderer/vulkan/CommandGraph.h | 2 + src/libANGLE/renderer/vulkan/ContextVk.cpp | 6 + src/libANGLE/renderer/vulkan/ContextVk.h | 6 + src/libANGLE/renderer/vulkan/OverlayVk.cpp | 281 ++ src/libANGLE/renderer/vulkan/OverlayVk.h | 57 + src/libANGLE/renderer/vulkan/RendererVk.cpp | 16 + src/libANGLE/renderer/vulkan/RendererVk.h | 7 + .../vulkan/SecondaryCommandBuffer.cpp | 21 + .../renderer/vulkan/SecondaryCommandBuffer.h | 3 + src/libANGLE/renderer/vulkan/SurfaceVk.cpp | 65 +- src/libANGLE/renderer/vulkan/SurfaceVk.h | 3 + src/libANGLE/renderer/vulkan/UtilsVk.cpp | 255 +- src/libANGLE/renderer/vulkan/UtilsVk.h | 49 +- .../vulkan/gen_vk_internal_shaders.py | 29 +- .../shaders/gen/OverlayCull.comp.00000000.inc | 145 + .../shaders/gen/OverlayCull.comp.00000001.inc | 138 + .../shaders/gen/OverlayCull.comp.00000002.inc | 146 + .../shaders/gen/OverlayCull.comp.00000003.inc | 162 + .../shaders/gen/OverlayCull.comp.00000004.inc | 226 ++ .../shaders/gen/OverlayCull.comp.00000005.inc | 249 ++ .../shaders/gen/OverlayDraw.comp.00000000.inc | 526 ++++ .../shaders/gen/OverlayDraw.comp.00000001.inc | 526 ++++ .../vulkan/shaders/src/OverlayCull.comp | 164 + .../vulkan/shaders/src/OverlayCull.comp.json | 19 + .../vulkan/shaders/src/OverlayDraw.comp | 230 ++ .../vulkan/shaders/src/OverlayDraw.comp.json | 14 + src/libANGLE/renderer/vulkan/vk_helpers.cpp | 14 +- src/libANGLE/renderer/vulkan/vk_helpers.h | 4 +- .../vulkan/vk_internal_shaders_autogen.cpp | 44 + .../vulkan/vk_internal_shaders_autogen.gni | 8 + .../vulkan/vk_internal_shaders_autogen.h | 36 + src/libANGLE/renderer/vulkan/vk_utils.h | 14 + src/libANGLE/renderer/vulkan/vk_wrapper.h | 10 + src/libGLESv2.gni | 10 + src/tests/angle_unittests_utils.h | 5 + src/tests/perf_tests/ANGLEPerfTest.cpp | 4 +- 70 files changed, 8253 insertions(+), 43 deletions(-) create mode 100644 scripts/code_generation_hashes/overlay_fonts.json create mode 100644 scripts/code_generation_hashes/overlay_widgets.json create mode 100644 src/libANGLE/Overlay.cpp create mode 100644 src/libANGLE/Overlay.h create mode 100644 src/libANGLE/OverlayWidgets.cpp create mode 100644 src/libANGLE/OverlayWidgets.h create mode 100644 src/libANGLE/Overlay_autogen.cpp create mode 100644 src/libANGLE/Overlay_font_autogen.cpp create mode 100644 src/libANGLE/Overlay_font_autogen.h create mode 100644 src/libANGLE/gen_overlay_fonts.py create mode 100644 src/libANGLE/gen_overlay_widgets.py create mode 100644 src/libANGLE/overlay/DejaVuSansMono-Bold.ttf create mode 100644 src/libANGLE/overlay_widgets.json create mode 100644 src/libANGLE/renderer/OverlayImpl.h create mode 100644 src/libANGLE/renderer/vulkan/OverlayVk.cpp create mode 100644 src/libANGLE/renderer/vulkan/OverlayVk.h create mode 100644 src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000000.inc create mode 100644 src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000001.inc create mode 100644 src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000002.inc create mode 100644 src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000003.inc create mode 100644 src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000004.inc create mode 100644 src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000005.inc create mode 100644 src/libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000000.inc create mode 100644 src/libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000001.inc create mode 100644 src/libANGLE/renderer/vulkan/shaders/src/OverlayCull.comp create mode 100644 src/libANGLE/renderer/vulkan/shaders/src/OverlayCull.comp.json create mode 100644 src/libANGLE/renderer/vulkan/shaders/src/OverlayDraw.comp create mode 100644 src/libANGLE/renderer/vulkan/shaders/src/OverlayDraw.comp.json diff --git a/BUILD.gn b/BUILD.gn index 8beab9b72f1..64a624b0043 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -717,6 +717,10 @@ angle_source_set("libANGLE_base") { defines += [ "ANGLE_GENERATE_SHADER_DEBUG_INFO" ] } + if (angle_enable_overlay) { + defines += [ "ANGLE_ENABLE_OVERLAY=1" ] + } + configs += [ ":debug_annotations_config" ] public_configs += [ ":libANGLE_config", diff --git a/gni/angle.gni b/gni/angle.gni index 410944c10f5..1ba4132d206 100644 --- a/gni/angle.gni +++ b/gni/angle.gni @@ -88,6 +88,9 @@ declare_args() { # Enable custom (cpu-side) secondary command buffers angle_enable_custom_vulkan_cmd_buffers = true } + + # Disable overlay by default + angle_enable_overlay = false } if (is_win) { diff --git a/samples/sample_util/SampleApplication.cpp b/samples/sample_util/SampleApplication.cpp index e27db78a76a..92ce5058016 100644 --- a/samples/sample_util/SampleApplication.cpp +++ b/samples/sample_util/SampleApplication.cpp @@ -68,7 +68,7 @@ SampleApplication::SampleApplication(std::string name, angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ApplicationDir)); mEGLWindow = EGLWindow::New(glesMajorVersion, glesMinorVersion); - mOSWindow = OSWindow::New(); + mOSWindow = OSWindow::New(); } SampleApplication::~SampleApplication() diff --git a/scripts/code_generation_hashes/Vulkan_internal_shader_programs.json b/scripts/code_generation_hashes/Vulkan_internal_shader_programs.json index fa6e7ce85f7..8a27d26fddf 100644 --- a/scripts/code_generation_hashes/Vulkan_internal_shader_programs.json +++ b/scripts/code_generation_hashes/Vulkan_internal_shader_programs.json @@ -1,6 +1,6 @@ { "src/libANGLE/renderer/vulkan/gen_vk_internal_shaders.py": - "76bc7ed183ce82e687b16f0496cc9f09", + "b05fa7c291a7c05d9bb1dd075990275b", "src/libANGLE/renderer/vulkan/shaders/gen/BlitResolve.frag.00000000.inc": "31832c377e532cd5ea05aab57154b8f8", "src/libANGLE/renderer/vulkan/shaders/gen/BlitResolve.frag.00000001.inc": @@ -223,6 +223,22 @@ "5bb2d9e8ee68f8ec2dacd4a056f8eff2", "src/libANGLE/renderer/vulkan/shaders/gen/ImageCopy.frag.00000015.inc": "8152303c7825ff73d9972d95520852dd", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000000.inc": + "1dc870604216818c7ca757ebb7cd22bc", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000001.inc": + "cb05ee0936a2235f49994497bd831b20", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000002.inc": + "9c6973f0e4035a411de5425d48a8ded5", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000003.inc": + "93a50e9365cef6be89033df687db44ad", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000004.inc": + "78e697d35c094a750a6cb6689b9d35c4", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000005.inc": + "5c57c4cb2507aee3e7d0d53555ef7471", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000000.inc": + "a341905ac08458eab61199817fe40c7e", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000001.inc": + "25ba613bf71f7c1397bfe2d089d57ac6", "src/libANGLE/renderer/vulkan/shaders/src/BlitResolve.frag": "a3ecba7bc86093f90b183605bed82813", "src/libANGLE/renderer/vulkan/shaders/src/BlitResolveStencilNoExport.comp": @@ -239,10 +255,14 @@ "8889ae8014a657a0efd5607954126945", "src/libANGLE/renderer/vulkan/shaders/src/ImageCopy.frag": "f0f3cc82d78198f114b698e1aea31267", + "src/libANGLE/renderer/vulkan/shaders/src/OverlayCull.comp": + "c89a0d185f7723e0c221c135aa4f48a3", + "src/libANGLE/renderer/vulkan/shaders/src/OverlayDraw.comp": + "dcc246b398b2e07a869a264666499362", "src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.cpp": - "0660e11229f28464a6de11eb07fff7d3", + "9035e5a2674bbab577576d5b704fbe99", "src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h": - "0532a7219ffa0a5a9ca0cd7a6eb3206e", + "bd3beed76c9069d967cc2946a035e2cc", "tools/glslang/glslang_validator.exe.sha1": "289f30598865a987a21b79ae525fc66f", "tools/glslang/glslang_validator.sha1": diff --git a/scripts/code_generation_hashes/overlay_fonts.json b/scripts/code_generation_hashes/overlay_fonts.json new file mode 100644 index 00000000000..56754b507b7 --- /dev/null +++ b/scripts/code_generation_hashes/overlay_fonts.json @@ -0,0 +1,10 @@ +{ + "src/libANGLE/Overlay_font_autogen.cpp": + "ff9bf191978e8c9cff6de3e31f3664f2", + "src/libANGLE/Overlay_font_autogen.h": + "2eae247cebb716c4f591de8a251b4a8e", + "src/libANGLE/gen_overlay_fonts.py": + "e257b626441bf057856eb357a1a2ca5c", + "src/libANGLE/overlay/DejaVuSansMono-Bold.ttf": + "f580ed7569a1967ceeb96fa3e1b234d4" +} \ No newline at end of file diff --git a/scripts/code_generation_hashes/overlay_widgets.json b/scripts/code_generation_hashes/overlay_widgets.json new file mode 100644 index 00000000000..edfd26a98ad --- /dev/null +++ b/scripts/code_generation_hashes/overlay_widgets.json @@ -0,0 +1,8 @@ +{ + "src/libANGLE/Overlay_autogen.cpp": + "514b8108f62ef616c296dc511bb2f644", + "src/libANGLE/gen_overlay_widgets.py": + "07252fbde304fd48559ae07f8f920a08", + "src/libANGLE/overlay_widgets.json": + "552b1e2883a12c38d427c7fbd1c2bf22" +} \ No newline at end of file diff --git a/scripts/run_code_generation.py b/scripts/run_code_generation.py index 2210933d4c1..83229559063 100755 --- a/scripts/run_code_generation.py +++ b/scripts/run_code_generation.py @@ -105,6 +105,10 @@ def auto_script(script): 'src/libANGLE/renderer/vulkan/gen_vk_mandatory_format_support_table.py', 'Vulkan internal shader programs': 'src/libANGLE/renderer/vulkan/gen_vk_internal_shaders.py', + 'overlay fonts': + 'src/libANGLE/gen_overlay_fonts.py', + 'overlay widgets': + 'src/libANGLE/gen_overlay_widgets.py', 'Emulated HLSL functions': 'src/compiler/translator/gen_emulated_builtin_function_tables.py', 'Static builtins': diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp index 4b268b0ef1c..9720b03b86a 100644 --- a/src/libANGLE/Context.cpp +++ b/src/libANGLE/Context.cpp @@ -315,6 +315,7 @@ Context::Context(egl::Display *display, : mState(reinterpret_cast(this), shareContext ? &shareContext->mState : nullptr, shareTextures, + &mOverlay, clientType, GetClientVersion(display, attribs), GetDebug(attribs), @@ -352,7 +353,8 @@ Context::Context(egl::Display *display, mScratchBuffer(1000u), mZeroFilledBuffer(1000u), mThreadPool(nullptr), - mFrameCapture(new angle::FrameCapture) + mFrameCapture(new angle::FrameCapture), + mOverlay(mImplementation.get()) { for (angle::SubjectIndex uboIndex = kUniformBuffer0SubjectIndex; uboIndex < kUniformBufferMaxSubjectIndex; ++uboIndex) @@ -539,6 +541,9 @@ void Context::initialize() mCopyImageDirtyObjects.set(State::DIRTY_OBJECT_READ_FRAMEBUFFER); ANGLE_CONTEXT_TRY(mImplementation->initialize()); + + // Initialize overlay after implementation is initialized. + ANGLE_CONTEXT_TRY(mOverlay.init(this)); } egl::Error Context::onDestroy(const egl::Display *display) @@ -611,6 +616,8 @@ egl::Error Context::onDestroy(const egl::Display *display) mImplementation->onDestroy(this); + mOverlay.destroy(this); + return egl::NoError(); } diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h index 2ad70a7b66e..ae5a8fe5927 100644 --- a/src/libANGLE/Context.h +++ b/src/libANGLE/Context.h @@ -723,6 +723,8 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl // Note: we use a raw pointer here so we can exclude frame capture sources from the build. std::unique_ptr mFrameCapture; + + OverlayType mOverlay; }; } // namespace gl diff --git a/src/libANGLE/Overlay.cpp b/src/libANGLE/Overlay.cpp new file mode 100644 index 00000000000..2de65d2821e --- /dev/null +++ b/src/libANGLE/Overlay.cpp @@ -0,0 +1,109 @@ +// +// 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. +// +// Overlay.cpp: +// Implements the Overlay class. +// + +#include "libANGLE/Overlay.h" + +#include "common/system_utils.h" +#include "libANGLE/Context.h" +#include "libANGLE/Overlay_font_autogen.h" +#include "libANGLE/renderer/GLImplFactory.h" +#include "libANGLE/renderer/OverlayImpl.h" + +#include + +namespace gl +{ +namespace +{ +constexpr std::pair kWidgetNames[] = { + {"FPS", WidgetId::FPS}, + {"VulkanLastValidationMessage", WidgetId::VulkanLastValidationMessage}, + {"VulkanValidationMessageCount", WidgetId::VulkanValidationMessageCount}, + {"VulkanCommandGraphSize", WidgetId::VulkanCommandGraphSize}, + {"VulkanSecondaryCommandBufferPoolWaste", WidgetId::VulkanSecondaryCommandBufferPoolWaste}, +}; +} // namespace + +OverlayState::OverlayState() : mEnabledWidgetCount(0), mOverlayWidgets{} {} +OverlayState::~OverlayState() = default; + +Overlay::Overlay(rx::GLImplFactory *factory) + : mLastPerSecondUpdate(0), mImplementation(factory->createOverlay(mState)) +{} +Overlay::~Overlay() = default; + +angle::Result Overlay::init(const Context *context) +{ + initOverlayWidgets(); + mLastPerSecondUpdate = angle::GetCurrentTime(); + + ASSERT(std::all_of( + mState.mOverlayWidgets.begin(), mState.mOverlayWidgets.end(), + [](const std::unique_ptr &widget) { return widget.get() != nullptr; })); + + enableOverlayWidgetsFromEnvironment(); + + return mImplementation->init(context); +} + +void Overlay::destroy(const gl::Context *context) +{ + ASSERT(mImplementation); + mImplementation->onDestroy(context); +} + +void Overlay::enableOverlayWidgetsFromEnvironment() +{ + std::istringstream angleOverlayWidgets(angle::GetEnvironmentVar("ANGLE_OVERLAY")); + + std::set enabledWidgets; + std::string widget; + while (getline(angleOverlayWidgets, widget, ':')) + { + enabledWidgets.insert(widget); + } + + for (const std::pair &widgetName : kWidgetNames) + { + if (enabledWidgets.count(widgetName.first) > 0) + { + mState.mOverlayWidgets[widgetName.second]->enabled = true; + ++mState.mEnabledWidgetCount; + } + } +} + +void Overlay::onSwap() const +{ + // Increment FPS counter. + getPerSecondWidget(WidgetId::FPS)->add(1); + + // Update per second values every second. + double currentTime = angle::GetCurrentTime(); + double timeDiff = currentTime - mLastPerSecondUpdate; + if (timeDiff >= 1.0) + { + for (const std::unique_ptr &widget : mState.mOverlayWidgets) + { + if (widget->type == WidgetType::PerSecond) + { + overlay::PerSecond *perSecond = + reinterpret_cast(widget.get()); + perSecond->lastPerSecondCount = static_cast(perSecond->count / timeDiff); + perSecond->count = 0; + } + } + mLastPerSecondUpdate += 1.0; + } +} + +DummyOverlay::DummyOverlay(rx::GLImplFactory *implFactory) {} +DummyOverlay::~DummyOverlay() = default; + +} // namespace gl diff --git a/src/libANGLE/Overlay.h b/src/libANGLE/Overlay.h new file mode 100644 index 00000000000..7662cf4b299 --- /dev/null +++ b/src/libANGLE/Overlay.h @@ -0,0 +1,137 @@ +// +// 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. +// +// Overlay.h: +// Defines the Overlay class that handles overlay widgets. +// + +#ifndef LIBANGLE_OVERLAY_H_ +#define LIBANGLE_OVERLAY_H_ + +#include "common/PackedEnums.h" +#include "common/angleutils.h" +#include "libANGLE/Error.h" +#include "libANGLE/OverlayWidgets.h" +#include "libANGLE/angletypes.h" + +namespace rx +{ +class OverlayImpl; +class GLImplFactory; +} // namespace rx + +namespace gl +{ +class Context; + +class OverlayState : angle::NonCopyable +{ + public: + OverlayState(); + ~OverlayState(); + + size_t getWidgetCoordinatesBufferSize() const; + size_t getTextWidgetsBufferSize() const; + size_t getGraphWidgetsBufferSize() const; + + void initFontData(uint8_t *fontData) const; + void fillEnabledWidgetCoordinates(const gl::Extents &imageExtents, + uint8_t *enabledWidgetsPtr) const; + void fillWidgetData(const gl::Extents &imageExtents, + uint8_t *textData, + uint8_t *graphData) const; + + uint32_t getEnabledWidgetCount() const { return mEnabledWidgetCount; } + + private: + friend class Overlay; + + uint32_t mEnabledWidgetCount; + + angle::PackedEnumMap> mOverlayWidgets; +}; + +class Overlay : angle::NonCopyable +{ + public: + Overlay(rx::GLImplFactory *implFactory); + ~Overlay(); + + angle::Result init(const Context *context); + void destroy(const gl::Context *context); + + void onSwap() const; + + overlay::Text *getTextWidget(WidgetId id) const + { + return getWidgetAs(id); + } + overlay::Count *getCountWidget(WidgetId id) const + { + return getWidgetAs(id); + } + overlay::PerSecond *getPerSecondWidget(WidgetId id) const + { + return getWidgetAs(id); + } + overlay::RunningGraph *getRunningGraphWidget(WidgetId id) const + { + return getWidgetAs(id); + } + overlay::RunningHistogram *getRunningHistogramWidget(WidgetId id) const + { + return getWidgetAs(id); + } + + rx::OverlayImpl *getImplementation() const { return mImplementation.get(); } + + private: + template + Widget *getWidgetAs(WidgetId id) const + { + ASSERT(mState.mOverlayWidgets[id] != nullptr); + ASSERT(mState.mOverlayWidgets[id]->type == Type); + return rx::GetAs(mState.mOverlayWidgets[id].get()); + } + void initOverlayWidgets(); + void enableOverlayWidgetsFromEnvironment(); + + // Time tracking for PerSecond items. + mutable double mLastPerSecondUpdate; + + OverlayState mState; + std::unique_ptr mImplementation; +}; + +class DummyOverlay +{ + public: + DummyOverlay(rx::GLImplFactory *implFactory); + ~DummyOverlay(); + + angle::Result init(const Context *context) { return angle::Result::Continue; } + void destroy(const Context *context) {} + + void onSwap() const {} + + const overlay::Dummy *getTextWidget(WidgetId id) const { return &mDummy; } + const overlay::Dummy *getCountWidget(WidgetId id) const { return &mDummy; } + const overlay::Dummy *getPerSecondWidget(WidgetId id) const { return &mDummy; } + const overlay::Dummy *getRunningGraphWidget(WidgetId id) const { return &mDummy; } + const overlay::Dummy *getRunningHistogramWidget(WidgetId id) const { return &mDummy; } + + private: + overlay::Dummy mDummy; +}; + +#if ANGLE_ENABLE_OVERLAY +using OverlayType = Overlay; +#else // !ANGLE_ENABLE_OVERLAY +using OverlayType = DummyOverlay; +#endif // ANGLE_ENABLE_OVERLAY + +} // namespace gl + +#endif // LIBANGLE_OVERLAY_H_ diff --git a/src/libANGLE/OverlayWidgets.cpp b/src/libANGLE/OverlayWidgets.cpp new file mode 100644 index 00000000000..50cfcc1be16 --- /dev/null +++ b/src/libANGLE/OverlayWidgets.cpp @@ -0,0 +1,504 @@ +// +// 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" + +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 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 = 64; + +constexpr angle::PackedEnumMap kWidgetInternalTypeMaxWidgets = { + {WidgetInternalType::Text, kMaxRenderableTextWidgets}, + {WidgetInternalType::Graph, kMaxRenderableGraphWidgets}, +}; + +constexpr angle::PackedEnumMap kWidgetInternalTypeWidgetOffsets = { + {WidgetInternalType::Text, 0}, + {WidgetInternalType::Graph, kMaxRenderableTextWidgets}, +}; + +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(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::kFontGlyphWidths[srcFontSize]; + dstFontSize[1] = overlay::kFontGlyphHeights[srcFontSize]; + // .z contains the layer + 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 96 ASCII characters starting from ' '. + textOut[i] = src[i] - ' '; + } +} + +void GetGraphValues(const std::vector 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(srcValues[index] * scale); + } +} + +std::vector CreateHistogram(const std::vector values) +{ + std::vector histogram(values.size(), 0); + + for (size_t rank : values) + { + ++histogram[rank]; + } + + return histogram; +} + +using OverlayWidgetCounts = angle::PackedEnumMap; +using AppendWidgetDataFunc = void (*)(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts); +} // namespace + +namespace overlay_impl +{ +// 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: + static void AppendFPS(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts); + static void AppendVulkanLastValidationMessage(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts); + static void AppendVulkanValidationMessageCount(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts); + static void AppendVulkanCommandGraphSize(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts); + static void AppendVulkanSecondaryCommandBufferPoolWaste(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts); + + 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); + + static void AppendGraphCommon(const overlay::Widget *widget, + const gl::Extents &imageExtent, + const std::vector 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 runningValues, + size_t startIndex, + float scale, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + const overlay::RunningGraph *widgetAsGraph = static_cast(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::AppendFPS(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + const overlay::PerSecond *fps = static_cast(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(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(widget); + std::ostringstream text; + text << "VVL Message Count: "; + OutputCount(text, validationMessageCount); + + AppendTextCommon(widget, imageExtent, text.str(), textWidget, widgetCounts); +} + +void AppendWidgetDataHelper::AppendVulkanCommandGraphSize(const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + const overlay::RunningGraph *commandGraphSize = + static_cast(widget); + + const size_t maxValue = *std::max_element(commandGraphSize->runningValues.begin(), + commandGraphSize->runningValues.end()); + const int32_t graphHeight = std::abs(widget->coords[3] - widget->coords[1]); + const float graphScale = static_cast(graphHeight) / maxValue; + + AppendGraphCommon(widget, imageExtent, commandGraphSize->runningValues, + commandGraphSize->lastValueIndex + 1, graphScale, graphWidget, widgetCounts); + + if ((*widgetCounts)[WidgetInternalType::Text] < + kWidgetInternalTypeMaxWidgets[WidgetInternalType::Text]) + { + std::ostringstream text; + text << "Command Graph Size (Max: " << maxValue << ")"; + AppendTextCommon(&commandGraphSize->description, imageExtent, text.str(), textWidget, + widgetCounts); + } +} + +void AppendWidgetDataHelper::AppendVulkanSecondaryCommandBufferPoolWaste( + const overlay::Widget *widget, + const gl::Extents &imageExtent, + TextWidgetData *textWidget, + GraphWidgetData *graphWidget, + OverlayWidgetCounts *widgetCounts) +{ + const overlay::RunningHistogram *secondaryCommandBufferPoolWaste = + static_cast(widget); + + std::vector histogram = CreateHistogram(secondaryCommandBufferPoolWaste->runningValues); + auto maxValueIter = std::max_element(histogram.rbegin(), histogram.rend()); + const size_t maxValue = *maxValueIter; + const int32_t graphHeight = std::abs(widget->coords[3] - widget->coords[1]); + const float graphScale = static_cast(graphHeight) / maxValue; + + AppendGraphCommon(widget, imageExtent, histogram, 0, graphScale, graphWidget, widgetCounts); + + if ((*widgetCounts)[WidgetInternalType::Text] < + kWidgetInternalTypeMaxWidgets[WidgetInternalType::Text]) + { + std::ostringstream text; + size_t peak = std::distance(maxValueIter, histogram.rend() - 1); + size_t peakPercent = (peak * 100 + 50) / histogram.size(); + + text << "CB Pool Waste (Peak: " << peakPercent << "%)"; + AppendTextCommon(&secondaryCommandBufferPoolWaste->description, 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 +{ +constexpr angle::PackedEnumMap kWidgetIdToAppendDataFuncMap = { + {WidgetId::FPS, overlay_impl::AppendWidgetDataHelper::AppendFPS}, + {WidgetId::VulkanLastValidationMessage, + overlay_impl::AppendWidgetDataHelper::AppendVulkanLastValidationMessage}, + {WidgetId::VulkanValidationMessageCount, + overlay_impl::AppendWidgetDataHelper::AppendVulkanValidationMessageCount}, + {WidgetId::VulkanCommandGraphSize, + overlay_impl::AppendWidgetDataHelper::AppendVulkanCommandGraphSize}, + {WidgetId::VulkanSecondaryCommandBufferPoolWaste, + overlay_impl::AppendWidgetDataHelper::AppendVulkanSecondaryCommandBufferPoolWaste}, +}; +} + +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::fillEnabledWidgetCoordinates(const gl::Extents &imageExtents, + uint8_t *enabledWidgetsPtr) const +{ + WidgetCoordinates *enabledWidgets = reinterpret_cast(enabledWidgetsPtr); + memset(enabledWidgets, 0, sizeof(*enabledWidgets)); + + OverlayWidgetCounts widgetCounts = {}; + + for (const std::unique_ptr &widget : mOverlayWidgets) + { + if (!widget->enabled) + { + continue; + } + + WidgetInternalType internalType = kWidgetTypeToInternalMap[widget->type]; + ASSERT(internalType != WidgetInternalType::InvalidEnum); + + if (widgetCounts[internalType] >= kWidgetInternalTypeMaxWidgets[internalType]) + { + continue; + } + + size_t writeIndex = + kWidgetInternalTypeWidgetOffsets[internalType] + widgetCounts[internalType]++; + + GetWidgetCoordinates(widget->coords, imageExtents, enabledWidgets->coordinates[writeIndex]); + + // Graph widgets have a text widget attached as well. + if (internalType == WidgetInternalType::Graph) + { + WidgetInternalType textType = WidgetInternalType::Text; + if (widgetCounts[textType] >= kWidgetInternalTypeMaxWidgets[textType]) + { + continue; + } + + const overlay::RunningGraph *widgetAsGraph = + static_cast(widget.get()); + writeIndex = kWidgetInternalTypeWidgetOffsets[textType] + widgetCounts[textType]++; + + GetWidgetCoordinates(widgetAsGraph->description.coords, imageExtents, + enabledWidgets->coordinates[writeIndex]); + } + } +} + +void OverlayState::fillWidgetData(const gl::Extents &imageExtents, + uint8_t *textData, + uint8_t *graphData) const +{ + TextWidgets *textWidgets = reinterpret_cast(textData); + GraphWidgets *graphWidgets = reinterpret_cast(graphData); + + memset(textWidgets, overlay::kFontCharacters, sizeof(*textWidgets)); + memset(graphWidgets, 0, sizeof(*graphWidgets)); + + OverlayWidgetCounts widgetCounts = {}; + + for (WidgetId id : angle::AllEnums()) + { + const std::unique_ptr &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]; + appendFunc(widget.get(), imageExtents, + &textWidgets->widgets[widgetCounts[WidgetInternalType::Text]], + &graphWidgets->widgets[widgetCounts[WidgetInternalType::Graph]], &widgetCounts); + } +} + +} // namespace gl diff --git a/src/libANGLE/OverlayWidgets.h b/src/libANGLE/OverlayWidgets.h new file mode 100644 index 00000000000..82399c7b280 --- /dev/null +++ b/src/libANGLE/OverlayWidgets.h @@ -0,0 +1,181 @@ +// +// 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.h: +// Defines the Overlay* widget classes and corresponding enums. +// + +#ifndef LIBANGLE_OVERLAYWIDGETS_H_ +#define LIBANGLE_OVERLAYWIDGETS_H_ + +#include "common/angleutils.h" + +namespace gl +{ +class Overlay; +class OverlayState; + +namespace overlay_impl +{ +class AppendWidgetDataHelper; +} + +enum class WidgetType +{ + // Text types: + + // A total count of some event. + Count, + // A single line of ASCII text. Retains content until changed. + Text, + // A per-second value. + PerSecond, + + // Graph types: + + // A graph of the last N values. + RunningGraph, + // A histogram of the last N values (values between 0 and 1). + RunningHistogram, + + InvalidEnum, + EnumCount = InvalidEnum, +}; + +enum class WidgetId +{ + // Front-end widgets: + + // Frames per second (PerSecond). + FPS, + + // Vulkan backend: + + // Last validation error (Text). + VulkanLastValidationMessage, + // Number of validation errors and warnings (Count). + VulkanValidationMessageCount, + // Number of nodes in command graph (RunningGraph). + VulkanCommandGraphSize, + // Secondary Command Buffer pool memory waste (RunningHistogram). + VulkanSecondaryCommandBufferPoolWaste, + + InvalidEnum, + EnumCount = InvalidEnum, +}; + +namespace overlay +{ +class Widget +{ + protected: + WidgetType type; + // Whether this item should be drawn. + bool enabled = false; + + // For text items, size of the font. This is a value in [0, overlay::kFontCount) which + // determines the font size to use. + int fontSize; + + // The area covered by the item, predetermined by the overlay class. Negative values + // indicate offset from the left/bottom of the image. + int32_t coords[4]; + float color[4]; + + friend class gl::Overlay; + friend class gl::OverlayState; + friend class overlay_impl::AppendWidgetDataHelper; +}; + +class Count : public Widget +{ + public: + void add(size_t n) { count += n; } + void reset() { count = 0; } + + protected: + size_t count = 0; + + friend class gl::Overlay; + friend class overlay_impl::AppendWidgetDataHelper; +}; + +class PerSecond : public Count +{ + protected: + size_t lastPerSecondCount = 0; + + friend class gl::Overlay; + friend class overlay_impl::AppendWidgetDataHelper; +}; + +class Text : public Widget +{ + public: + void set(std::string &&str) { text = std::move(str); } + + protected: + std::string text; + + friend class overlay_impl::AppendWidgetDataHelper; +}; + +class RunningGraph : public Widget +{ + public: + // Out of line constructor to satisfy chromium-style. + RunningGraph(size_t n); + ~RunningGraph(); + void add(size_t n) { runningValues[lastValueIndex] += n; } + void next() + { + lastValueIndex = (lastValueIndex + 1) % runningValues.size(); + runningValues[lastValueIndex] = 0; + } + + protected: + std::vector runningValues; + size_t lastValueIndex = 0; + Text description; + + friend class gl::Overlay; + friend class gl::OverlayState; + friend class overlay_impl::AppendWidgetDataHelper; +}; + +class RunningHistogram : public RunningGraph +{ + public: + RunningHistogram(size_t n) : RunningGraph(n) {} + void set(float n) + { + ASSERT(n >= 0.0f && n <= 1.0f); + size_t rank = + n == 1.0f ? runningValues.size() - 1 : static_cast(n * runningValues.size()); + + runningValues[lastValueIndex] = rank; + } +}; + +// If overlay is disabled, all the above classes would be replaced with Dummy, turning them into +// noop. +class Dummy +{ + public: + void reset() const {} + template + void set(T) const + {} + template + void add(T) const + {} + void next() const {} +}; + +} // namespace overlay + +} // namespace gl + +#endif // LIBANGLE_OVERLAYWIDGETS_H_ diff --git a/src/libANGLE/Overlay_autogen.cpp b/src/libANGLE/Overlay_autogen.cpp new file mode 100644 index 00000000000..f202d0e6374 --- /dev/null +++ b/src/libANGLE/Overlay_autogen.cpp @@ -0,0 +1,193 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_overlay_widgets.py using data from overlay_widgets.json. +// +// Copyright 2019 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Overlay_autogen.cpp: +// Autogenerated overlay widget declarations. + +#include "libANGLE/Overlay.h" +#include "libANGLE/OverlayWidgets.h" +#include "libANGLE/Overlay_font_autogen.h" +#include "libANGLE/renderer/driver_utils.h" + +namespace gl +{ +using namespace overlay; + +namespace +{ +int GetFontSize(int fontSize, bool largeFont) +{ + if (largeFont && fontSize > 0) + { + return fontSize - 1; + } + return fontSize; +} +} // anonymous namespace + +void Overlay::initOverlayWidgets() +{ + const bool kLargeFont = rx::IsAndroid(); + + { + PerSecond *widget = new PerSecond; + { + const int32_t fontSize = GetFontSize(kFontLayerMedium, kLargeFont); + const int32_t offsetX = 10; + const int32_t offsetY = 10; + const int32_t width = 12 * kFontGlyphWidths[fontSize]; + const int32_t height = kFontGlyphHeights[fontSize]; + + widget->type = WidgetType::PerSecond; + widget->fontSize = fontSize; + widget->coords[0] = offsetX; + widget->coords[1] = offsetY; + widget->coords[2] = offsetX + width; + widget->coords[3] = offsetY + height; + widget->color[0] = 0.498039215686; + widget->color[1] = 0.749019607843; + widget->color[2] = 1.0; + widget->color[3] = 1.0; + } + mState.mOverlayWidgets[WidgetId::FPS].reset(widget); + } + + { + Text *widget = new Text; + { + const int32_t fontSize = GetFontSize(kFontLayerSmall, kLargeFont); + const int32_t offsetX = 10; + const int32_t offsetY = -10; + const int32_t width = 150 * kFontGlyphWidths[fontSize]; + const int32_t height = kFontGlyphHeights[fontSize]; + + widget->type = WidgetType::Text; + widget->fontSize = fontSize; + widget->coords[0] = offsetX; + widget->coords[1] = offsetY - height; + widget->coords[2] = offsetX + width; + widget->coords[3] = offsetY; + widget->color[0] = 1.0; + widget->color[1] = 0.0; + widget->color[2] = 0.0; + widget->color[3] = 1.0; + } + mState.mOverlayWidgets[WidgetId::VulkanLastValidationMessage].reset(widget); + } + + { + Count *widget = new Count; + { + const int32_t fontSize = GetFontSize(kFontLayerSmall, kLargeFont); + const int32_t offsetX = 10; + const int32_t offsetY = + mState.mOverlayWidgets[WidgetId::VulkanLastValidationMessage]->coords[1]; + const int32_t width = 25 * kFontGlyphWidths[fontSize]; + const int32_t height = kFontGlyphHeights[fontSize]; + + widget->type = WidgetType::Count; + widget->fontSize = fontSize; + widget->coords[0] = offsetX; + widget->coords[1] = offsetY - height; + widget->coords[2] = offsetX + width; + widget->coords[3] = offsetY; + widget->color[0] = 1.0; + widget->color[1] = 0.0; + widget->color[2] = 0.0; + widget->color[3] = 1.0; + } + mState.mOverlayWidgets[WidgetId::VulkanValidationMessageCount].reset(widget); + } + + { + RunningGraph *widget = new RunningGraph(60); + { + const int32_t fontSize = GetFontSize(0, kLargeFont); + const int32_t offsetX = 10; + const int32_t offsetY = 100; + const int32_t width = 5 * static_cast(widget->runningValues.size()); + const int32_t height = 100; + + widget->type = WidgetType::RunningGraph; + widget->fontSize = fontSize; + widget->coords[0] = offsetX; + widget->coords[1] = offsetY; + widget->coords[2] = offsetX + width; + widget->coords[3] = offsetY + height; + widget->color[0] = 0.294117647059; + widget->color[1] = 0.78431372549; + widget->color[2] = 0.0; + widget->color[3] = 0.78431372549; + } + mState.mOverlayWidgets[WidgetId::VulkanCommandGraphSize].reset(widget); + { + const int32_t fontSize = GetFontSize(kFontLayerSmall, kLargeFont); + const int32_t offsetX = + mState.mOverlayWidgets[WidgetId::VulkanCommandGraphSize]->coords[0]; + const int32_t offsetY = + mState.mOverlayWidgets[WidgetId::VulkanCommandGraphSize]->coords[1]; + const int32_t width = 40 * kFontGlyphWidths[fontSize]; + const int32_t height = kFontGlyphHeights[fontSize]; + + widget->description.type = WidgetType::Text; + widget->description.fontSize = fontSize; + widget->description.coords[0] = offsetX; + widget->description.coords[1] = std::max(offsetY - height, 1); + widget->description.coords[2] = offsetX + width; + widget->description.coords[3] = offsetY; + widget->description.color[0] = 0.294117647059; + widget->description.color[1] = 0.78431372549; + widget->description.color[2] = 0.0; + widget->description.color[3] = 1.0; + } + } + + { + RunningHistogram *widget = new RunningHistogram(50); + { + const int32_t fontSize = GetFontSize(0, kLargeFont); + const int32_t offsetX = -50; + const int32_t offsetY = 100; + const int32_t width = 6 * static_cast(widget->runningValues.size()); + const int32_t height = 100; + + widget->type = WidgetType::RunningHistogram; + widget->fontSize = fontSize; + widget->coords[0] = offsetX - width; + widget->coords[1] = offsetY; + widget->coords[2] = offsetX; + widget->coords[3] = offsetY + height; + widget->color[0] = 1.0; + widget->color[1] = 0.78431372549; + widget->color[2] = 0.294117647059; + widget->color[3] = 0.78431372549; + } + mState.mOverlayWidgets[WidgetId::VulkanSecondaryCommandBufferPoolWaste].reset(widget); + { + const int32_t fontSize = GetFontSize(kFontLayerSmall, kLargeFont); + const int32_t offsetX = + mState.mOverlayWidgets[WidgetId::VulkanSecondaryCommandBufferPoolWaste]->coords[0]; + const int32_t offsetY = + mState.mOverlayWidgets[WidgetId::VulkanSecondaryCommandBufferPoolWaste]->coords[1]; + const int32_t width = 40 * kFontGlyphWidths[fontSize]; + const int32_t height = kFontGlyphHeights[fontSize]; + + widget->description.type = WidgetType::Text; + widget->description.fontSize = fontSize; + widget->description.coords[0] = offsetX; + widget->description.coords[1] = std::max(offsetY - height, 1); + widget->description.coords[2] = std::min(offsetX + width, -1); + widget->description.coords[3] = offsetY; + widget->description.color[0] = 1.0; + widget->description.color[1] = 0.78431372549; + widget->description.color[2] = 0.294117647059; + widget->description.color[3] = 1.0; + } + } +} + +} // namespace gl diff --git a/src/libANGLE/Overlay_font_autogen.cpp b/src/libANGLE/Overlay_font_autogen.cpp new file mode 100644 index 00000000000..b09f6d900cf --- /dev/null +++ b/src/libANGLE/Overlay_font_autogen.cpp @@ -0,0 +1,2728 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_overlay_fonts.py using images from overlay/DejaVuSansMono-Bold.ttf. +// +// 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. +// +// Overlay_font_autogen.cpp: +// Autogenerated overlay font data. + +#include "libANGLE/Overlay_font_autogen.h" +#include "libANGLE/Overlay.h" + +#include + +namespace gl +{ +using namespace overlay; + +// Save binary size if the font images are never to be used. +#if ANGLE_ENABLE_OVERLAY +namespace +{ +constexpr int kFontWidths[kFontCount] = {kFontGlyphWidths[0] * kFontCharactersPerRow, + kFontGlyphWidths[1] * kFontCharactersPerRow, + kFontGlyphWidths[2] * kFontCharactersPerRow}; +constexpr int kFontHeights[kFontCount] = {kFontGlyphHeights[0] * kFontCharactersPerCol, + kFontGlyphHeights[1] * kFontCharactersPerCol, + kFontGlyphHeights[2] * kFontCharactersPerCol}; + +constexpr uint32_t + kFontImageLarge[kFontHeights[kFontLayerLarge]][kFontWidths[kFontLayerLarge] / 32] = { + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x003C3C00, 0x0000000C, 0x00000000, 0xF0000000, + 0x0000F000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0xC0000000, 0x3E1F0007, 0x003C3C00, 0x007C000C, 0x0007F000, 0x78000078, + 0x0000F000, 0x000000E0, 0x00000000, 0x00000000, 0x1C000000, 0xF0003F00, + 0x01FE000F, 0x0000FF80, 0xFFFE01F8, 0xF00FE000, 0x3F801FFF, 0x000FE000, + 0x00000000, 0x00000000, 0x00000000, 0x01FC0000, + }, + { + 0xC0000000, 0x3E1F0007, 0x001E3C00, 0x00FF000C, 0x000FFC00, 0x78000078, + 0x0001E000, 0x000000E0, 0x00000000, 0x00000000, 0x1E000000, 0xFC00FFC0, + 0x0FFF800F, 0x0003FFE0, 0xFFFE01F8, 0xF03FF800, 0xFFE01FFF, 0x003FF800, + 0x00000000, 0x00000000, 0x00000000, 0x03FF8000, + }, + { + 0xC0000000, 0x3E1F0007, 0x001E3C00, 0x01FF800C, 0x000FFE00, 0x7C000078, + 0x8003E000, 0x000020E0, 0x00000000, 0x00000000, 0x1E000000, 0xFC01FFE0, + 0x1FFF800F, 0x0007FFE0, 0xFFFE01FC, 0xF03FFC00, 0xFFF01FFF, 0x007FFC01, + 0x00000000, 0x00000000, 0x00000000, 0x0FFFC000, + }, + { + 0xC0000000, 0x3E1F0007, 0x801E1E00, 0x01C780FF, 0x000FFF00, 0x3C000078, + 0x8003C000, 0x000070E3, 0x00000000, 0x00000000, 0x0F000000, 0xFC01FFF0, + 0x3FFF800F, 0x000FFFE0, 0xFFFE01FE, 0xF03FFE00, 0xFFF01FFF, 0x007FFE03, + 0x00000000, 0x00000000, 0x00000000, 0x0FFFC000, + }, + { + 0xC0000000, 0x3E1F0007, 0xE01E1E00, 0x03C383FF, 0x000FFF00, 0x3E000078, + 0xC007C000, 0x00007CEF, 0x00000000, 0x00000000, 0x0F000000, 0x9C03F1F0, + 0x3F83800F, 0x000FFFE0, 0x003E01FE, 0x00383F00, 0xE1F81F80, 0x00FC7E03, + 0x00000000, 0x00000000, 0x00000000, 0x1F83C000, + }, + { + 0xC0000000, 0x3E1F0007, 0xF00F1E00, 0x038383FF, 0x00081F00, 0x1E000078, + 0x0007C000, 0x78003FFF, 0x00000000, 0x00000000, 0x07800000, 0x8003E1F8, + 0x3E00800F, 0x001FC060, 0x003E01FF, 0x00201F00, 0xC0F80F80, 0x00F83F07, + 0x00000000, 0x08000000, 0x00400000, 0x1F80C000, + }, + { + 0xC0000000, 0x3E1F0007, 0xF8FFFFF0, 0x03C383FF, 0x00001F00, 0x1F000078, + 0x00078000, 0x78000FFE, 0x00000000, 0x00000000, 0x07800000, 0x8007C0F8, + 0x7E00000F, 0x801F8000, 0x003E01FF, 0x00000F80, 0xC0F80FC0, 0x01F81F07, + 0x00000000, 0x0F000000, 0x01C00000, 0x1F004000, + }, + { + 0xC0000000, 0x3E1F0007, 0xF8FFFFF0, 0x01C7838C, 0x00001F00, 0x1F000078, + 0x000F8000, 0x780007F8, 0x00000000, 0x00000000, 0x03C00000, 0x8007C0F8, + 0x7E00000F, 0x801F0000, 0x003E01F7, 0x00000F80, 0xC0F807C0, 0x01F01F07, + 0xFC0003F0, 0x0FC00000, 0x0FC00000, 0x1F800000, + }, + { + 0xC0000000, 0x3E1F0007, 0xF8FFFFF0, 0x01FF800C, 0x00003E02, 0x0F000078, + 0x000F8000, 0x780007F8, 0x00000000, 0x00000000, 0x03C00000, 0x8007C0FC, + 0x7E00000F, 0xC00F8000, 0x003E01F3, 0x0007E780, 0xC0F807C0, 0x01F01F03, + 0xFC0003F0, 0x0FF80000, 0x3FC00000, 0x0F800000, + }, + { + 0xC0000000, 0x3E1F0007, 0xF8FFFFF0, 0xC0FF000C, 0x00007E03, 0x0F800078, + 0x000F8000, 0x78000FFE, 0x00000000, 0x00000000, 0x01E00000, 0x8007C0FC, + 0x3E00000F, 0xE00FC000, 0x0FFE01F3, 0x001FF780, 0xE1F007E0, 0x01F01F03, + 0xFC0003F0, 0x0FFE0000, 0xFFC3FFFF, 0x0FC00001, + }, + { + 0xC0000000, 0x00000007, 0xF8078F00, 0xF07C000C, 0x0000FE00, 0x0F800000, + 0x001F0000, 0x78003FFF, 0x00000000, 0x00000000, 0x01E00000, 0x8007C07C, + 0x3F00000F, 0xE007FE00, 0x3FFE01F1, 0x003FFFC0, 0xFFE003E0, 0x01F01F01, + 0xFC0003F0, 0x01FFC000, 0xFF03FFFF, 0x07E00007, + }, + { + 0xC0000000, 0x00000007, 0xF8078780, 0x3C00000D, 0x0000FF80, 0x0F800000, + 0xC01F0000, 0x78007CEF, 0x00000000, 0x00000000, 0x00F00000, 0x8007CE7C, + 0x1F00000F, 0xF003FE00, 0x7FFE01F0, 0x007FFFC0, 0xFFC003F0, 0x01F81F00, + 0xFC0003F0, 0x007FF000, 0xF803FFFF, 0x03F0003F, + }, + { + 0x80000000, 0x00000007, 0xF0078780, 0x0F00001F, 0x01E1FF80, 0x0F800000, + 0x801F0000, 0x780070E3, 0x00000000, 0x00000000, 0x00F00000, 0x800FDE7C, + 0x1F80000F, 0xF801FE00, 0xFFFE01F0, 0x007E3FC0, 0xFFE001F0, 0x01F83F00, + 0xFC0003F0, 0x000FFC00, 0xC003FFFF, 0x01F800FF, + }, + { + 0x80000000, 0x00000007, 0xF003C780, 0x03C000FF, 0x01E3E3C0, 0x0F800000, + 0x801F0000, 0xFFF820E0, 0x0000007F, 0x00003FF8, 0x00700000, 0x800FDE7C, + 0x0FC0000F, 0x7807FE00, 0xFE0601F0, 0x007C1FC0, 0xFFF001F0, 0x01FC7E03, + 0x00000000, 0x0001FC00, 0x00000000, 0x00FC00FE, + }, + { + 0x80000000, 0x00000007, 0xC003C780, 0x00F801FF, 0x01E7E3E0, 0x0F800000, + 0x001F0000, 0xFFF800E0, 0x0000007F, 0x00003FF8, 0x00780000, 0x8007CE7C, + 0x07E0000F, 0x7C0FFE00, 0xF80001F0, 0x00FC0FC1, 0xE1F801F8, 0x01FFFE03, + 0x00000000, 0x00007C00, 0x00000000, 0x007C00F8, + }, + { + 0x80000000, 0x00000007, 0x003FFFFC, 0xF81E03FF, 0x01E7C1E0, 0x0F800000, + 0x001F0000, 0xFFF800E0, 0x0000007F, 0x00003FF8, 0x00780000, 0x8007C07C, + 0x03F0000F, 0x3C1FC000, 0xF00001F0, 0x00F80FC1, 0xC0F800F8, 0x01FFFC07, + 0x00000000, 0x0001FC00, 0x00000000, 0x007C00FE, + }, + { + 0x80000000, 0x00000007, 0x003FFFFC, 0xFC0707FC, 0x01EF81E3, 0x0F800000, + 0x001F0000, 0xFFF80000, 0x0000007F, 0x00003FF8, 0x003C0000, 0x8007C0FC, + 0x01F8000F, 0xFC1F0000, 0xF0000FFF, 0x00F80FC1, 0xC07C00FC, 0x01FFF807, + 0x00000000, 0x000FFC00, 0xC0000000, 0x003C00FF, + }, + { + 0x80000000, 0x00000007, 0x003FFFFC, 0xFE0107CC, 0x01FF83E7, 0x0F800000, + 0x001F0000, 0x78000000, 0x00000000, 0x00003FF8, 0x003C0000, 0x8007C0FC, + 0x00FC000F, 0xFC1F0000, 0xF0000FFF, 0x00F80F81, 0x807C007C, 0x01F3F007, + 0x00000000, 0x003FF000, 0xF803FFFF, 0x003C003F, + }, + { + 0x00000000, 0x00000000, 0x003FFFFC, 0x8E0007CC, 0x00FF03E7, 0x0F800000, + 0x001F0000, 0x78000000, 0x00000000, 0x00000000, 0x001E0000, 0x8007C0F8, + 0x007E000F, 0xFC1F0000, 0xF0000FFF, 0x00F80F81, 0x807C007C, 0x01F00007, + 0x00000000, 0x01FFC000, 0xFF03FFFF, 0x003C0007, + }, + { + 0x00000000, 0x00000000, 0x0801E1C0, 0x0F0007CC, 0x007E07E7, 0x0F800000, + 0x001F0000, 0x78000000, 0x00000000, 0x00000000, 0x001E0000, 0x8007C0F8, + 0x003F000F, 0xFC1F0000, 0xF0000FFF, 0x007C0F81, 0xC07C007E, 0x00F00007, + 0x00000000, 0x0FFE0000, 0xFFC3FFFF, 0x00000001, + }, + { + 0x00000000, 0x00000000, 0x1801E1E0, 0x070007CC, 0x007F0FE7, 0x0F800000, + 0x000F8000, 0x78000000, 0x003F0000, 0xF0000000, 0x000F0003, 0x8003E1F8, + 0x001F000F, 0x001FC070, 0xF80001F0, 0x007C1F81, 0xC0F8003E, 0x00F80007, + 0xFC0003F0, 0x0FF80000, 0x3FC3FFFF, 0x00000000, + }, + { + 0xC0000000, 0x00000007, 0x7800E1E0, 0x0F0007EC, 0x007FFFE7, 0x0F000000, + 0x000F8000, 0x78000000, 0x003F0000, 0xF0000000, 0x000F0003, 0x8003F1F0, + 0x000F800F, 0x001FFFF0, 0xFC0F01F0, 0x007E3F00, 0xE1F8003E, 0x00FE0C07, + 0xFC0003F0, 0x0FC00000, 0x0FC00000, 0x003C0000, + }, + { + 0xC0000000, 0x00000007, 0xF800F1E0, 0x8E0003FF, 0x00FFFFC7, 0x1F000000, + 0x000F8000, 0x78000000, 0x003F0000, 0xF0000000, 0x00078003, 0xFE01FFF0, + 0x7FFFC3FF, 0x000FFFF0, 0xFFFF01F0, 0x003FFF00, 0xFFF8001F, 0x007FFC03, + 0xFC0003F0, 0x0F000000, 0x01C00000, 0x003C0000, + }, + { + 0xC0000000, 0x00000007, 0xF800F1E0, 0xFE0003FF, 0x00FFFF87, 0x1F000000, + 0x00078000, 0x78000000, 0x003F0000, 0xF0000000, 0x00078003, 0xFE01FFE0, + 0x7FFFC3FF, 0x000FFFF0, 0x7FFF01F0, 0x003FFE00, 0xFFF0001F, 0x003FFC03, + 0xFC0003F0, 0x08000000, 0x00400000, 0x003C0000, + }, + { + 0xC0000000, 0x00000007, 0xF000F0F0, 0xFC0001FF, 0x01FFFF03, 0x1E000000, + 0x0007C000, 0x78000000, 0x003F0000, 0xF0000000, 0x0003C003, 0xFE00FFC0, + 0x7FFFC3FF, 0x0003FFF0, 0x3FFF01F0, 0x800FFC00, 0xFFE0001F, 0x001FFC00, + 0xFC0003F0, 0x00000000, 0x00000000, 0x003C0000, + }, + { + 0xC0000000, 0x00000007, 0x8000F0F0, 0xF800007F, 0x01F1FC00, 0x3E000000, + 0x0007C000, 0x00000000, 0x001F0000, 0xF0000000, 0x0003C003, 0xFE003F00, + 0x7FFFC3FF, 0x0000FF80, 0x07F801F0, 0x8007F000, 0x3F80000F, 0x0003F800, + 0xFC0003F0, 0x00000000, 0x00000000, 0x003C0000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x0000000C, 0x00000000, 0x3C000000, + 0x0003C000, 0x00000000, 0x001F0000, 0x00000000, 0x0003C000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x7C000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x0000000C, 0x00000000, 0x7C000000, + 0x0003E000, 0x00000000, 0x000F8000, 0x00000000, 0x0001E000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x7E000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x0000000C, 0x00000000, 0x78000000, + 0x0001E000, 0x00000000, 0x000F8000, 0x00000000, 0x0001E000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x3E000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x0000000C, 0x00000000, 0x78000000, + 0x0000F000, 0x00000000, 0x00078000, 0x00000000, 0x0000F000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x3E000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x0000000C, 0x00000000, 0xF0000000, + 0x0000F000, 0x00000000, 0x00078000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x1E000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x0003C000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x1E000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFE000000, 0x00000003, 0x00000FF8, 0x00000000, + }, + { + 0xC0000000, 0x07FFC00F, 0xFC07F000, 0xFFFE000F, 0x00FFFF81, 0xC0FC03F8, + 0x01FFFE07, 0x01F03FFC, 0x8001F07E, 0x0FC3F03F, 0x00FC00F8, 0xC0007FF8, + 0x03FFC00F, 0xFC00FE00, 0xE01F0FFF, 0x7DF803E3, 0x803EF800, 0xC7C00FDF, + 0xFE00FFFF, 0x00003C03, 0xF0000FF8, 0x00000001, + }, + { + 0xE0007E00, 0x1FFFC00F, 0xFC1FFC00, 0xFFFE007F, 0x00FFFF81, 0xC0FC0FFE, + 0x01FFFE07, 0x01F03FFC, 0x8001F03F, 0x0FC3F83F, 0x03FF00F8, 0xF001FFF8, + 0x1FFFC03F, 0xFC07FF80, 0xE01F0FFF, 0x7CF807E3, 0x807CF800, 0xC7E00F8F, + 0xFE00FFFF, 0x00007803, 0xF0000FF8, 0x00000003, + }, + { + 0xE001FFC0, 0x3FFFC01F, 0xFC1FFF00, 0xFFFE01FF, 0x00FFFF81, 0xC0FC1FFF, + 0x01FFFE07, 0x81F03FFC, 0x8001F01F, 0x1FC3F83F, 0x07FF80F8, 0xF803FFF8, + 0x3FFFC07F, 0xFC0FFFC0, 0xE01F0FFF, 0x7CF807C3, 0xC0FC7800, 0xC3E01F8F, + 0x3E00FFFF, 0x00007800, 0xF8000F00, 0x00000007, + }, + { + 0xE003FFE0, 0x7FFFC01F, 0xFC1FFF80, 0xFFFE03FF, 0x80FFFF81, 0xC0FC1FFF, + 0x01FFFE07, 0x81F03FFC, 0x8001F00F, 0x1FC3F87F, 0x0FFFC0F8, 0xFC07FFF8, + 0x3FFFC0FF, 0xFC0FFFE0, 0xE01F0FFF, 0x7CF807C3, 0xC0F87800, 0xC3F01F07, + 0x3E00FFFF, 0x0000F000, 0xFC000F00, 0x0000000F, + }, + { + 0xF007C1F0, 0x7E07C01F, 0xFC1FFF80, 0xFFFE03FF, 0xC0FFFF81, 0xC0FC1FFF, + 0x01FFFE07, 0xC1F03FFC, 0x8001F00F, 0x1FC3F87F, 0x0FFFE0F8, 0xFE0FFFF8, + 0x7FFFC0FF, 0xFC0FFFE0, 0xE01F0FFF, 0x78FC07C3, 0xE1F87800, 0xC1F03F03, + 0x3E00FFFF, 0x0000F000, 0xFE000F00, 0x0000000F, + }, + { + 0xF00F00F8, 0x7C07C03F, 0xFC1C1FC0, 0x003E07F0, 0xE0000F80, 0xC0FC1C1F, + 0x0007C007, 0xE1F03E00, 0x8001F007, 0x3FC3FC7F, 0x1FC7E0F8, 0x7E0FE0F8, + 0x7E0FC1FC, 0x000F07F0, 0xE01F001F, 0x787C07C3, 0xF1F07800, 0x01F83E03, + 0x3E007E00, 0x0000F000, 0x3F000F00, 0x0000001F, + }, + { + 0xF00F007C, 0x7C07C03E, 0xFC100FC0, 0x003E07E0, 0xE0000F80, 0xC0FC1807, + 0x0007C007, 0xF1F03E00, 0x8001F003, 0x3FC3FCFF, 0x1F83F0F8, 0x3E0FC0F8, + 0x7C0FC1F8, 0x000C03F0, 0xE01F001F, 0x787C0F83, 0xF3F07800, 0x00F87E01, + 0x3E003E00, 0x0001E000, 0x1F000F00, 0x0000003E, + }, + { + 0xF00E003C, 0x7C07C03E, 0xFC0007E0, 0x003E07C0, 0xE0000F80, 0xC0FC0007, + 0x0007C007, 0xF9F03E00, 0x8001F001, 0x7FC3DCEF, 0x3F03F0F8, 0x3F0F80F8, + 0x7C0FC1F0, 0x000801F0, 0xE01F001F, 0x787C0F83, 0xFBE07878, 0x00FC7C01, + 0x3E003F00, 0x0001E000, 0x0F800F00, 0x0000007C, + }, + { + 0xF80EF81E, 0x7C07C03C, 0xFC0007E0, 0x003E0FC0, 0xE0000F80, 0xC0FC0003, + 0x0007C007, 0xF9F03E00, 0x8001F000, 0x7FC3DCEF, 0x3F01F0F8, 0x1F0F80F8, + 0x7C0FC3F0, 0x000003F0, 0xE01F001F, 0x787C0F83, 0xFFC07C7C, 0x007CFC00, + 0x3E001F80, 0x0003C000, 0x07C00F00, 0x000000F8, + }, + { + 0xF80FFE1E, 0x7E07C07C, 0xFC0003E0, 0x003E0FC0, 0xF0000F80, 0xC0FC0003, + 0x0007C007, 0xFDF03E00, 0x8001F000, 0x77C3DEEF, 0x3F01F0F8, 0x1F0FC0F8, + 0x7C0FC3F0, 0x000003E0, 0xE01F001F, 0x783E0F83, 0x7FC07CFC, 0x007EF800, + 0x3E000F80, 0x0003C000, 0x03E00F00, 0x000000F0, + }, + { + 0x780FFF0E, 0x3FFFC07C, 0xFC0003E0, 0xFFFE0FC0, 0xF07FFF80, 0xFFFC0003, + 0x0007C007, 0x7FF03E00, 0x8001F000, 0xF7C3CFEF, 0x3E01F0F8, 0x1F0FE0F8, + 0x7E0FC3F0, 0x00000FE0, 0xE01F001F, 0xF83E0F83, 0x7F803CFC, 0x003FF000, + 0x3E000FC0, 0x00078000, 0x00000F00, 0x00000000, + }, + { + 0x780F8F0E, 0x0FFFC07C, 0xFC0003E0, 0xFFFE0F80, 0xF07FFF80, 0xFFFC3FC3, + 0x0007C007, 0xFFF03E00, 0x8001F000, 0xF7C3CFCF, 0x3E01F0F8, 0x1F0FFFF8, + 0x3FFFC3E0, 0x00007FC0, 0xE01F001F, 0xF83E1F03, 0x3F803CFC, 0x003FF000, + 0x3E0007E0, 0x00078000, 0x00000F00, 0x00000000, + }, + { + 0x7C0F078F, 0x1FFFC078, 0xFC0003E0, 0xFFFE0F80, 0xF07FFF80, 0xFFFC3FC3, + 0x0007C007, 0xFFF03E00, 0x8001F000, 0xE7C3CFCF, 0x3E01F0F9, 0x1F07FFF8, + 0x1FFFC3E0, 0x0003FF80, 0xE01F001F, 0xF03E1F03, 0x3F003CFC, 0x001FE000, + 0x3E0003E0, 0x000F0000, 0x00000F00, 0x00000000, + }, + { + 0x7C0E078F, 0x3FFFC0F8, 0xFC0003E0, 0xFFFE0F80, 0xF07FFF80, 0xFFFC3FC1, + 0x0007C007, 0xFFF03E00, 0x8001F001, 0xE7C3CFCF, 0x3E01F0F9, 0x1F03FFF8, + 0x07FFC3E0, 0x0007FE00, 0xE01F001F, 0xF01E1F03, 0x3F003CFE, 0x001FE000, + 0x3E0001F0, 0x000F0000, 0x00000F00, 0x00000000, + }, + { + 0x7C0E078F, 0x7E07C0F8, 0xFC0003E0, 0xFFFE0F80, 0xF07FFF80, 0xFFFC3FC3, + 0x0007C007, 0xFFF03E00, 0x8001F001, 0xC7C3C7CF, 0x3E01F0F9, 0x1F01FFF8, + 0x0FFFC3E0, 0x000FF800, 0xE01F001F, 0xF01F1F03, 0x7F803DEE, 0x000FC000, + 0x3E0001F8, 0x001E0000, 0x00000F00, 0x00000000, + }, + { + 0xFE0E038F, 0xFC07C0FF, 0xFC0003E0, 0x003E0FC0, 0xF0000F80, 0xC0FC3FC3, + 0x0007C007, 0xF7F03E00, 0x8001F003, 0xC7C3C78F, 0x3E01F0FB, 0x1F007FF8, + 0x0FFFC3E0, 0x001FC000, 0xE01F001F, 0xF01F3E03, 0x7F803DEE, 0x000FC000, + 0x3E0000FC, 0x001E0000, 0x00000F00, 0x00000000, + }, + { + 0xFE0E038F, 0xF807C1FF, 0xFC0003E0, 0x003E0FC0, 0xF0000F80, 0xC0FC3E03, + 0x0007C007, 0xE3F03E00, 0x8001F003, 0xC7C3C00F, 0x3F01F0FB, 0x1F0000F8, + 0x1F8FC3F0, 0x001F0000, 0xE01F001F, 0xF01F3E03, 0xFFC03DCE, 0x0007C000, + 0x3E00007C, 0x001C0000, 0x00000F00, 0x00000000, + }, + { + 0xFE0E078F, 0xF807C1FF, 0xFC0007E0, 0x003E0FC0, 0xE0000F80, 0xC0FC3E03, + 0x0007C007, 0xE1F03F00, 0x8001F007, 0x87C3C00F, 0x3F01F0FB, 0x1F0000F8, + 0x1F0FC3F0, 0x001F0000, 0xE01F001F, 0xF00F3E03, 0xFFE03FCF, 0x0007C000, + 0x3E00007E, 0x003C0000, 0x00000F00, 0x00000000, + }, + { + 0xFE0E078F, 0xF807C1FF, 0xFC0007E0, 0x003E07C0, 0xE0000F80, 0xC0FC3E07, + 0x4007C007, 0xC1F03F00, 0x8001F007, 0x87C3C00F, 0x3F03F0FF, 0x1F0000F8, + 0x3F0FC3F0, 0x003F0010, 0xF01F001F, 0xF00FBE03, 0xFBE03FCF, 0x0007C001, + 0x3E00003F, 0x003C0000, 0x00000F00, 0x00000000, + }, + { + 0x1F0F078F, 0xF807C1F0, 0xFC100FC0, 0x003E07E0, 0xE0000F80, 0xC0FC3E07, + 0xC007C007, 0xC1F03F00, 0x8001F00F, 0x87C3C00F, 0x1F83F0FF, 0x3F0000F8, + 0x3E0FC1F0, 0x001F0070, 0xF03F001F, 0xF00FBC01, 0xF3F01FC7, 0x0007C001, + 0x3E00001F, 0x00780000, 0x00000F00, 0x00000000, + }, + { + 0x1F0F8F0E, 0xF807C3E0, 0xFC1C1FC0, 0x003E07F0, 0xC0000F80, 0xC0FC3E1F, + 0xC007C007, 0x81F01F83, 0x8001F01F, 0x07C3C00F, 0x1FC7E0FF, 0x3E0000F8, + 0x7E0FC1F8, 0x001F81F0, 0xF87F001F, 0xE00FFC01, 0xE1F01F87, 0x8007C003, + 0x3E00000F, 0x00780000, 0x00000F00, 0x00000000, + }, + { + 0x1F0FFF1E, 0xFE07C3E0, 0xFC1FFF80, 0xFFFE03FF, 0xC0000F81, 0xC0FC3FFF, + 0xC1FFFE07, 0x81F01FFF, 0x8FFFF01F, 0x07C3C00F, 0x0FFFE0FF, 0x7E0000F8, + 0x7C0FC1FC, 0x001FFFF0, 0xFFFE001F, 0xE00FFC01, 0xE0F81F87, 0xC007C007, + 0x3E00FFFF, 0x00F00000, 0x00000F00, 0x00000000, + }, + { + 0x1F0FFE1E, 0xFFFFC3E0, 0xFC1FFF80, 0xFFFE03FF, 0x80000F81, 0xC0FC3FFF, + 0xC1FFFE07, 0x01F01FFF, 0x8FFFF03F, 0x07C3C00F, 0x0FFFC0FE, 0xFE0000F8, + 0xFC0FC0FF, 0x001FFFF0, 0xFFFE001F, 0xE007FC00, 0xC0FC1F87, 0xC007C007, + 0x3E00FFFF, 0x00F00000, 0x00000F00, 0x00000000, + }, + { + 0x0F8EF83C, 0x7FFFC3E0, 0xFC1FFF00, 0xFFFE01FF, 0x00000F81, 0xC0FC1FFF, + 0xC1FFFE07, 0x01F00FFF, 0x8FFFF03F, 0x07C3C00F, 0x07FF80FE, 0xFC0000F8, + 0xF80FC0FF, 0x000FFFF0, 0xFFFC001F, 0xE007F800, 0xC07C1F87, 0xC007C00F, + 0x3E00FFFF, 0x01E00000, 0x00000F00, 0x00000000, + }, + { + 0x0F80003C, 0x3FFFC7C0, 0xFC1FFC00, 0xFFFE007F, 0x00000F81, 0xC0FC0FFE, + 0x81FFFE07, 0x01F007FF, 0x8FFFF07E, 0x07C3C00F, 0x03FF00FE, 0xF80000F8, + 0xF80FC07F, 0x0007FFE1, 0x7FF8001F, 0xE007F800, 0x807E1F83, 0xC007C00F, + 0x3E00FFFF, 0x01E00000, 0x00000F00, 0x00000000, + }, + { + 0x0F800078, 0x07FFC7C0, 0xFC07F000, 0xFFFE000F, 0x00000F81, 0xC0FC03F8, + 0x01FFFE07, 0x01F001FC, 0x8FFFF07E, 0x07C3C00F, 0x00FC00FC, 0xF00000F8, + 0xF00FC03F, 0x0000FF01, 0x1FE0001F, 0xE007F800, 0x003E1F03, 0xC007C01F, + 0x3E00FFFF, 0x03C00000, 0x00000F00, 0x00000000, + }, + { + 0x000400F8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xC0000000, + 0x0000007F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x3E000000, 0x03C00000, 0x00000F00, 0x00000000, + }, + { + 0x000703F0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x000000FC, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x3E000000, 0x07800000, 0x00000F00, 0x00000000, + }, + { + 0x000FFFE0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x000001F8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFE000000, 0x07800003, 0x00000FF8, 0x00000000, + }, + { + 0x000FFF80, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x000000F0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFE000000, 0x07000003, 0x00000FF8, 0x00000000, + }, + { + 0x0001FC00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000020, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFE000000, 0x00000003, 0x00000FF8, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xFFFFFC00, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xFFFFFC00, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xFFFFFC00, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x000001F0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x000F8000, 0x000007C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x000003E0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x000F8000, 0x000007C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x000003C0, 0x000F8000, 0x00000000, 0x000007C0, 0x007F8000, 0x00F80000, + 0x000F8000, 0x03E007C0, 0x000FFC00, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xC0000000, 0x001E001F, 0x000000FE, 0x00000000, + }, + { + 0x00000780, 0x000F8000, 0x00000000, 0x000007C0, 0x007FE000, 0x00F80000, + 0x000F8000, 0x03E007C0, 0x000FFC00, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0x0000000F, 0x00000000, 0x00000000, 0x00000000, + 0xF0000000, 0x001E001F, 0x000003FE, 0x00000000, + }, + { + 0x00000F00, 0x000F8000, 0x00000000, 0x000007C0, 0x007FF000, 0x00F80000, + 0x000F8000, 0x03E007C0, 0x000FFC00, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0x0000000F, 0x00000000, 0x00000000, 0x00000000, + 0xF8000000, 0x001E001F, 0x000003FE, 0x00000000, + }, + { + 0x00000E00, 0x000F8000, 0x00000000, 0x000007C0, 0x007FF000, 0x00F80000, + 0x000F8000, 0x03E007C0, 0x000FFC00, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0x0000000F, 0x00000000, 0x00000000, 0x00000000, + 0xF8000000, 0x001E0000, 0x000007E0, 0x00000000, + }, + { + 0x00001E00, 0x000F8000, 0x00000000, 0x000007C0, 0x0001F000, 0x00F80000, + 0x00000000, 0x03E00000, 0x000F8000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0x0000000F, 0x00000000, 0x00000000, 0x00000000, + 0xF8000000, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0x00000000, 0x000F8000, 0x00000000, 0x000007C0, 0x0001F000, 0x00F80000, + 0x00000000, 0x03E00000, 0x000F8000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0x0000000F, 0x00000000, 0x00000000, 0x00000000, + 0x78000000, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0x00000000, 0x000F8000, 0x00000000, 0x000007C0, 0x0001F000, 0x00F80000, + 0x00000000, 0x03E00000, 0x000F8000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0x0000000F, 0x00000000, 0x00000000, 0x00000000, + 0x78000000, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0xF0000000, 0x0F8F801F, 0xC003F800, 0x0FC007C7, 0x007FFF80, 0xF8F81F3F, + 0x000FFC00, 0x03E007FE, 0x800F803F, 0x8F80F1E7, 0x00FC000F, 0xF000F8F8, + 0x7E3E01F1, 0xFC01FE00, 0xF83E07FF, 0x3CF807C1, 0xC0FCF800, 0x87E01F8F, + 0x78007FFF, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0xFC000000, 0x1FEF807F, 0xE00FFE00, 0x3FF007DF, 0x807FFF80, 0xFEF81F7F, + 0x000FFC01, 0x83E007FE, 0x800F801F, 0xEF81FBF7, 0x03FF001F, 0xFC01FEF8, + 0xFF3E01F7, 0xFC07FF80, 0xF83E07FF, 0x7CF807C1, 0xE0F87800, 0x83E01F07, + 0x78007FFF, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0xFC000000, 0x3FFF80FF, 0xF01FFF00, 0xFFFC07FF, 0xC07FFF80, 0xFFF81FFF, + 0x000FFC03, 0xC3E007FE, 0x800F800F, 0xFF83FFFF, 0x07FFC03F, 0xFC03FFF8, + 0xFFFE01FF, 0xFC07FFC0, 0xF83E07FF, 0x7CFC07C1, 0xE1F87800, 0x83F01F03, + 0x78007FFF, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0xFC000000, 0x7FFF81FF, 0xF81FFF80, 0xFFFC07FF, 0xE07FFF80, 0xFFF81FFF, + 0x000FFC03, 0xE3E007FE, 0x800F8007, 0xFF83FFFF, 0x0FFFC03F, 0xFE07FFF8, + 0xFFFE01FF, 0xFC07FFC0, 0xF83E07FF, 0x787C0FC1, 0xF3F07800, 0x81F03F03, + 0x7C007FFF, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0x0C000000, 0x7E3F81F8, 0xFC1C1FC0, 0xF87E07F1, 0xE001F001, 0xE3F81FC7, + 0x000F8007, 0xF3E007C0, 0x800F8003, 0x3F83EFCF, 0x1F87E07E, 0x7F07E3F8, + 0xC1FE01FC, 0x800607E0, 0xF83E000F, 0x787C0F81, 0xF3E07800, 0x01F03E01, + 0x7C007E00, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0x00000000, 0xFC1F81F0, 0xFC100FC0, 0xF03F07E0, 0xF001F003, 0xE1F81F83, + 0x000F8007, 0xFBE007C0, 0x800F8001, 0x1F83C78F, 0x1F03F07E, 0x3F0FC1F8, + 0x00FE01F8, 0x800003E0, 0xF83E000F, 0x787C0F81, 0xFFE07878, 0x01F83E00, + 0x7C003F00, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0x00000000, 0xFC0F81F0, 0x7C0007E0, 0xE01F07E0, 0xF001F003, 0xC0F81F81, + 0x000F8007, 0xFFE007C0, 0x800F8000, 0x0F83C78F, 0x3F01F07C, 0x1F0FC0F8, + 0x007E01F8, 0x800007E0, 0xF83E000F, 0x783E0F81, 0xFFC07C7C, 0x00F87C00, + 0x7C001F80, 0x001E0000, 0x3F000F80, 0x00000080, + }, + { + 0xF0000000, 0xF80F81FF, 0x7C0007E0, 0xE01F07C0, 0xF001F003, 0xC0F81F01, + 0x000F8007, 0x7FE007C0, 0x800F8000, 0x0F83C78F, 0x3F01F07C, 0x1F0F80F8, + 0x007E01F0, 0x80001FE0, 0xF83E000F, 0x783E1F01, 0x7F803C7C, 0x00F87C00, + 0x7E000FC0, 0x001E0000, 0xFFC01F80, 0x000000C1, + }, + { + 0xFC000000, 0xF80F81FF, 0x7C0003E0, 0xFFFF07C0, 0xF001F003, 0xC0F81F01, + 0x000F8007, 0xFFE007C0, 0x800F8000, 0x0F83C78F, 0x3E01F07C, 0x1F0F80F8, + 0x003E01F0, 0x8001FFC0, 0xF83E000F, 0xF83E1F01, 0x3F803CFC, 0x007C7C00, + 0x3FE007E0, 0x001E0000, 0xFFC1FF00, 0x000000FF, + }, + { + 0xFE000000, 0xF80F83FF, 0x7C0003E0, 0xFFFF07C0, 0xF001F003, 0xC0F81F01, + 0x000F8007, 0xFFE007C0, 0x800F8000, 0x0F83C78F, 0x3E01F07C, 0x1F0F80F8, + 0x003E01F0, 0x8007FFC0, 0xF83E000F, 0xF01F1F01, 0x3F003CFC, 0x007CF800, + 0x0FE003F0, 0x001E0000, 0xFFC1FE00, 0x000000FF, + }, + { + 0xFF000000, 0xF80F83FF, 0x7C0003E0, 0xFFFF07C0, 0xF001F003, 0xC0F81F01, + 0x000F8007, 0xFFE007C0, 0x800F8001, 0x0F83C78F, 0x3E01F07C, 0x1F0F80F8, + 0x003E01F0, 0x800FFF80, 0xF83E000F, 0xF01F1E01, 0x3F003CFC, 0x007CF800, + 0x3FE001F0, 0x001E0000, 0xE0C1FF00, 0x000000FF, + }, + { + 0x7F000000, 0xF80F83F0, 0x7C0003E0, 0xFFFF07C0, 0xF001F003, 0xC0F81F01, + 0x000F8007, 0xF7E007C0, 0x800F8003, 0x0F83C78F, 0x3E01F07C, 0x1F0F80F8, + 0x003E01F0, 0x800FFC00, 0xF83E000F, 0xF01F3E01, 0x7F803CEE, 0x003EF800, + 0x7E0001F8, 0x001E0000, 0x00001F80, 0x0000003F, + }, + { + 0x1F000000, 0xF80F83F0, 0x7C0007E0, 0x001F07C0, 0xF001F000, 0xC0F81F01, + 0x000F8007, 0xE3E007C0, 0x800F8003, 0x0F83C78F, 0x3F01F07C, 0x1F0F80F8, + 0x003E01F0, 0x801FC000, 0xF83E000F, 0xF00F3E01, 0xFFC01EEE, 0x003FF000, + 0x7C0000FC, 0x001E0000, 0x00000F80, 0x00000000, + }, + { + 0x1F000000, 0xFC0F83F0, 0x7C0007E0, 0x001F07E0, 0xF001F000, 0xC0F81F81, + 0x000F8007, 0xC3E007C0, 0x800F8007, 0x0F83C78F, 0x3F01F07C, 0x1F0FC0F8, + 0x003E01F8, 0x801F0000, 0xF83E000F, 0xF00FBC01, 0xFFE01FCE, 0x003FF000, + 0x7C00007E, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0x1F000000, 0xFC1F83F8, 0xFC100FC0, 0x003F07E0, 0xF001F000, 0xC0F81F83, + 0x000F8007, 0xC3E007C0, 0x800F800F, 0x0F83C78F, 0x1F03F07C, 0x3F0FC1F8, + 0x003E01F8, 0x801F0000, 0xF83E000F, 0xE00FFC01, 0xF3E01FCF, 0x001FE001, + 0x7C00003F, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0x3F000000, 0x7E3F83FC, 0xFC1C1FC0, 0x807E07F1, 0xE001F001, 0xC0F81FC7, + 0x000F8007, 0x83E007C0, 0x801F800F, 0x0F83C78F, 0x1F87E07C, 0x7F07E3F8, + 0x003E01FC, 0x801F80E0, 0xFC7E001F, 0xE007FC01, 0xF3F01FC7, 0x801FE003, + 0x7C00001F, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0xFF000000, 0x7FFF83FF, 0xF81FFF80, 0xFFFE07FF, 0xE001F001, 0xC0F81FFF, + 0x07FFFF07, 0x83E007C0, 0x87FF801F, 0x0F83C78F, 0x0FFFC07C, 0xFE07FFF8, + 0x003E01FF, 0x800FFFE0, 0xFFFE07FF, 0xE007F801, 0xE1F81FC7, 0x800FE003, + 0x78007FFF, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0xFE000000, 0x3FFF83FF, 0xF01FFF00, 0xFFFC07FF, 0xC001F001, 0xC0F81FFF, + 0x07FFFF07, 0x03E007C0, 0x87FF003F, 0x0F83C78F, 0x07FFC07C, 0xFC03FFF8, + 0x003E01FF, 0x000FFFE0, 0xFFFC07FF, 0xE007F801, 0xE0F81F87, 0x800FC007, + 0x78007FFF, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0xFC000000, 0x1FEF83F7, 0xF00FFE00, 0xFFF007DF, 0x8001F001, 0xC0F81F7F, + 0x07FFFF07, 0x03E007C0, 0x87FE003F, 0x0F83C78F, 0x03FF007C, 0xFC01FEF8, + 0x003E01F7, 0x0007FFE0, 0xFBF807FE, 0xE007F801, 0xC0FC0F87, 0x800FC00F, + 0x78007FFF, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0xF0000000, 0x0F8F83F1, 0xC003F800, 0x7FC007C7, 0x0001F000, 0xC0F81F3F, + 0x07FFFF07, 0x03E007C0, 0x87FC007E, 0x0F83C78F, 0x00FC007C, 0xF000F8F8, + 0x003E01F1, 0x0001FF00, 0xF9F007FC, 0xE003F801, 0xC07E0F87, 0x8007C00F, + 0x78007FFF, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00001F00, + 0x00000000, 0x000007C0, 0x00000000, 0x00000000, 0x00000000, 0x000000F8, + 0x000001F0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0007C000, + 0x78000000, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00001F00, + 0x00000000, 0x000007E0, 0x00000000, 0x00000000, 0x00000000, 0x000000F8, + 0x000001F0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0007C000, + 0xF8000000, 0x001E0000, 0x000007C0, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xC0000000, 0x00001FC0, + 0x00000000, 0x000007F0, 0x00000000, 0x00000000, 0x00000000, 0x000000F8, + 0x000001F0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0003E000, + 0xF8000000, 0x001E0000, 0x000007E0, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xC0000000, 0x00000FFF, + 0xC0000000, 0x000003FF, 0x00000000, 0x00000000, 0x00000000, 0x000000F8, + 0x000001F0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0003FF00, + 0xF8000000, 0x001E001F, 0x000003FE, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xC0000000, 0x00000FFF, + 0xC0000000, 0x000003FF, 0x00000000, 0x00000000, 0x00000000, 0x000000F8, + 0x000001F0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0001FF00, + 0xF0000000, 0x001E001F, 0x000003FE, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xC0000000, 0x000007FF, + 0xC0000000, 0x000001FF, 0x00000000, 0x00000000, 0x00000000, 0x000000F8, + 0x000001F0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000FF00, + 0xC0000000, 0x001E001F, 0x000000FE, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, + 0xC0000000, 0x0000007F, 0x00000000, 0x00000000, 0x00000000, 0x000000F8, + 0x000001F0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00007F00, + 0x00000000, 0x001E0000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x001E0000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x001E0000, 0x00000000, 0x00000000, + }, +}; + +constexpr uint32_t kFontImageMedium[kFontHeights[kFontLayerMedium]] + [kFontWidths[kFontLayerMedium] / 32] = { + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0xC0000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x80380000, + 0xC0738071, + 0x1F000F00, + 0x03800380, + 0x000C000C, + 0x00000000, + 0x30000000, + 0x807C01E0, + 0x8007E01F, + 0x3E01FF07, + 0x01F03FF8, + 0x0000007C, + 0x00000000, + 0x0FC00000, + }, + { + 0x80380000, + 0xC0338071, + 0x3F801F80, + 0x03800380, + 0x008C401C, + 0x00000000, + 0x38000000, + 0xC07F07F8, + 0x801FF07F, + 0xFF01FF07, + 0x07F83FF8, + 0x000001FE, + 0x00000000, + 0x1FE00000, + }, + { + 0x80380000, + 0xF0318071, + 0x3F801983, + 0x01C00380, + 0x00EDC038, + 0x00000000, + 0x18000000, + 0xC07F07F8, + 0xC01FF07F, + 0xFF81FF07, + 0x0FFC3FF8, + 0x000001FF, + 0x00000000, + 0x3FE00000, + }, + { + 0x80380000, + 0xF839C071, + 0x23C038C7, + 0x01C00380, + 0x007F8038, + 0x00000003, + 0x1C000000, + 0x40730F3C, + 0xE03C30F0, + 0xC3C00707, + 0x0F3C3C00, + 0x000003C7, + 0x00000000, + 0x3C200000, + }, + { + 0x80380000, + 0xFCFFF871, + 0x03801987, + 0x00E00380, + 0x003F0038, + 0x00000003, + 0x1C000000, + 0x00700E1C, + 0xE03800F0, + 0x01C00707, + 0x8E1C1C00, + 0x00000387, + 0x00100000, + 0x38000020, + }, + { + 0x80380000, + 0xDCFFF871, + 0x03841F84, + 0x00E00380, + 0x003F0070, + 0x00000003, + 0x0C000000, + 0x00700E1C, + 0x703800F0, + 0x01C00707, + 0x8E1C1C00, + 0x801E0383, + 0x001E0007, + 0x3C0001E0, + }, + { + 0x00380000, + 0xDCFFF800, + 0x07830F00, + 0x00E00000, + 0x007F8070, + 0x00000003, + 0x0E000000, + 0x00700E1E, + 0x301C00F0, + 0x3DC07F07, + 0x8F3C1E00, + 0x801E0387, + 0xFF9FC007, + 0x1E0007E7, + }, + { + 0x00380000, + 0xDC1CC000, + 0x0FC0C000, + 0x00E00000, + 0x00EDC070, + 0x00000003, + 0x06000000, + 0x00700EDE, + 0x381FC070, + 0x7FE1FF07, + 0x87F80E00, + 0x801E03C7, + 0xFF87F007, + 0x0F003F87, + }, + { + 0x00380000, + 0xFC1CE000, + 0x9FE03001, + 0x00F00003, + 0xF88C4070, + 0x0000007F, + 0x07000000, + 0x00700EDE, + 0x1C07C038, + 0xFFE1FF07, + 0x03F00F00, + 0x801E03FF, + 0xFF80FE07, + 0x0700FC07, + }, + { + 0x00300000, + 0xF80CE000, + 0x9CE00C07, + 0x00F00003, + 0xF80C0070, + 0xFE00007F, + 0x03000000, + 0x00700EDE, + 0x0C1FC01C, + 0xE3E3C107, + 0x07F80700, + 0x000003FF, + 0x00001E00, + 0x0381F000, + }, + { + 0x00300000, + 0xE07FFC00, + 0xBCE3C30F, + 0x00700001, + 0xF80000F0, + 0xFE00007F, + 0x03800000, + 0x00700E1E, + 0x0E3C000E, + 0xE1C38007, + 0x0E1C0701, + 0x000003BC, + 0x00001E00, + 0x0381E000, + }, + { + 0x00300000, + 0xC07FFC00, + 0xF8F7E08E, + 0x00F00001, + 0x00000070, + 0xFE000003, + 0x01800000, + 0x00700E1C, + 0xFE380007, + 0xE1C3801F, + 0x0E1C0781, + 0x00000380, + 0xFF80FE00, + 0x0380FC07, + }, + { + 0x00000000, + 0xC07FFC00, + 0xF0FE600E, + 0x00F00001, + 0x00000070, + 0x00000003, + 0x01C00000, + 0x80700E1C, + 0xFE380003, + 0xE1C3801F, + 0x0E1E0381, + 0x000003C0, + 0xFF87F000, + 0x03803F87, + }, + { + 0x00000000, + 0xCC067000, + 0xF1EC600E, + 0x00E00000, + 0x00000070, + 0x0001E003, + 0x00C01E00, + 0xC0700F3C, + 0xFE3C1801, + 0xE3C3C11F, + 0x0E1C03C0, + 0x801E01E1, + 0xFF9FC007, + 0x000007E7, + }, + { + 0x00380000, + 0xFC063000, + 0xFFEE600F, + 0x00E00001, + 0x00000070, + 0x0001E003, + 0x00E01E00, + 0xE7FF07F8, + 0x003FF8FF, + 0xFF81FF07, + 0x0FFC01C0, + 0x801E01FF, + 0x001E0007, + 0x038001E0, + }, + { + 0x00380000, + 0xFC073000, + 0xFFC7E007, + 0x00E00001, + 0x00000070, + 0x0001E003, + 0x00601E00, + 0xE7FF07F8, + 0x001FF8FF, + 0x7F81FF07, + 0x07F801C0, + 0x801E00FF, + 0x00100007, + 0x03800020, + }, + { + 0x00380000, + 0xF8073800, + 0xDF83C003, + 0x00E00003, + 0x00000038, + 0x0000E000, + 0x00701E00, + 0xE7FF01E0, + 0x000FE0FF, + 0x3E007E07, + 0x03F001E0, + 0x801E003E, + 0x00000003, + 0x03800000, + }, + { + 0x00000000, + 0xC0000000, + 0x00000000, + 0x01C00000, + 0x00000038, + 0x0000E000, + 0x00300000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x80000000, + 0x00000003, + 0x00000000, + }, + { + 0x00000000, + 0xC0000000, + 0x00000000, + 0x01C00000, + 0x00000038, + 0x00007000, + 0x00380000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xC0000000, + 0x00000001, + 0x00000000, + }, + { + 0x00000000, + 0xC0000000, + 0x00000000, + 0x03800000, + 0x0000001C, + 0x00007000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xC0000000, + 0x00000001, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x03800000, + 0x0000000C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0xE0780000, + 0xFC1F003F, + 0xFFC3FF01, + 0x0E1C1F81, + 0x787F03FF, + 0x87803878, + 0x07C1C1E7, + 0xE07C03FC, + 0xFE0FC03F, + 0xC0E7879F, + 0xDC0EE01D, + 0x81FFCF03, + 0x7E000E0F, + 0x00001E00, + }, + { + 0xE07C03E0, + 0xFC3FC07F, + 0xFFC3FF03, + 0x0E1C3FC1, + 0x787F03FF, + 0xC7803838, + 0x1FE1C1E7, + 0xE1FE0FFC, + 0xFE3FE07F, + 0xC0E7879F, + 0x9E1EE01D, + 0x81FFC783, + 0x7E000C0F, + 0x00003F00, + }, + { + 0xE0FC0FF8, + 0xFC3FE0FF, + 0xFFC3FF07, + 0x0E1C3FE1, + 0x787F03FF, + 0xCF80383C, + 0x3FF1C3E7, + 0xE3FF0FFC, + 0xFE3FF0FF, + 0xE1E7879F, + 0x8E1CE01D, + 0x81FFC787, + 0x70001C03, + 0x00003F80, + }, + { + 0xE0FC0E3C, + 0x1C31E0F1, + 0x01C0070F, + 0x0E1C31F0, + 0x78700078, + 0xCF80381E, + 0x3CF1C3E7, + 0xE3CF1E1C, + 0xE03870F1, + 0xE1E78781, + 0x073C601C, + 0x80F003C7, + 0x70001803, + 0x00007380, + }, + { + 0xE0FC1C0C, + 0x1C00F0E1, + 0x01C0070E, + 0x0E1C00F0, + 0x78700078, + 0xCF80380F, + 0x3879C7E7, + 0xE3879E1C, + 0xE00078E1, + 0xE1C78781, + 0x07B86398, + 0x80F003CF, + 0x70003803, + 0x0000E1C0, + }, + { + 0xE0EE180E, + 0x1C00F0E1, + 0x01C0071E, + 0x0E1C0070, + 0x78700078, + 0xEF803807, + 0x7879C7E7, + 0xE7879E1C, + 0xE00070E1, + 0xE1C78781, + 0x03F07798, + 0x807801CE, + 0x70003003, + 0x0001C0E0, + }, + { + 0xE1CE1BC6, + 0x1C0070F1, + 0x01C0071E, + 0x0E1C0078, + 0xF8700078, + 0x7B803807, + 0x7879C6E7, + 0xE7879E1C, + 0xE000F0F1, + 0xF1C78781, + 0x03F077B8, + 0x803C01FE, + 0x70007003, + 0x00000000, + }, + { + 0xE1CE1FE7, + 0x1C00707F, + 0xFFC3FF1E, + 0x0FFC0078, + 0xF8700078, + 0x7B803807, + 0x7879CEE7, + 0xE7878FFC, + 0xE007F07F, + 0x73C78781, + 0x01E077B8, + 0x803C00FC, + 0x70006003, + 0x00000000, + }, + { + 0xE1CE1CE3, + 0x1C00703F, + 0xFFC3FF1E, + 0x0FFC7C78, + 0xF8700078, + 0x7B803807, + 0x7879CCE7, + 0xE7878FFC, + 0xE01FC03F, + 0x73878781, + 0x01E077B8, + 0x801E00FC, + 0x7000E003, + 0x00000000, + }, + { + 0xE3C71873, + 0x1C0070FF, + 0xFFC3FF1E, + 0x0FFC7C78, + 0xF8700078, + 0x7B80380F, + 0x7879DCE7, + 0xE78783FC, + 0xE03F003F, + 0x73878781, + 0x01E077B8, + 0x800F0078, + 0x7000C003, + 0x00000000, + }, + { + 0xE3FF1873, + 0x1C0071E1, + 0x01C0071E, + 0x0E1C7C78, + 0x78700078, + 0x3B80380E, + 0x7879DCE7, + 0xE787801C, + 0xE03C0079, + 0x73878781, + 0x03F07EF8, + 0x800F0078, + 0x7001C003, + 0x00000000, + }, + { + 0xE3FF1873, + 0x1C00F1C1, + 0x01C0071E, + 0x0E1C7070, + 0x78700078, + 0x0380381E, + 0x7879F8E7, + 0xE787801C, + 0xE0380071, + 0x7B878781, + 0x03F87CF8, + 0x80078078, + 0x70018003, + 0x00000000, + }, + { + 0xE3FF1CE7, + 0x1C00F1C1, + 0x01C0070E, + 0x0E1C70F0, + 0x78702078, + 0x0380381C, + 0x3879F8E7, + 0xE387801C, + 0xE03800F1, + 0x3F078781, + 0x07383CF8, + 0x8003C078, + 0x70038003, + 0x00000000, + }, + { + 0xE7879FE7, + 0x1C31E1E1, + 0x01C0070F, + 0x0E1C71F0, + 0x78786078, + 0x0380383C, + 0x3CF1F0E7, + 0xE3CF001C, + 0xE03C38E1, + 0x3F03C701, + 0x0F3C3CF0, + 0x8001C078, + 0x70038003, + 0x00000000, + }, + { + 0xE7839FC6, + 0xFC3FE1FF, + 0x01C3FF07, + 0x0E1C7FE0, + 0x787FE3FF, + 0x039FF838, + 0x3FF1F0E7, + 0xE3FF001C, + 0xE03FF9E1, + 0x3F03FF01, + 0x0E1C3CF0, + 0x81FFE078, + 0x70070003, + 0x00000000, + }, + { + 0xE703800E, + 0xFC3FC0FF, + 0x01C3FF03, + 0x0E1C3FC0, + 0x783FE3FF, + 0x039FF878, + 0x1FE1F0E7, + 0xE1FE001C, + 0xE01FF9C1, + 0x3F01FE01, + 0x1E1E3C70, + 0x81FFE078, + 0x70070003, + 0x00000000, + }, + { + 0xE703C01C, + 0xFC1F003F, + 0x01C3FF01, + 0x0E1C1F80, + 0x781F83FF, + 0x039FF8F0, + 0x07C1E0E7, + 0xE0FC001C, + 0xE00FE3C1, + 0x1F00FC01, + 0x1C0E3870, + 0x81FFE078, + 0x70060003, + 0x00000000, + }, + { + 0x0000083C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x01C00000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x80000000, + 0x700E0003, + 0x00000000, + }, + { + 0x00001FF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x03800000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x80000000, + 0x700C0003, + 0x00000000, + }, + { + 0x00000FC0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x01800000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x80000000, + 0x7E00000F, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x80000000, + 0x7E00000F, + 0xFFFC0000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xFFFC0000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x003C0070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000038, + 0x00000000, + 0x00000000, + 0x00000000, + 0x003C0070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0xC0000070, + 0x00000001, + 0xFC00000E, + 0x001C0000, + 0x703C0070, + 0x0000FE00, + 0x00000000, + 0x00000000, + 0xF0000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x1F00C03E, + 0x00000000, + }, + { + 0xC0000060, + 0x00000001, + 0xFE00000E, + 0x001C0000, + 0x703C0070, + 0x0000FE00, + 0x00000000, + 0x00000000, + 0xF0000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x3F00C03F, + 0x00000000, + }, + { + 0xC00000C0, + 0x00000001, + 0xFE00000E, + 0x001C0000, + 0x70000000, + 0x0000FE00, + 0x00000000, + 0x00000000, + 0xF0000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x3800C007, + 0x00000000, + }, + { + 0xC0000000, + 0x00000001, + 0x0E00000E, + 0x001C0000, + 0x70000000, + 0x0000F000, + 0x00000000, + 0x00000000, + 0xF0000000, + 0x00000000, + 0x00000000, + 0x80000000, + 0x3800C007, + 0x00000000, + }, + { + 0xC0FC0000, + 0x701F8039, + 0xFFC0FC0E, + 0x039C3BC0, + 0x703F807F, + 0x9D80F078, + 0x07C039C3, + 0x839C039C, + 0xFE0FC0F7, + 0xE0E3870F, + 0x9E1EE01D, + 0x80FFC703, + 0x3800C007, + 0x00000000, + }, + { + 0xC1FF0000, + 0xFC3FC07F, + 0xFFC1FE0E, + 0x07FC3FE0, + 0x703F807F, + 0xFF80F03C, + 0x1FE07FC3, + 0x83BF07FC, + 0xFE1FE1FF, + 0xE1E3870F, + 0x8F3CE01D, + 0x80FFC787, + 0x3800C007, + 0x00000000, + }, + { + 0xC3FF0000, + 0xFC3FE0FF, + 0xFFC3FF0F, + 0x0FFC3FF0, + 0x703F807F, + 0xFF80F01E, + 0x3FF0FFC7, + 0x83FF0FFC, + 0xFE1FF1FF, + 0xE1C3870F, + 0x0738601C, + 0x80FFC387, + 0x3800C007, + 0x00000000, + }, + { + 0xC3830000, + 0x1E21F0F3, + 0x0E03870F, + 0x0F3C3CF0, + 0x703C0070, + 0x7B80F00F, + 0x3CF0F3C7, + 0x83C78F3C, + 0xF010710F, + 0xE1C38700, + 0x03F86398, + 0x80700387, + 0x3800C003, + 0x000107C0, + }, + { + 0xC3800000, + 0x1E00F1E1, + 0x0E07878F, + 0x0E1C3878, + 0xF03C0070, + 0x3380F007, + 0x7878E1C7, + 0x83C79E1C, + 0xF0007007, + 0xF1C38700, + 0x03F07798, + 0x803803CF, + 0x7800C003, + 0x0001FFE0, + }, + { + 0xC3FE0000, + 0x0E0071E1, + 0x0E07FF8E, + 0x0E1C3878, + 0xF03C0070, + 0x3380F007, + 0x7878E1C7, + 0x83839E1C, + 0xF003F007, + 0x73838700, + 0x01E077B8, + 0xC03C01CE, + 0x7000C003, + 0x0001FFE0, + }, + { + 0xC3FF0000, + 0x0E0071E1, + 0x0E07FF8E, + 0x0E1C3838, + 0xF03C0070, + 0x3380F007, + 0x7838E1C7, + 0x83839E1C, + 0xF01FE007, + 0x73838700, + 0x01E077B8, + 0xF01E01CE, + 0xE000C001, + 0x0000F823, + }, + { + 0xC3FF8000, + 0x0E0071E1, + 0x0E07FF8E, + 0x0E1C3878, + 0xF03C0070, + 0x3380F00E, + 0x7878E1C7, + 0x83839E1C, + 0xF03F0007, + 0x73838700, + 0x03F077B8, + 0xF00F00FE, + 0xF000C001, + 0x00000003, + }, + { + 0xC3878000, + 0x1E00F1E1, + 0x0E00078F, + 0x0E1C3878, + 0x703C0070, + 0x3380F01E, + 0x7878E1C7, + 0x83C79E1C, + 0xF0380007, + 0x3F83C700, + 0x03F03EF8, + 0x800700FC, + 0x7000C003, + 0x00000000, + }, + { + 0xC3C78000, + 0x1E21F0F3, + 0x0E02070F, + 0x0E1C3CF8, + 0x703C0070, + 0x3380F01C, + 0x3CF0E1C7, + 0x83C78F3C, + 0xF03C3007, + 0x3F03CF00, + 0x07B83CF0, + 0x800380FC, + 0x7800C003, + 0x00000000, + }, + { + 0xC3FF8000, + 0xFC3FE0FF, + 0x0E03FF0F, + 0x0E1C3FF0, + 0x703C07FF, + 0x338FE03C, + 0x3FF0E1C7, + 0x83FF0FFC, + 0xE03FF007, + 0x3F03FF0F, + 0x0F3C3CF0, + 0x80FFC078, + 0x3800C007, + 0x00000000, + }, + { + 0xC3FF0000, + 0xFC3FC07F, + 0x0E03FE0E, + 0x0E1C3FE0, + 0x703C07FF, + 0x338FE078, + 0x1FE0E1C7, + 0x83BF07FC, + 0xE01FF007, + 0x1F03FE0F, + 0x0E1C3CF0, + 0x80FFC078, + 0x3800C007, + 0x00000000, + }, + { + 0xC39E0000, + 0x701F8039, + 0x0E01F80E, + 0x0E1C3BC0, + 0x703C07FF, + 0x338FC070, + 0x07C0E1C7, + 0x839C039C, + 0xC00FC007, + 0x1E039C0F, + 0x1E1E3CF0, + 0x80FFC078, + 0x3800C007, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00003800, + 0x003C0000, + 0x00000000, + 0x00000000, + 0x0380001C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x80000038, + 0x3800C007, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00003C30, + 0x001C0000, + 0x00000000, + 0x00000000, + 0x0380001C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000003C, + 0x3800C007, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00003FF0, + 0x001FC000, + 0x00000000, + 0x00000000, + 0x0380001C, + 0x00000000, + 0x00000000, + 0x80000000, + 0x0000001F, + 0x3F00C03F, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00001FF0, + 0x001FC000, + 0x00000000, + 0x00000000, + 0x0380001C, + 0x00000000, + 0x00000000, + 0x80000000, + 0x0000001F, + 0x1F00C03E, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000FC0, + 0x000FC000, + 0x00000000, + 0x00000000, + 0x0380001C, + 0x00000000, + 0x00000000, + 0x80000000, + 0x0000000F, + 0x0000C000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000C000, + 0x00000000, + }, +}; + +constexpr uint32_t kFontImageSmall[kFontHeights[kFontLayerSmall]] + [kFontWidths[kFontLayerSmall] / 32] = { + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000010, + 0x00000C30, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0xD8641800, + 0x183C0E10, + 0x00101830, + 0x40000000, + 0x3C3C3C3C, + 0x7E387E70, + 0x00003C3C, + 0x3C000000, + }, + { + 0x58641800, + 0x180C0B7C, + 0x18521818, + 0x60000000, + 0x62623E6C, + 0x604C0678, + 0x00006666, + 0x60000000, + }, + { + 0x48641800, + 0x180C0B56, + 0x183C1018, + 0x60000000, + 0x60603066, + 0x60060678, + 0x00006666, + 0x6002FEC0, + }, + { + 0xFE641800, + 0x180C8E16, + 0x183C3018, + 0x20000000, + 0x606030E6, + 0x703E3E6C, + 0x18186666, + 0x701EFEF0, + }, + { + 0x6C001800, + 0x001E201E, + 0xFF523018, + 0x30000000, + 0x387030D6, + 0x306E6266, + 0x1818E63C, + 0x3878001E, + }, + { + 0x24001800, + 0x009E0C78, + 0xFF103018, + 0x10003C00, + 0x603030D6, + 0x38C66066, + 0x1818E666, + 0x18E00006, + }, + { + 0xFF001800, + 0x00B3E270, + 0x18003018, + 0x18003C00, + 0x601830E6, + 0x18C660FE, + 0x00007CC6, + 0x1878FE1E, + }, + { + 0x36000000, + 0x00F39050, + 0x18001018, + 0x08180018, + 0x600C3066, + 0x18C66060, + 0x18186046, + 0x001EFEF0, + }, + { + 0x36001800, + 0x00E69076, + 0x18001818, + 0x0C180018, + 0x6206306C, + 0x1C6C6260, + 0x18186066, + 0x180200C0, + }, + { + 0x12001800, + 0x00FCE03C, + 0x00001830, + 0x04180018, + 0x3C7EFE3C, + 0x0C3C3C60, + 0x18183C3C, + 0x18000000, + }, + { + 0x00000000, + 0x00000010, + 0x00000C30, + 0x06000008, + 0x00000000, + 0x00000000, + 0x08000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000010, + 0x00000000, + 0x06000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x38000000, + 0x00003C00, + }, + { + 0x783E3838, + 0x78FEFE3E, + 0xC67C7EE6, + 0x3CC6E60C, + 0x3C3E3C7E, + 0x83C7C6FE, + 0x18FEC7C6, + 0x00183006, + }, + { + 0x0C663846, + 0x0C060666, + 0x666018E6, + 0x66CEE60C, + 0x46666666, + 0x83C6C618, + 0x18E0E666, + 0x003C3006, + }, + { + 0x0EC63CC2, + 0x06060666, + 0x366018E6, + 0x66CEEE0C, + 0x066666C6, + 0xC366C618, + 0x1870666C, + 0x006E3004, + }, + { + 0x06662CF3, + 0x060606C6, + 0x1E6018E6, + 0xC6CEFE0C, + 0x0E66C6C6, + 0xDB66C618, + 0x18707C3C, + 0x00C6300C, + }, + { + 0x063E6CDB, + 0x067E7EC6, + 0x1E6018FE, + 0xC6DEDA0C, + 0x3E66C666, + 0xDA66C618, + 0x18383C38, + 0x00003008, + }, + { + 0x06666689, + 0xE60606C6, + 0x3E6018E6, + 0xC6D6DA0C, + 0x783EC67E, + 0xFA6CC618, + 0x181C3838, + 0x00003018, + }, + { + 0x06C67E89, + 0xC60606C6, + 0x366018E6, + 0xC6F6C20C, + 0xE076C606, + 0xEE2CC618, + 0x181C183C, + 0x00003010, + }, + { + 0x0EC6C6DB, + 0xC6060666, + 0x666018E6, + 0x66F6C20C, + 0xE066E606, + 0xEE3CC618, + 0x180E186C, + 0x00003030, + }, + { + 0x0CE6C6F3, + 0xCC060666, + 0xE67218E6, + 0x66E6C20C, + 0x62E66606, + 0x663C6618, + 0x18061866, + 0x00003020, + }, + { + 0x787EC302, + 0x7806FE3E, + 0xC63C7EE6, + 0x3CE6C2FC, + 0x3CC63C06, + 0x66383C18, + 0x18FE18C7, + 0x00003060, + }, + { + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00006000, + 0x00000000, + 0x38000000, + 0x00003C60, + }, + { + 0x00000078, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00004000, + 0x00000000, + 0x00000000, + 0x00000040, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xFF000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x0000000C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + { + 0x00060008, + 0x00700060, + 0x03301806, + 0x0000001E, + 0x00000000, + 0x00000000, + 0x70000000, + 0x00000E18, + }, + { + 0x00060018, + 0x00180060, + 0x03301806, + 0x00000018, + 0x00000000, + 0x00000018, + 0x18000000, + 0x00001818, + }, + { + 0x00060000, + 0x00180060, + 0x03000006, + 0x00000018, + 0x00000000, + 0x00000018, + 0x18000000, + 0x00001818, + }, + { + 0x787E3C00, + 0xFC7E3C7C, + 0x733C1E7E, + 0x3C7E7E18, + 0x3CFC7C7E, + 0x83C6667E, + 0x187EC6E6, + 0x00001818, + }, + { + 0x0C6E6200, + 0xE6186666, + 0x3B30186E, + 0x666EDA18, + 0x469C666E, + 0x83666618, + 0x1860E66C, + 0x00001818, + }, + { + 0x06C6C000, + 0xE618C666, + 0x1F301866, + 0xC666DA18, + 0x060C66C6, + 0xDB666618, + 0x1870663C, + 0x008E3818, + }, + { + 0x06C6FC00, + 0xE618FE66, + 0x0F301866, + 0xC666DA18, + 0x3E0C66C6, + 0xDA6C6618, + 0x0E386C38, + 0x00FE7018, + }, + { + 0x06C6C600, + 0xE6180666, + 0x1F301866, + 0xC666DA18, + 0x780C66C6, + 0xFA6C6618, + 0x181C7C38, + 0x00703818, + }, + { + 0x06C6E600, + 0xE6180666, + 0x33301866, + 0xC666DA18, + 0x600C66C6, + 0x6E3C6618, + 0x181C3C3C, + 0x00001818, + }, + { + 0x0C6EE600, + 0xE6180E66, + 0x33301866, + 0x6666DA18, + 0x620C666E, + 0x6E3C6618, + 0x180E386E, + 0x00001818, + }, + { + 0x787EFC00, + 0xFC187C7C, + 0x6330FE66, + 0x3C66DAF0, + 0x3C0C7C7E, + 0x66387C78, + 0x187E38E6, + 0x00001818, + }, + { + 0x00000000, + 0x60000000, + 0x00300000, + 0x00000000, + 0x00006006, + 0x00000000, + 0x18001800, + 0x00001818, + }, + { + 0x00000000, + 0x60000000, + 0x00380000, + 0x00000000, + 0x00006006, + 0x00000000, + 0x70001800, + 0x00000E18, + }, + { + 0x00000000, + 0x3C000000, + 0x001E0000, + 0x00000000, + 0x00006006, + 0x00000000, + 0x00000E00, + 0x00000018, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, +}; + +// Returns a bit with the value of the pixel. +template +uint32_t GetFontLayerPixel(const uint32_t fontImage[kFontHeight][kFontWidth / 32], int x, int y) +{ + ASSERT(x >= 0 && x < kFontWidth && y >= 0 && y < kFontHeight); + return fontImage[y][x / 32] >> (x % 32) & 1; +} + +inline uint32_t GetFontPixel(int layer, int x, int y) +{ + switch (layer) + { + case kFontLayerLarge: + return GetFontLayerPixel( + kFontImageLarge, x, y); + case kFontLayerMedium: + return GetFontLayerPixel( + kFontImageMedium, x, y); + case kFontLayerSmall: + return GetFontLayerPixel( + kFontImageSmall, x, y); + + default: + UNREACHABLE(); + return 0; + } +} + +} // anonymous namespace + +void OverlayState::initFontData(uint8_t *fontData) const +{ + constexpr int kFontDataLayerSize = kFontImageWidth * kFontImageHeight; + + // Unpack the font bitmap into R8_UNORM format. Border pixels are given a 0.5 value for better + // font visibility. + for (int layer = 0; layer < kFontCount; ++layer) + { + memset(fontData, 0, kFontDataLayerSize); + for (int y = 0; y < kFontHeights[layer]; ++y) + { + for (int x = 0; x < kFontWidths[layer]; ++x) + { + uint32_t src = GetFontPixel(layer, x, y); + uint8_t dstValue = src ? 255 : 0; + fontData[y * kFontImageWidth + x] = dstValue; + } + } + fontData += kFontDataLayerSize; + } +} +#else +void OverlayState::initFontData(uint8_t *fontData) const +{ + memset(fontData, 0, kFontCount * kFontImageWidth * kFontImageHeight * sizeof(*fontData)); +} +#endif +} // namespace gl diff --git a/src/libANGLE/Overlay_font_autogen.h b/src/libANGLE/Overlay_font_autogen.h new file mode 100644 index 00000000000..20f9d9348ea --- /dev/null +++ b/src/libANGLE/Overlay_font_autogen.h @@ -0,0 +1,29 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_overlay_fonts.py using overlay/DejaVuSansMono-Bold.ttf. +// +// 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. +// +// Overlay_font_autogen.h: +// Autogenerated overlay font data. + +#include "libANGLE/Overlay.h" + +namespace gl +{ +namespace overlay +{ +constexpr int kFontCount = 3; +constexpr int kFontGlyphWidths[kFontCount] = {22, 14, 8}; +constexpr int kFontGlyphHeights[kFontCount] = {43, 28, 17}; +constexpr int kFontCharactersPerRow = 32; +constexpr int kFontCharactersPerCol = 3; +constexpr int kFontCharacters = kFontCharactersPerRow * kFontCharactersPerCol; +constexpr int kFontImageWidth = 22 * kFontCharactersPerRow; +constexpr int kFontImageHeight = 43 * kFontCharactersPerCol; +constexpr int kFontLayerLarge = 0; +constexpr int kFontLayerMedium = 1; +constexpr int kFontLayerSmall = 2; +} // namespace overlay +} // namespace gl diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp index 99b122dc614..51b88124dc3 100644 --- a/src/libANGLE/State.cpp +++ b/src/libANGLE/State.cpp @@ -236,6 +236,7 @@ const angle::PackedEnumMap State::kBu State::State(ContextID contextIn, const State *shareContextState, TextureManager *shareTextures, + const OverlayType *overlay, const EGLenum clientType, const Version &clientVersion, bool debug, @@ -299,7 +300,8 @@ State::State(ContextID contextIn, mFramebufferSRGB(true), mRobustResourceInit(robustResourceInit), mProgramBinaryCacheEnabled(programBinaryCacheEnabled), - mMaxShaderCompilerThreads(std::numeric_limits::max()) + mMaxShaderCompilerThreads(std::numeric_limits::max()), + mOverlay(overlay) {} State::~State() {} diff --git a/src/libANGLE/State.h b/src/libANGLE/State.h index 8927f257064..8050de2a1e2 100644 --- a/src/libANGLE/State.h +++ b/src/libANGLE/State.h @@ -17,6 +17,7 @@ #include "common/bitset_utils.h" #include "libANGLE/Debug.h" #include "libANGLE/GLES1State.h" +#include "libANGLE/Overlay.h" #include "libANGLE/Program.h" #include "libANGLE/ProgramPipeline.h" #include "libANGLE/RefCountObject.h" @@ -58,6 +59,7 @@ class State : angle::NonCopyable State(ContextID contextIn, const State *shareContextState, TextureManager *shareTextures, + const OverlayType *overlay, const EGLenum clientType, const Version &clientVersion, bool debug, @@ -678,6 +680,8 @@ class State : angle::NonCopyable mProvokingVertex = val; } + const OverlayType *getOverlay() const { return mOverlay; } + private: friend class Context; @@ -891,6 +895,9 @@ class State : angle::NonCopyable ActiveTextureMask mDirtyTextures; ActiveTextureMask mDirtySamplers; ImageUnitMask mDirtyImages; + + // The Overlay object, used by the backend to render the overlay. + const OverlayType *mOverlay; }; ANGLE_INLINE angle::Result State::syncDirtyObjects(const Context *context, diff --git a/src/libANGLE/Surface.cpp b/src/libANGLE/Surface.cpp index 106fa2615c6..ad13509cd4b 100644 --- a/src/libANGLE/Surface.cpp +++ b/src/libANGLE/Surface.cpp @@ -235,6 +235,8 @@ Error Surface::swap(const gl::Context *context) { ANGLE_TRACE_EVENT0("gpu.angle", "egl::Surface::swap"); + context->getState().getOverlay()->onSwap(); + ANGLE_TRY(mImplementation->swap(context)); postSwap(context); return NoError(); @@ -242,6 +244,8 @@ Error Surface::swap(const gl::Context *context) Error Surface::swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects) { + context->getState().getOverlay()->onSwap(); + ANGLE_TRY(mImplementation->swapWithDamage(context, rects, n_rects)); postSwap(context); return NoError(); @@ -258,6 +262,8 @@ Error Surface::postSubBuffer(const gl::Context *context, return egl::NoError(); } + context->getState().getOverlay()->onSwap(); + ANGLE_TRY(mImplementation->postSubBuffer(context, x, y, width, height)); postSwap(context); return NoError(); diff --git a/src/libANGLE/gen_overlay_fonts.py b/src/libANGLE/gen_overlay_fonts.py new file mode 100644 index 00000000000..243d7e8f38d --- /dev/null +++ b/src/libANGLE/gen_overlay_fonts.py @@ -0,0 +1,291 @@ +#!/usr/bin/env vpython +# +# [VPYTHON:BEGIN] +# wheel: < +# name: "infra/python/wheels/freetype-py/${vpython_platform}" +# version: "version:2.1.0.post1" +# > +# [VPYTHON:END] + +# 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. +# +# gen_vk_overlay_fonts.py: +# Code generation for overlay fonts. Should be run if the font file under overlay/ is changed, +# or the font sizes declared in this file are modified. The font is assumed to be monospace. +# The output will contain ASCII characters in order from ' ' to '~'. The output will be images +# with 3 rows of 32 characters each. +# NOTE: don't run this script directly. Run scripts/run_code_generation.py. + +from datetime import date +import sys + +if len(sys.argv) < 2: + from freetype import * + +out_file_cpp = 'Overlay_font_autogen.cpp' +out_file_h = 'Overlay_font_autogen.h' +font_file = 'overlay/DejaVuSansMono-Bold.ttf' + +template_out_file_h = u"""// GENERATED FILE - DO NOT EDIT. +// Generated by {script_name} using {font_file}. +// +// Copyright {copyright_year} 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. +// +// {out_file_name}: +// Autogenerated overlay font data. + +#include "libANGLE/Overlay.h" + +namespace gl +{{ +namespace overlay +{{ +constexpr int kFontCount = {font_count}; +constexpr int kFontGlyphWidths[kFontCount] = {{ {font_glyph_widths} }}; +constexpr int kFontGlyphHeights[kFontCount] = {{ {font_glyph_heights} }}; +constexpr int kFontCharactersPerRow = 32; +constexpr int kFontCharactersPerCol = 3; +constexpr int kFontCharacters = kFontCharactersPerRow * kFontCharactersPerCol; +constexpr int kFontImageWidth = {max_font_width} * kFontCharactersPerRow; +constexpr int kFontImageHeight = {max_font_height} * kFontCharactersPerCol; +{font_layers} +}} // namespace overlay +}} // namespace gl + +""" + +template_out_file_cpp = u"""// GENERATED FILE - DO NOT EDIT. +// Generated by {script_name} using images from {font_file}. +// +// Copyright {copyright_year} 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. +// +// {out_file_name}: +// Autogenerated overlay font data. + +#include "libANGLE/Overlay.h" +#include "libANGLE/Overlay_font_autogen.h" + +#include + +namespace gl +{{ +using namespace overlay; + +// Save binary size if the font images are never to be used. +#if ANGLE_ENABLE_OVERLAY +namespace +{{ +constexpr int kFontWidths[kFontCount] = {{ {font_layer_widths} }}; +constexpr int kFontHeights[kFontCount] = {{ {font_layer_heights} }}; + +{font_data} + +// Returns a bit with the value of the pixel. +template +uint32_t GetFontLayerPixel(const uint32_t fontImage[kFontHeight][kFontWidth / 32], int x, int y) +{{ + ASSERT(x >= 0 && x < kFontWidth && y >= 0 && y < kFontHeight); + return fontImage[y][x / 32] >> (x % 32) & 1; +}} + +inline uint32_t GetFontPixel(int layer, int x, int y) +{{ + switch (layer) + {{ + {get_font_layer_pixel} + default: + UNREACHABLE(); + return 0; + }} +}} + +}} // anonymous namespace + +void OverlayState::initFontData(uint8_t *fontData) const +{{ + constexpr int kFontDataLayerSize = kFontImageWidth * kFontImageHeight; + + // Unpack the font bitmap into R8_UNORM format. Border pixels are given a 0.5 value for better + // font visibility. + for (int layer = 0; layer < kFontCount; ++layer) + {{ + memset(fontData, 0, kFontDataLayerSize); + for (int y = 0; y < kFontHeights[layer]; ++y) + {{ + for (int x = 0; x < kFontWidths[layer]; ++x) + {{ + uint32_t src = GetFontPixel(layer, x, y); + uint8_t dstValue = src ? 255 : 0; + fontData[y * kFontImageWidth + x] = dstValue; + }} + }} + fontData += kFontDataLayerSize; + }} +}} +#else +void OverlayState::initFontData(uint8_t *fontData) const +{{ + memset(fontData, 0, kFontCount * kFontImageWidth * kFontImageHeight * sizeof(*fontData)); +}} +#endif +}} // namespace gl +""" + +template_get_font_layer_pixel = u"""case {layer}: + return GetFontLayerPixel({font_image}, x, y); +""" + + +def main(): + if len(sys.argv) == 2 and sys.argv[1] == 'inputs': + print(font_file) + return + if len(sys.argv) == 2 and sys.argv[1] == 'outputs': + print(','.join([out_file_cpp, out_file_h])) + return + + font_defs = [('large', 36), ('medium', 23), ('small', 14)] + chars = ' !"#$%&\'()*+,-./0123456789:;<=>?' + \ + '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' + \ + '`abcdefghijklmnopqrstuvwxyz{|}~ ' + output_rows = 3 + output_cols = 32 + assert (len(chars) == output_rows * output_cols) + + font_glyph_widths = [] + font_glyph_heights = [] + font_layers = [] + font_data = [] + get_font_layer_pixel = [] + current_font_layer = 0 + + # Load the font file. + face = Face(font_file) + assert (face.is_fixed_width) + + for font_name, font_size in font_defs: + + # Since the font is fixed width, we can retrieve its size right away. + face.set_char_size(font_size << 6) + glyph_width = face.size.max_advance >> 6 + glyph_ascender = face.size.ascender >> 6 + glyph_descender = face.size.descender >> 6 + glyph_height = glyph_ascender - glyph_descender + + font_tag = font_name.capitalize() + font_layer = str(current_font_layer) + font_layer_symbol = 'kFontLayer' + font_tag + font_array_name = 'kFontImage' + font_tag + font_width = 'kFontWidths[' + font_layer_symbol + ']' + font_height = 'kFontHeights[' + font_layer_symbol + ']' + + # Font pixels are packed in 32-bit values. + font_array_width = output_cols * glyph_width / 32 + font_array_height = output_rows * glyph_height + font_array = [[0] * font_array_width for i in range(font_array_height)] + + for charIndex in range(len(chars)): + char = chars[charIndex] + base_x = (charIndex % output_cols) * glyph_width + base_y = (charIndex / output_cols) * glyph_height + + # Render the character. + face.load_char(char) + bitmap = face.glyph.bitmap + left = face.glyph.bitmap_left + top = face.glyph.bitmap_top + width = bitmap.width + rows = bitmap.rows + pitch = bitmap.pitch + + offset_x = left + offset_y = glyph_height - (top - glyph_descender) + + # '#' in the smallest font generates a larger glyph than the "fixed" font width. + if offset_x + width > glyph_width: + offset_x = glyph_width - width + if offset_x < 0: + width += offset_x + offset_x = 0 + + base_x += offset_x + base_y += offset_y + + assert (offset_x + width <= glyph_width) + assert (offset_y + rows <= glyph_height) + + # Write the character bitmap in the font image. + for y in range(rows): + for x in range(width): + pixel_value = bitmap.buffer[y * pitch + x] + output_bit = 1 if pixel_value >= 122 else 0 + + font_array_row = base_y + y + font_array_col = (base_x + x) / 32 + font_array_bit = (base_x + x) % 32 + font_array[font_array_row][font_array_col] |= output_bit << font_array_bit + + # Output the image to a C array. + data = 'constexpr uint32_t ' + font_array_name + '[' + font_height + '][' + font_width + '/32] = {\n' + for y in range(font_array_height): + data += '{' + for x in range(font_array_width): + data += '0x{:08X}, '.format(font_array[y][x]) + data += '},\n' + data += '};\n' + + font_glyph_widths.append(glyph_width) + font_glyph_heights.append(glyph_height) + font_layers.append('constexpr int ' + font_layer_symbol + ' = ' + font_layer + ';') + font_data.append(data) + get_font_layer_pixel.append( + template_get_font_layer_pixel.format( + layer=font_layer_symbol, font_image=font_array_name)) + current_font_layer += 1 + + with open(out_file_h, 'w') as outfile: + outfile.write( + template_out_file_h.format( + script_name=__file__, + font_file=font_file, + copyright_year=date.today().year, + out_file_name=out_file_h, + font_count=len(font_data), + font_glyph_widths=','.join(map(str, font_glyph_widths)), + font_glyph_heights=','.join(map(str, font_glyph_heights)), + max_font_width=max(font_glyph_widths), + max_font_height=max(font_glyph_heights), + font_layers='\n'.join(font_layers))) + outfile.close() + + font_layer_widths = [ + 'kFontGlyphWidths[' + str(layer) + '] * kFontCharactersPerRow' + for layer in range(len(font_data)) + ] + font_layer_heights = [ + 'kFontGlyphHeights[' + str(layer) + '] * kFontCharactersPerCol' + for layer in range(len(font_data)) + ] + + with open(out_file_cpp, 'w') as outfile: + outfile.write( + template_out_file_cpp.format( + script_name=__file__, + font_file=font_file, + copyright_year=date.today().year, + out_file_name=out_file_cpp, + font_layer_widths=','.join(font_layer_widths), + font_layer_heights=','.join(font_layer_heights), + font_data='\n'.join(font_data), + get_font_layer_pixel=''.join(get_font_layer_pixel))) + outfile.close() + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/src/libANGLE/gen_overlay_widgets.py b/src/libANGLE/gen_overlay_widgets.py new file mode 100644 index 00000000000..004c32c0cb4 --- /dev/null +++ b/src/libANGLE/gen_overlay_widgets.py @@ -0,0 +1,320 @@ +#! /usr/bin/python + +# 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. +# +# gen_overlay_widgets.py: +# Code generation for overlay widgets. Should be run when the widgets declaration file, +# overlay_widgets.json, is changed. +# NOTE: don't run this script directly. Run scripts/run_code_generation.py. + +from datetime import date +import json +import sys + +out_file = 'Overlay_autogen.cpp' +in_file = 'overlay_widgets.json' + +template_out_file = u"""// GENERATED FILE - DO NOT EDIT. +// Generated by {script_name} using data from {input_file_name}. +// +// Copyright {copyright_year} 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. +// +// {out_file_name}: +// Autogenerated overlay widget declarations. + +#include "libANGLE/renderer/driver_utils.h" +#include "libANGLE/Overlay.h" +#include "libANGLE/OverlayWidgets.h" +#include "libANGLE/Overlay_font_autogen.h" + +namespace gl +{{ +using namespace overlay; + +namespace +{{ +int GetFontSize(int fontSize, bool largeFont) +{{ + if (largeFont && fontSize > 0) + {{ + return fontSize - 1; + }} + return fontSize; +}} +}} // anonymous namespace + +void Overlay::initOverlayWidgets() +{{ + const bool kLargeFont = rx::IsAndroid(); + + {init_widgets} +}} + +}} // namespace gl + +""" + +template_init_widget = u"""{{ +const int32_t fontSize = GetFontSize({font_size}, kLargeFont); +const int32_t offsetX = {offset_x}; +const int32_t offsetY = {offset_y}; +const int32_t width = {width}; +const int32_t height = {height}; + +widget->{subwidget}type = WidgetType::{type}; +widget->{subwidget}fontSize = fontSize; +widget->{subwidget}coords[0] = {coord0}; +widget->{subwidget}coords[1] = {coord1}; +widget->{subwidget}coords[2] = {coord2}; +widget->{subwidget}coords[3] = {coord3}; +widget->{subwidget}color[0] = {color_r}; +widget->{subwidget}color[1] = {color_g}; +widget->{subwidget}color[2] = {color_b}; +widget->{subwidget}color[3] = {color_a}; +}} +""" + + +def extract_type_and_constructor(properties): + constructor = properties['type'] + args_separated = constructor.split('(', 1) + if len(args_separated) == 1: + return constructor, constructor + + type_no_constructor = args_separated[0] + return type_no_constructor, constructor + + +def get_font_size_constant(properties): + return 'kFontLayer' + properties['font'].capitalize() + + +def is_graph_type(type): + return type == 'RunningGraph' or type == 'RunningHistogram' + + +def is_text_type(type): + return not is_graph_type(type) + + +class OverlayWidget: + + def __init__(self, properties, is_graph_description=False): + if not is_graph_description: + self.name = properties['name'] + self.type, self.constructor = extract_type_and_constructor(properties) + self.extract_common(properties) + + if is_graph_type(self.type): + description_properties = properties['description'] + description_properties['type'] = 'Text' + self.description = OverlayWidget(description_properties, True) + + def extract_common(self, properties): + self.color = properties['color'] + self.coords = properties['coords'] + if is_graph_type(self.type): + self.bar_width = properties['bar_width'] + self.height = properties['height'] + else: + self.font = get_font_size_constant(properties) + self.length = properties['length'] + + self.negative_alignment = [False, False] + + +def is_negative_coord(coords, axis, widgets_so_far): + + if isinstance(coords[axis], unicode): + coord_split = coords[axis].split('.') + # The coordinate is in the form other_widget.edge.mode + # We simply need to know if other_widget's coordinate is negative or not. + return widgets_so_far[coord_split[0]].negative_alignment[axis] + + return coords[axis] < 0 + + +def set_alignment_flags(overlay_widget, widgets_so_far): + overlay_widget.negative_alignment[0] = is_negative_coord(overlay_widget.coords, 0, + widgets_so_far) + overlay_widget.negative_alignment[1] = is_negative_coord(overlay_widget.coords, 1, + widgets_so_far) + + if is_graph_type(overlay_widget.type): + set_alignment_flags(overlay_widget.description, widgets_so_far) + + +def get_offset_helper(widget, axis, smaller_coord_side): + # Assume axis is X. This function returns two values: + # - An offset where the bounding box is placed at, + # - Whether this offset is for the left or right edge. + # + # The input coordinate (widget.coord[axis]) is either: + # + # - a number: in this case, the offset is that number, and its sign determines whether this refers to the left or right edge of the bounding box. + # - other_widget.edge.mode: this has multiple possibilities: + # * edge=left, mode=align: the offset is other_widget.left, the edge is left. + # * edge=left, mode=adjacent: the offset is other_widget.left, the edge is right. + # * edge=right, mode=align: the offset is other_widget.right, the edge is right. + # * edge=right, mode=adjacent: the offset is other_widget.right, the edge is left. + # + # The case for the Y axis is similar, with the edge values being top or bottom. + + coord = widget.coords[axis] + if not isinstance(coord, unicode): + is_left = coord >= 0 + return coord, is_left + + coord_split = coord.split('.') + + is_left = coord_split[1] == smaller_coord_side + is_align = coord_split[2] == 'align' + + other_widget_coords = 'mState.mOverlayWidgets[WidgetId::' + coord_split[0] + ']->coords' + other_widget_coord_index = axis + (0 if is_left else 2) + offset = other_widget_coords + '[' + str(other_widget_coord_index) + ']' + + return offset, is_left == is_align + + +def get_offset_x(widget): + return get_offset_helper(widget, 0, 'left') + + +def get_offset_y(widget): + return get_offset_helper(widget, 1, 'top') + + +def get_bounding_box_coords(offset, width, offset_is_left, is_left_aligned): + # See comment in generate_widget_init_helper. This function is implementing the following: + # + # - offset_is_left && is_left_aligned: [offset, offset + width] + # - offset_is_left && !is_left_aligned: [offset, std::min(offset + width, -1)] + # - !offset_is_left && is_left_aligned: [std::max(1, offset - width), offset] + # - !offset_is_left && !is_left_aligned: [offset - width, offset] + + coord_left = offset if offset_is_left else (offset + ' - ' + width) + coord_right = (offset + ' + ' + width) if offset_is_left else offset + + if offset_is_left and not is_left_aligned: + coord_right = 'std::min(' + coord_right + ', -1)' + if not offset_is_left and is_left_aligned: + coord_left = 'std::max(' + coord_left + ', 1)' + + return coord_left, coord_right + + +def generate_widget_init_helper(widget, is_graph_description=False): + font_size = '0' + + # Common attributes + color = [channel / 255.0 for channel in widget.color] + offset_x, offset_x_is_left = get_offset_x(widget) + offset_y, offset_y_is_top = get_offset_y(widget) + + if is_text_type(widget.type): + # Attributes deriven from text properties + font_size = widget.font + width = str(widget.length) + ' * kFontGlyphWidths[fontSize]' + height = 'kFontGlyphHeights[fontSize]' + else: + # Attributes deriven from graph properties + width = str(widget.bar_width) + ' * static_cast(widget->runningValues.size())' + height = widget.height + + is_left_aligned = not widget.negative_alignment[0] + is_top_aligned = not widget.negative_alignment[1] + + # We have offset_x, offset_y, width and height which together determine the bounding box. If + # offset_x_is_left, the bounding box X would be in [offset_x, offset_x + width], otherwise it + # would be in [offset_x - width, offset_x]. Similarly for y. Since we use negative values to + # mean aligned to the right side of the screen, we need to make sure that: + # + # - if left aligned: offset_x - width is at minimum 1 + # - if right aligned: offset_x + width is at maximum -1 + # + # We therefore have the following combinations for the X axis: + # + # - offset_x_is_left && is_left_aligned: [offset_x, offset_x + width] + # - offset_x_is_left && !is_left_aligned: [offset_x, std::min(offset_x + width, -1)] + # - !offset_x_is_left && is_left_aligned: [std::max(1, offset_x - width), offset_x] + # - !offset_x_is_left && !is_left_aligned: [offset_x - width, offset_x] + # + # Similarly for y. + coord0, coord2 = get_bounding_box_coords('offsetX', 'width', offset_x_is_left, is_left_aligned) + coord1, coord3 = get_bounding_box_coords('offsetY', 'height', offset_y_is_top, is_top_aligned) + + return template_init_widget.format( + subwidget='description.' if is_graph_description else '', + offset_x=offset_x, + offset_y=offset_y, + width=width, + height=height, + type=widget.type, + font_size=font_size, + coord0=coord0, + coord1=coord1, + coord2=coord2, + coord3=coord3, + color_r=color[0], + color_g=color[1], + color_b=color[2], + color_a=color[3]) + + +def generate_widget_init(widget): + widget_init = '{\n' + widget.type + ' *widget = new ' + widget.constructor + ';\n' + + widget_init += generate_widget_init_helper(widget) + widget_init += 'mState.mOverlayWidgets[WidgetId::' + widget.name + '].reset(widget);\n' + + if is_graph_type(widget.type): + widget_init += generate_widget_init_helper(widget.description, True) + + widget_init += '}\n' + + return widget_init + + +def main(): + if len(sys.argv) == 2 and sys.argv[1] == 'inputs': + print(in_file) + return + if len(sys.argv) == 2 and sys.argv[1] == 'outputs': + print(out_file) + return + + with open(in_file) as fin: + layout = json.loads(fin.read()) + + # Read the layouts from the json file and determine alignment of widgets (as they can refer to + # other widgets. + overlay_widgets = {} + for widget_properties in layout['widgets']: + widget = OverlayWidget(widget_properties) + overlay_widgets[widget.name] = widget + set_alignment_flags(widget, overlay_widgets) + + # Go over the widgets again and generate initialization code. Note that we need to iterate over + # the widgets in order, so we can't use the overlay_widgets dictionary for iteration. + init_widgets = [] + for widget_properties in layout['widgets']: + init_widgets.append(generate_widget_init(overlay_widgets[widget_properties['name']])) + + with open(out_file, 'w') as outfile: + outfile.write( + template_out_file.format( + script_name=__file__, + copyright_year=date.today().year, + input_file_name=in_file, + out_file_name=out_file, + init_widgets='\n'.join(init_widgets))) + outfile.close() + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/src/libANGLE/overlay/DejaVuSansMono-Bold.ttf b/src/libANGLE/overlay/DejaVuSansMono-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1ad83dd3b02920a55c449408da976e43c3257474 GIT binary patch literal 331992 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 z z%Po97g!*8xz1V>Fx$?I5>_2$MZKNq|7Jt&#h0?GP)WK`eWmQ(2^}5i;T+mqwy*W76 zbXJ3Vb(Ws;yx-tsr7t2fOpNe#IN{4dCIu8usQGbU!6!Q{y*Adm6J>%deChcffpnUq zr?HWrPVNESbXxP%bP`XAzCylQx+X)_SHly)$!8_FQT&?oy9V;0F(S#T9F$F%yLnlq zA-soY)Nj~LVFGLrJ!>X%7;(B?dkgDtHaT@)HM+CccSlY^D5jYUp%FJJ*XXwA$Xhj zMDdd13FJ$2HUu|{s?NhRl$UTBhSPit;J&*q;ENN=apa-lMi@=-pK-=VU@yoYiTjZ@?0_gBZSMPON{Z(o zf7F^Q?*H@u4^QLdf24O6Jn+kKJ>C1pB&(ItnuLZn*itS>K}nK7YCDgy4kV8! z_|MFcN3*m>8h~?42EkGuBuMj&k}QnCUWiZJ-yB2X+*~YX+(q(>^2TeQPn6bRH}`S{ zwRCw}NuacBgn+bX{nFBv)lsbLYoAXrMk^N)#t%LZ(oR#plZ#Re_VM{0{Wi6`J0b*O+uird?%N1`EdS;eiQNk|3qJx9t+o`*q(n) ziYPv0$v&9y`7x;i|1ReWf@Q*%wo=()_!Lr2D~}A28-s9_hA~7kupWWD&}GNmWu!RA z{`jQqESD+T2IAmg`zrg132cCJpiNK?vTDPp%CZx!Z_35!=ltlJg_82bFk@ptgxnY< z3LybO!lY=E6o?EWL&JlG=!j3s%8nJd=^wH=^~tdUK+YFLocCp>XXu})FJo`!O3q2T zp!X#ElvsdH3T%V)kxX~sMI4MW#)SxRKHI<}&(py%z5$o6%f-=tMD!9|j-s0?`>!rQ zq^3g0&HXD^6&4hUmjG}$iwX)?;Zb3s3y-)HPI>f@t#UIo6jH}m$;x_2H_&o~M7tp5 z2Tt2MVyd^yw5CoBCAx z-o$Bz(o?<6d%Fe>$n2lrp}Hz|j4@)2(07chd`y0qF&*e;lup zlE|o%$P!}le8KsGKhG=YQ8$qmzz7~ylBb;|R!;}FyCzRPWXvD@-@wyxYDT>8v8JY7 zyPD=d&JqjyS2`S3Rqlkx7cSVjb3xNCmQ>h}K-J2(k1cF^eAj}eoh->wse&GtqwTG~ zGV8*fk2fuRVrSFJ>Vm@R>cWEl;_-!#?*eGopZyA*0|pl6SGjXkq+NejI#kFd_Q*J8 zjGs)=C*W=clIRFwvLKkjn#CKLB?F;Z97P=&&Oh@1JT8hYH5Z2u^#2)Z{1ARxkgzor z9ZXyNX^Xv;PNpO>I=;(MZM+Z%JC~Q&_w1#7zH$1r{-V@>+SF<$_5XO&rfF09%dC3p zlqy-Qo-*woE{{ftW1lV|aZ0C(9;2-(DK^%lQ%a&NC!~z7=qWzHi+8_X+GPuOvN}l` z%KwqHhRRYMy>`hpx{Q`-Li0RKa?D7}7ez-}Mn+1ODa@3Ul0kx{Hnv6{FJaFBbR7MU z72ls?vC0W~Je#lFLH+$Z@_5+@U)^qU2rp1iWpcD(48Z%a2t0d5ea4#b3^)qLlIWiu zKxj|f#;j7+cI5<%CE9BGw~#)7r!NwYa@s|0=m#&OUBqc;n2HRPdlBUT+V#SnQm$;n ze)+iaAW;@fq9hD6n9z$9K-Xa>pw}^>EQUFyTts({R&r$9`QyjWv)ifRGqwZi7wPE@ zXyFDn4F6%f&g$s{DRpO{vQHHpJ5qj?ZA#N>WdX>jJnlvNO(p&XS$UWEhYy08Cj3ak zFL;(^_zkyb*?3G!Ya|qf4i9lnG8u6N9-S63MVoM^pL$?~!7PifD*uTdJ$}OVldgaJ z$JEquBYT^1xx6hRwo8ceBd)i;TN)Z*>&rrllM-KeY(PcNF~fUhWp@h<2?-OwQ~pj* z%*^SP8ra%_B~U~qsz1Rn5V4PgRS&~NGikmo(&2aoofo5*mF;Bii}+DwWAsta zI{H)bbAg|u;luXR$x3=jIf_j9#^}GlJu1$lKj4E`j2Y$K*#BVpaRcAwZ{N-LSN84OhZS!A z>WdjOzWQ>;3=H|{JS@fHc+yzzjp3mkO*KR2Y$Tg?%Cq#x0|%Z*R01WKj;FG{FY$E3 zpGddUa02~VsL-c81()H53X&9>F2E(&A8ZPIM%ovK!KyJp9v6a>+0b`#5YR=S(fr{i zA0e_NuX^Z6Qv`-p5r(%$rSiaWRM$8}Wp#=xE?tUxcjnCJl_o=$@~kK*!iEC}wj*E&5CNv}?y>2d(B36d{b+szu@QKCKFPL z5|+4UZFY8D?_Sy2S&F-+cF0hcJY;C5eL!7)?(h-H%OghQ=TA?yEu?~#mD+H*L#l0F z-!xlESKHLsalNLMmX&pz(kr)%C8oG&;NtR%ik=IrOI$DIC*fy8Vqy}FE=3j$UiX35 z6rl@Br3Ns;sWliX{Uo^>O-TK2Rto|4j9`^jku+zPl*rbC0?4zvu5R;@VRe(IybpnX zT0x9e^z3W1iBI2e2@fqRZNhDqmHlp6Hvlp{_09AdfdT9>yIqyKovIW16efO%bE?JM z-o(Id2VXd-0xN@TcT7UJuAP) zeL1QzIB38~6gPVs=_S2>3%mJdn2Pz zinm@`zSMK;N;i`|D=tfes|nEm*(mC320OZ8(u4_& z`m+}2JuUbGYot|kyHmK*+UH|q3mi#FxCSCGuXkf1g|V5+miJCh@&>S>lZj+IS!~+{ z>3OLR@j&`|<9xt>g+zKqnFP$3Yq38t=OOJOJYk*}))8r6LSk+F-!;aTrz@G+3BWD7A=N zkZ+9-#?qx0wi~cPURa{=nDnfe1sK*Aw6sUtrb=e15iqPMTmi#sf(FY1&%4A`h>6n4 z3rhs-AcqxrVX1)aAsQdCT|T zx0E*(7tbi0zIgHUvKhtl_^&?tN@@FwZOzU`$e%b?lAZOl%klctPrY71mQNB!we6H= z8%tmb^XO!OA;WI6Q5+In@LZJca*zSE@VCeeJ8nrWa&c~eg!@d<-*&{YXLE*K?AO(q zbZ1_U{h4PTXL06rXd9-Wggdj%QH74PBL)p0G5p2G$f$@r`d1c?PoI!m@}J_epis+= zFQj$;5Vztse)MWcRV{9T5~pns3Q^wal;pl%OiAspyyGfn-3_tUzBm88Vd}P=Sm{U@ z28TkQwo~#H*hFXw`DvV`6d^JKSHfvQaYXV2Ea)Jqw*iOz8Trt``b@`Pd5cGcBqcIyxwWB@Nr4eOdl%bE{IPAtF6Ev6y_LUz{^{nf zDdM|3Cyo{k%5k&#kxg2?jfOuHi7^cg#?}Ckk*J-es zuWI8gW`~Kp#IS)b8c^9%;TgjWvR7w5934~G%a-=zk2ys}y{bxF$xXA0Q#vkP`6Kk8 zpgcV&{_CUcHx_%?w%v8M1LZ zg)W#dP+WNWbW6+W7WS-CMK63*Kd@)n9#OG~tvxEES?4@bFWJn@L)u z_OTR^CKo4uaT^&FT?^HTr~HgMNk@ymgu~?>^B$|3 z7If~?F*jjKouY(y>a}Fn<1A)LuY!FE=zGdHZ9wlv{_b@LV!{x_sP&th>^Zkes6YmY3&n z=5z@Tv~At}%rlV&1D+HrDhBd z$XDoVmXMY7DlP3*4^wiwF}a7c>~mJRV{>h7r#@*Z#ifX5P@2`vcFXj&ce)l;mM?Uc zxU!3Eo2TBhv3rF@>QO(raip@+{i?`roHNApj^WeSKfCv6=cpAc7v#ppdrP=~&*eor zfT>A=ygE%+IwF2R1}s)*x~b7j_gElGk;BDbxINoOF9f0GzfJ?9b>SgP5KRud6`$(D z`{XBoko-gPhsmds-%HN#9Z@%B&OdXj=Kei*ij+}Wx;f(EaL>Zh(!=4laAjA-LlM%? z3pSqSKN}ZpbU!H#r`N`fN>6r_1uR&A+efrd3lZEspVfjU?S%I-bTRf$JwaEkF;jvwnitS zXpd4JKm3UNImTUOh^N1opV9dEdyH_!8A7ulqiq|JuM>78UszdQk`b2~8!Ci%T$wUE zaiPt$(l|S4p)|`jH#fW>KhvI@)hRAELNbS2!ZL(T9YQT(7IS!>y`!-crV5W0VDj+T zv8WQvMDdv_3;$3;a$kR`)^NhM6^YR`tB6?u_zHr+4bc6Zk-#bnz0C)6$efHI=JZz8H~~7M2ou zWW}1w8s$)08Z%xx64o&}DJA?x)Cr?gi}D`SiDsi2rUT(?T2TqG(Hk(Ua5t+^9IS_O z6idcClse_iSZTaC-*ZB=dhU3@Q!Ebf91!1pfYXvei|hyY6ETTkcRBF_CHh6QtQeO? zGASQS>U09Uht*m7kJohg!vTh))Ph zF`BXl^~=o8NbQ-y>Mjavs?Uz$8MQ>&LXjvIZb{NC1gk`u!_ zgkfMo?Y0Bj&mqV^OK_51fy2cG!-sy_C`%3e;#7xOT%@?m1X9xi_C$a2(gT}j^qLu) zX*tw?@YXFO2Ts_!`j+Ffd*=0+y77kUu9>-Fnj<>injULrzuwHkde2DM_s5=*n53bC%z91Y$*tBEN|(MTsypPFP73J_vd%Q!&{6o4Rw|ls-rH-$MU0? z?@NJJL*; zy%7g^be)o3n!ERzoFT5naFg;Yiwd9n0*pp4}f0>dp2i+|V z4o_X|{(X%Vywsy!aF!P}gxN~mJ_Gx!8qIn+sr3hOJ62|Hk&~2L(ETZ`ouyH@;Y1-B zW3515jCASvVnX;HbRtv`QZ3A2lXfF=Aj#Qf<+|>Y7Y{#~9Ku3|9}IU^-`UC9F%Pp7 zFC2&&G=1mCiwYA$mE4hRQD}VOVmFS&zgk@NYD4+xsKAtz2G37yQKu*V?%px`)$F9w zSCMxR@_qt&Cn0a#;bfHIIQa~|YV1vs1!+$CiN>i5mF98#j~4&=a`E5Hex&PvUhMkU za3+aopHTj~e%^JWb=0C8H;-C0kNvJZFmlP<2S+WrQCals32u8Dkq_bvAkrS?WKEGH zWGfG>iJ(2I+fPyQRX;TkQJQeW4Av<7L~6aH)G>G$3{ zz4I@&UYWaK`vS;*9emz==&1#oAf&_It6|T*!zK(Y$;;Q8r^p(XPI{;=@Xedy-5g?l zSnRU9x{Y4`^X#bs!MEKS613V?-f6XA0NcgJvbk(iVe+c%u6Z>9Vf&T6%DYD+QN1V* z{E-i^e?#W&&`!P@QzMr8T1jdK536a$g-bmCA@N0BkQ(9_582z!t{uCUmv^<67IYbC zU%PqpTKhoLR?+rIL{4sQ4nkjMt=hP8)#`iiH9Vr6Ew?WCc7d&@@=J2upX}*B<1U$v zPWR0>%)4>!+#BcJ@bh0v-JgH5J%5pnhy{ZOxh|UY7>O8bMA|itB)yal-|x=3-_5RL z#}Od*5yhrFVi?<+AfKk!LeFY(*`*xuqzCeZo?tdY9*=g`0bgKW_*@e;c&uGoy`j$K znmd)RZ!s9Ux`xh+UxeFYa+z&j-mdF!x;;?*!jmaJ8ShN!+HJ!c&mG2S&yF#Z?^uyM zz>hX*25tr-qGsrz*=llG446>m0qp@Rl5%cP3IF?FuHSkvTSjY7<*~fHU8ir4qKt#2 z=q4gA7nRK)&-%PEY00gBQzoV3C~sON5xJlAD3=Rn=L2yyLpppUjKeToV1ih*#q*YO zKYLu9)Tj*eY;9EKvGCGCL-nN`L$6CO@_MI#Z)ma&7OeQ15|I*>8c{&QS!Ttkv&azx z4+A2mAec_nIqu+_pgjCRS=k5l4z+YqkE2JMhHT)xVO%RsB4%eXlbi$l2=3XEbz7CC>HR*anzBY~3MmR&-ZK*C^M_8XW zsKX!{5t-3#Qg~=_%8IY*>&J|K_N(Q~zIt}_nELv!mQQ@Lf4|Dg^?N2x+S9j^ex6Wn zWH&yxfB$3mo;b0zqF=uXLrs1C=x=xmq+GWAo6+_4EBp2Dx99o^Pu|tPe`V#96RzKb z?@cS_&tIXq#ql4xu6KfW%+kr5xV*xkmmOgnA#q&Df_{R`jTK#nD-u@DKz%6r8v7qo zTE(irS)lUQ-^X$F(9Gk`++62z*4!<-p&?tV6wj|`Jf2J9a-;aM(dLP=<6c6(+|I5Po%vtpxfxg}cM#^2JFW){I7Kn&pNYzyx0y4$VXYsOsZQ;x#c zhvg2j@q0Xv?1`79)}LZKJSASYCm!`@;AcNcZvtQg)78-(O)ohlSarmvwSY@La7EkX zDsO~rh*6tG<1Za@6PMIgE?6_aU|{L&F4q+{D@~6(mo-Kzo5hJ=e>N%0a{|?mpL_D- z`}9uoWNj8_c6*#6$lX|;-?zif%atkYwxv@%_ZU9??28X4WQlis){5dhG12piC3yfV z8)(g=#*cO)NcT`22+T=G3l-&Qfkq~UnIeMZs4(1BKPe^vH<1g5Kto?Cuy1f^-|)VX zea*RUT@Q|lNqxDfNsg4A{nd`ZTYd`%8xI~ZHIbuKt~^eLD*%q&J+-NHJ@xiMwYdG`rS z=%x2kzBcYYuv;GQj$61;nj=1_JgL0szDt^ea$|iId+V@oS6Bk)V+;0zzQI?)tA)4R z!};?cRIE7P0$`=wuWWqR-PB%Yq= z&-bUVKX3a(r*Epf+H;iudwKm;@~_hJx9QJK{oAG2pA-MfuabU%mY(=q&iQZ8pZ?sY zr@xH8{yg6Myt-Zf`tw}&N4xqnQvIRcqLGf|uGS}{L;OTwWrnDrN%h3;&<)bRC@!km z$t=`USxh~dZQ&}Z(EaYJh3wb$^yTELg-|6GX<$;7B$V_%LSd*QJ%`BDUurzs~ za(v+`_q$Rd(qdwl()i^Oh?{INEU>$nyulxlVP=?9P>x@bkCnMFr5)+QhMrXA8x`wY zABU8}mq$3hSWK8WLQ#-Q4Dw^6S1nYIQvxx8n4+B6EA)vMjUKKiSiABO9V(iG3W=<3 z%*FmjnzZ#)RHXTKJ$PXqd?Y=mwQM+@&24Ap&e94lR~J?baRF~_~?(FxHkjiO4+61ur1iDKgpMX36HjYCl^Wch<>^W`x(HV z(;*iv@M4Wvpyi~}-`w^+_?b`m20JE~u?GqNB6Or=A7?7QUT0)mu-*^13woi76|+3Q zZ&Cj1p0@`nXLQN3+wOf^+;;M}IX8Lb`r91;dZGCzln4U{y;?x?+bt{-WLS(|ElSh9 zZ?jiaGFq(=8Psnnn<=k_d@$ZLqn{v=8Zi#?PT7G+s)HyFr%sj%j zEI49|#x!9_wwNAMni!WEBZ{$!w&H;!6Cz`x!@|O?{bbVss}(_UVE#($ag&;wKMyIB4Lo3_1tWdo3-V^?L5&wo9H) zzDfb>eszMh>0Vn#n|J&y8IrY#b9E*>>sv5;LTUB(Px*S8rae|nZjVm#*BKT+xjbK{ z*-q%R6Ors8chzvNx+H!g-QmaoT%NH{kIdki?7p7~M%Uz2djPL05jmEMB9L`wqx51Z zj}uRzsFg#GqFp%@#GZa>B*B}avj8I{eRdgE!YkUzA>m;`!3O+bRyHKOJin;U5*r(r zmE+7W_xwS$d2h1KXb1`p4Gjwm3&oYt#*?vegNt3I-3m)Gvn|}D@&3h6o*ExsdGeWQ zzQv|H?f;Cy<{J9ti?}ceY?>IN7s>NSdA>6zD=s$HQdg8;4z2=K27|)F{i-0wlAT#n z*sau6JUA})q|p=@#MuiC4l>X>lBm`z_(-F;ShV^@zkIeF8DqNChJ{E~#c^2#hKjJM z8dpg)9Mc5Ide^`|gx3np2io;xaTWJTOF-`vpgEaRvnkg@wpbEXI7H8uY#LQ;tOZ=FX6V#+{VMV_A!lcEDTD7IXhBd|L~uV@4hakogLfY{1l(6rS-IbE z@}y7dSy`5t6D0Qd@UT!W^~%ujkdQz`cK5ZZzFhLjSeaDisjXU2RcJu1IBLhmg>A>M zlq-kUpQ)9^Mu&$7M8!k}1W2KA@rlW{v_xx6T&Mx-0{}*Z=_RvtN=@o$NeYxrrl7!> zfS>@A9GDoFoSd2)tyP)0EhHi!C9L-m77hVPI73G5c zXPw|G7H0oR&m6Q%+FIr1hRrnYgK03>C6~p_a1kt%ZnCWI$2>pyUB!m$)qScop`=yZhivUh z&jVVfICu0!Ym=U-njg}|Yw0v?pm{n;(6Ubr`gl?HL8jt;lA>7*N_w)~5rEypAIZ|AB(!I;eC)?&((T>joHd1~>4(0ob z`Bp*bw7O^qvtrX)8g!P{;;=r*{pe0MYel!(n)H6rq}R9pAbq19vSYiheySZ(4BS~jaJ>Gocc;fzI? zQ&Kata_a{T=}~4&NwIdXsI9ZWE)~Fke?%UR8CGbg8GW6>>-87NGg{p~|5|!`-MUx& zoPXFf$bN$%N?kV(WZEDM!vOTQsB>tichJNP(9pX)bHG+>ON;ncON-LFaFu6{c-N|h zawt6|YihtW*(dHtn8DMDK64;+-_`b|yjivgnDJy-;?u1@H<;@7PnX57`{CxECJS@X zEs)18oyh2(nVCJX-{krmXEj_ma8PY#`jFjSVl9@~&i1mrUKLJP=gyridE{tIV;-0= zdsf55f&IE3t88sqbvCI&4d`dP0w#mM9L<{^f?ak7oE3Py!@(l$J;f^PGeuYcXCD5 z3g@}q-jZrlEzpqeyER(88Qa#Ybg)d%%S&S`7oU(IMNqZDAx=daKKsJcq^*~>@Ak6i zWm2tsvNI|_%tA9GTv1eQiIGlSB^fcK7K(_&FmpP7{G^+_LRYl}O9)S@5?{TN>&yDx zS1Bl!%cmQ3&xD|9W27o4T`N=>u@_X;WU|)IE=#Mnv_MVqy$#OSMA!@91^RJ>mxAZ5 z&3nb*RE)r^7$VXv2kHg`P1R@V$gC!dl|9Io48N}ElJaIPTdVXLKECKkZwLZ>T~fwW zR^nEX6Azb8Y`m*+OVE-6|C;w@|rQajmkD9Z}20^SZ=#R8}faveka&QgczurP(;l8Pb>* zBBEBTwP%I{bkZ14kX{1uPjOLYrH|uAu0Q%5BBj@~7;^?#g|dq&gv+N1dN;EE(iry+ z@lRa_o*-!q%Gf@CO?y>kc1aIkkw9DolA4qnsa||zOyr*~aoeUTu|?d6J6W|MYVXF% z3+>C|-a+YoG7iV8+ZD5o=_Fkfdr%hvd&J9st2n)~(zB_Ot@c)-A8VvEbc98nUsY-Q z4}ZZUP6dnPo&|~ z`r+dED$lRfbI%fEs>EZ%J=?29%N&~g^8AX0I+EMJkiJe$4@*uHl+;DzlT+$N=rOZ2 zbaA|R%(JyhjHOO?j^~#u5tlGh`tOmR>kY>CG@YT%Tsou&FGv4f99QKzGfSC-8Oqoy z&sNHR8PXSN>0=yx2Ggp|Wfl)7{9op1_`kO=4$|uFg64HeW2vQ+(&C*ZOEw1BY5Y_D9<^2&nVvj)7LB_s5b@~om zVn;Vzj!XEV{*?DM`26t054Q|&!2m?f=>>e@yy^N&`vKI%HqGs~c!|SJP|4|YLHKr3 zdKx5-P$xq+{|LT3;%`F((MM4Khuuu7vB7TX7zbXW^>sZF>vd$w5zWg|`_Ys50b8)e zI$t^+y@VE%#pc3{vj6Npc3FPMPMl=oERa^q_xiFUN0hgZ&}6;OuIsdPJDwvt9R^5H zY`!9$pZJNTEBWyX2{(_%NO<|pl`(em1h!3{@D`M~VMXA^r`PB~FB>_?myH$fYd1Qe zy4UrHdf#^A44PZ?jVnZ?^dCq-1|n9iZ-+1Z1^iM!6Qth z8x6(3Jb~h`hYycE_dr}blz%|yFLn>*U4gvc_2$hFjKG>8XD5@ksMvpdg2X@Bz2dK94~;#njQWY) z^pi4*(zef+FF0c*1o=9clsfLvm_thakL;$Om60ru%CLi(s07MPun<-j)_C8Tf3pyr5dLHwi}R-^e!dBOOPk!&XNemj0zaOOpigs0Bm-;)p{AdSZmlAfF_(|B# zYd+HEQuC2`9$s0`fso()@fSTWBhTk3dwItWr5sWxX*1~?o}ZQ%`34)Ho5wZDlSD8V z;IhZ?mVs)Zk&gf&Q`H^i6nNc<8$b4J|9C9giE`>KDe5g~E3_86VaL3}R(TTI8}(dh zUbaXxhT`gaqI`#2o_xwTwIENL?3Uz7%42@h3!s7XLh@tsLX8HW6_WHN!$^5Y>lR7* zLz(nEUygi1p4j@(WXbJbr7a&~mB?R5)qCkx6}7l*s>VC8VM>+Sm_yHxQ%hvm0>PHn_c7s7N#0?i6s--N7QUHNwVb$*4 z>-}V+_H*#AG`AYP9424NT9og+Jzd8Z9E*R2cggB1HhNIhlh39T4KPGWH5Y-D=3eD# zHl&56=z>&EwqSCA$f&-`s!J-37x_E~Z-?3t1$w9VywvOZe2mB6*f@k zNTqCeM|?@6tL`-*-vBhoJ%GnSFTX*NRMWCzMa#&RFZHs1*@DHbOS%JcEqcV1S9^4_ zaAq8A^@x_Q^zweyGJ>cRL0^%{`|#s$7ug8-8SOcPF;Y7zRUYE$Y3bAM)>*t;{i3=G zR4slL!%WIQ^z!D1YJzU+{ijGP^32qc1u}jL7=35Ee)Bwan#x-4_hx*Duv zYh&YEZ@`DRknGIg1=AW}5KCPG+(z>LCzh&ldx2sS*~4v>C<>+OEZB zY@Eh&*OVppees@0pPaIE_KZ(vO|cgTrZhZ0bXjIrzpjoR`5Cc;Z(rrG%GZCBrnJs` z?uOOM;fEHFo^|Nmtq=8yA5zhOcGunRef>LkN$WJYNB^hRp*Bbck3xREAU|vscEM%f zUJKqI73X;FqL;MQJ-(GK{fXUr0Ya0o&tse1%UFonvsgY;;V=OkM^)iw(j2K76fBYh zJ7XiodtZ)cfu4!+FU9x1XG$yUK1Hc#pFcQv?z2-^vazt?QcgpIM)`uW_$TFNwiNVx z2qWct<)=`ud3^V%ML+s)3S+d8h6x1J5TDt{hFeI?Nb6AAavIC9TWAfDs*Wa#?HO`n zQ&UEq-EJQ==;-l=u8yXrrcCeG(!z_IDk_{s&V=Ad_E&u39wjI)p+X1AdzzXGOB&|P zY-ku%Q=1u=fwYCC4KwH9J7$_YWcE%-bQaw-u&O+<1N$>Fd?&4G@6@+;@|8SpZ`a;{lu zmLtAx?ohDL0ze!9k}c-j*w+DB#^aTMS0Y~NU@M?G9&7~`G+PRq;|hrNeI~qO z@QUTdFyb*QXcmd_=4h4oNIZ?gD;uvIV1?&4Bi<28LVLWyIGuIC5eGgeXQR8?rC44n zdxnK;Bb8DTZssLn<`FLh#o;XK(^a46SQl-LG<8_zY1%~U3-V4na01HjxY01#c!98<6_qVe3mNW7vNdDVb-6ooU7$PG9HL)8TH zGEC~={y8dp+&Xqq3ETMBU3dMpkv`qgkS$*LHlx#oZ*M!tV$a=nay+-2?erxK^%3r9 zj&SVL#b|~IEzObO0W}~%rl_c9nKNZ5Xf_t`8VLYAP}LWHsXOdOL2Oinh+Pl(L<`ZF z$he8?ixSQ*sQN;mxRl+eq?xL|DBF|?%C>9i%XDEM@fYc6j&d|-JDPJGoFRtHMZCc2 zzGyIKOZm?MLjN^(qUOz~#CUk*gMapBdF3jaN(~HDfbM!V30@&=m=~Vr&)xK*<9N z_5}hKgjeuJRaczU7jo7Sw&YV4Vof5__s=7j-?iiONnl)Wfe)Z}K zY@qZxtR7C7)7a*ch(n5(+-l$RfHFWXF`P%+PAU&GutU;wLV(yH$PLB-9`O*nv%fh@ zf%%Y-e&rH`<7;RW4CntIXZ-k|&Zg~`)4`5?74-p_*KL?h8erP~PiN!De~+WKv;z6n zBEMiEyFAt?gvh4n0uRa0i6JH{$etq?@?eohz0|S?fOaq_}_lcn#?H6hq`Y5usTUqMj2LP{7V;8Br-wj8D$y znL(hZT-|z5ymTHt!bsTMMUYD{c|qVA9WUgA@f3NUF5h_7W7qWJek!o#?aZ5U!%Vg5t8o?tA2&65tuVSvpAESbXuHWG0I zvk-@+v+x#p&c_<;ea55ko;sDs2k~AgSbov?LO^g(Aa-To7Px?50}IAsWOcjzG56Uh zY?L?K)6F!WhCLNGl(X@eo&TaxDLnGE`0(pXJVy*^AO3Sj{G0asa{8tPQ5gYPegh}- z+p^fLUikGo+*H}tjok{l>=RDNICKTMq@&8ZkO@{#^D)FQgc9OhKaV(Pf$_rG6`YxO zh>sLi<&{n3e{`oQfY{E8yZpEsHcFzY(4AS{1+fhF?)#)^Bx@hd z2=cpex>q}wPbZOV&wlX3srOs2+jCv3SkDR(o9?Xgu4kvXW8R7t^E_j&OpjtlQ+PqV zN8p5!_$*KR{;3~65G%!c&lpN4?(pnX-la%)YWj`JIJvvYhMJBqH-v;ZXAc zXRoh(;-7ET56DPFn;VBaJ#CotLbnNeMcD44kt464sHI;ODqfg7`|eqTyHsT8@1FnY zpY(U+dG~?pyE2fa`hMAWoXPkM`L}BMSN!idxH@0bb#rG|&l(aD2foyI<&L?t2B?rZ z)iddda=ZRae^)tO9HDZGch2dxzjJ$bk1$p4DL)!v4|tXpDkJD!`8VE80nb89(>Tt( z!0E2x!d@{jy2n?p2PShG;%B5PwJ9|c?f9}7{(sMhOW&PE z`AF_7>OdKFj`AUSrQrN^2fnvWiiNKk1JT=4?X*pRwl-q*4;~vvEKYJni#m#C>Ed&J z#|`UKdVSxz%t7PC2+y?p)=mD14Y{Rse*eB>%0~C8>pNssXvSOe>&gp}_SBv~7o{bz z_+4j|e`=pQ^J7P&+%dD{`vK-yQF0oh*c52_NTCdM_6sj->i;NJS_`?VWc^A^rIvrW zvedO_f8gbYeA}MT@_hqL$0=k?Hb1Nzy!(0&E)ZU%Cd(dT;`ng#nysTQb;D7t{QmqXdfjAN9C zSx^gx*!vm3;j4@x*KiDCDfPa=jY`}&Mw(W_LP|DaH&I77z>t#l&D1e#xBl{ zDe}e+!5gEB^Yd`9HBpGk4vQ}4ZVdN)Db_dzZho0!BlEyBh=;7b=UrX;G^Q*lGGDcY zsn4!j4Z+dWzWQIq90i-n9$nt%41s8L-?!Hkz+j}PZFGZ<9OHWl+tmf?p}=QNOn#On z!;VIySDBdDv4gilRyKY;HXuMXGg+N`kEzkQGzU-qy8gL2u$i_@Q3*Dx)l$TS`ZL`2 z1V549t(*)+pscjje;+jabhjcC+OFPiowdpU9uU(-^l0wc3{Rm-m07J2`b zvQxIUhr#A+_J(-w0GSfcF1lU#f6w!Orx(}mi~c9IxMnHY{Ps4Q^hH|MzI>!FS1Ge! z9eHirf79173)Inf6g2$xMR<95j%}EnLmRK!D5!Pb}3B5T15toIA{PqlSYJPT3LL6hmzYL7e zts2|IF{NKYD*KX+5H0bYtX;cWJH=Z><%us@YC*p#jviyHa^nNP#2&4j2>gG4oBv&Jm;Ch@=7}fdRiaKdB==C zgVCgkx2tnUjX<3G-}2x&%KOs)Tq8pz@f`Q3sNXj1!aWlyx=$x&k)PF8?*~`CtxDDB zYxkV|w)@2_?ypVvRAMX+I$HY0Ub-9$PfhUZW{6o>w;wEcGv-ZV>H5!u${B+3|)+!x#i3D0JLi$O?}!)_Q^o z9TF5pwzdiJ;%|99y5;3{>zDb>xpO_b6qcSj6F&_7GyW+ z=DensU$(0>q+QBqEZg&#H@#`eBq()-G%4Vt&C#KZJSFDgC zt(O@VHFavN!&X*PQjSb&ZW0 zHEK#>VQCMQcX9k)rE6YN!ub2gC;XN_HXnc2C8wuHM-L7Qs~=oDW^7J!T55{W);l8F zQtftETbz)UBn(I0Ei{t1Yodr+Uah4;R4j!dF2el=+}*=x{y~jR%%2aJQ(M2KmpI&7 zUo>vQUY43(;ADF{+6#*I?oAm|P&`5tY=px(f3~upC7VJ+yE=!~D8IAh(axa*m5XBf z;M`mnZ$q3HQ&-MQI>nCia$|#}dN6N*8}50cox|m)#>jDZY!vX17`&iiw`okYCd&F(utHem{(YP}BCOyxI_g zHNWoVsiD!BCB)pRupr797PKHDAR3`ILIN;T7!YWP2^XTH{ai^*i&5D0E)g%23yC>U zI(4P`!rFkvS|i@$z7J7DUwfMU;+aVwSw*uFE`81NmmN6s%{k?R75mS9qqZqN_IRDk z0%L8G1pSgl@oEe;O!05H#q#YKoxv|`+W=d>gj+Y5GIb4y@2f^Cb&j4)oVeWcmAJ9? z>$J6hG_rc7+x23mXGYD}skdIZ9^G1t^!1s86NaAo0d$|5Pz{%y*UiYbt)RV1;|F$J z=Sb!2GOma-!>V)7^IxPVpB;0+@-ED+1qm7D(O4J68lYq}EeOCaFCivSjt=Isq+1(u z&wlbQ1t{UyHn2!oXL*q)N&G=IMbd$fKKh;2o?$iazUR+hg*GO*vBobm(}F-_fEZ(v z1x_1v2BPAHLVcXiwD0d`2aZBPr0zbaA zs_-#)&Jfg|yKB(ER(qa5`BjuJugV`-_tq1j;KzbmK4lr_!A!Fq78?5MwX2P^G>(4V z$m&Na1H~oFw*}s%>>SDVdv0B^P1>xpckbNO^P6r9IY0H>eYY7bI-jT>s-OQU4@u?t z>UpeD`EQ?rUJTG@!icuJQHC41Zf3yqb7AI#MvUPs7Ve)(LU2hM%8T*O!ZZwd^O-l6 zEx7lyEwzVOu(JEuGjA+!+Vsi8;_L%)X~5rN55vPZ*Uxwak^-@AUOH zDn}d53kP7O0c!;;-IImPzo0|HL-=BhlwVupQe`%|Ly$@z9f3x}#${=y^q=S;JypX-n?T^}Dr~H1$3+ImwSa|-g+t0koQU|E@ z`hRG955TC3?SFh{?!CL|$!3$?5Fp8BQ)z)zS|C6YNlMenc0&uaW*>jCFjV}P}0ldRu)lz zHiOw3KOVre)Yku9nQ;4~&UX1SjVUAl;gUrLu(9MXqurXzvk|ODlT|Z~cr>ekuqCD5 zu#gxHi8faDpdI_ODWa^*HFKmf<)$fYV^8;8?Ynm=CHtf&zBk%+&e&aI)sYv}$sN!1 zJ9+INE5F7}j_iFfScV0^U;Yqp+?1@A%0Z*0Mf0LuiCbIQ)-B2JCKXehhG?0Hk;$wx ztH%VL;qg;l(19fc;?+ARuJM(-S`~H~P@LQ}wVDm;E=IGXlO$ujdDX)!{NeFv6cexH zFuU@5`Ld=3M~mXZ?2`>fxtp~q7vIe}`CN5Yy2U5qz;TY@du&NzgC|Tu%sSO_!2K5O z>tw!^RW$)H4B1Dnokkm5nQLY0{T9!#Uo3DW*Tt34S=&G!B}k4XDd8X~flg@j?*i)I z)OL!aKq-KPI-I-huYRn%nBAJ~*4K}fKM|B{MQhQWPwJZT?a7pH?QKf8<(?_6u?_uW z!KRfb-xM#FK9cuGDYFedGk?>nlW+LrW_IRJ&g@LIz<6DY1NJmhZ}gxyrW$ep!YUoT zRKvT155D2>4adb@?b$;jERDzO+io~~<4NmFk=^9sAMRIKQE^7@xbzKE|vC|TdhX?hKUCHGbS5~s_0ij(lD{41A*q;aeQHiXM0 zJiyeP@+t*7#8iNt$G2flcNbr!FA^hgY~U3r#5YIZ!Mbubjjv<<_3AWnHdh3*{w%g9 z78^*;WJ`SGX`MFpl9oS1w$)YQ^0KB^!)mR$NX)5MUZQ&c0FQc=zPy>NJ`pa3#zn;7 zwm~%!;G;8`6Ey(~lik-zW4OneM&qkwDIAgl>E~94e%HTG(XDru?0NVxQT^<9uRL?| zxu1p(n4mRn8n2z{srSD|Y<_6Or=#8wo5kJw=RJA%65rY6{@&&=&ucjCvO!rIiBu=# z7Q)85sk2DdvpZZsA&pJ1D~oCM%le&)VxweHV92|9v!413W>KtI7Das#{+)B+r;TM( zQVMC(jy9z$!vl|Z=I!;jr*16oJp~v0zF4|u&1!Y_kxla#mi0ceX48jXRjx7mbO0Q4 zpSS5uLenU?RowCZ>NRVYexdKOd&VG4v4rwa|-gyN`^((@E9O}tt$)L0HODnkKWnin0Wn5?$-A;ZZvu)o7D;^ zJELFs=1CM8D|zXN{@D=(xh+-p5%SLPOO%K9lsnWBJzg%gkf&odto$^ul@UCY1p(!; zPG9OLcsnXjtT4(`yO;%v8WhM|9N~^n=IX_B%2Q?Q_c!3~lVdy{iC>QBBqnKVYCm7v#&t%?Sd{>zNcGZ`67FXS1bQrS%+Y|?slY~O8 z_y{r>gIOeTAl0p|50#A{me1nr3Zx28?jw7YmMI&ue{xx|QJ&Sc5Dyx@$+M)77VXY~ z{gL8#QkVnNt-_ncF*n!6^r~5pJ~F53S8+rfuHw4*t3Q85A9Uhw#_s!xKc;sTPm9wy zs8{w?3#OCeD7!9(XL;Mh;4`=$*nX>4EnBsUmtG1qA571dt&*~75MkIBHD0hR>= za?Ht-TCwb1Izeu6YNP7oc-9~t`T3JOPp4Cyl2sp98<7W{f>~0I`n>uX{C0E5SK5Xpd9x3Y zvoz`4QbHEwtCo+nOkjCOQv&R20>2U>@H+eDkB_e!)S`Lw=2ud|$z5a)Kkfi))_=`xsQ}6wcQ5QcF z(*Gy4*9tt4S{?_@jQ%0+ZD+sm!t57z&v}0L?A`yk3cKg*LFVUYQ|626^1sqQ9owJ( z5&wuCv)RwH|1t9V2+9Vu1KL1=i~-){dlUV?@XlUx(P{Nhm>=h+u2Y=RN=!oycS7Fhg-x?g+z9iAR-RCWB9}@fpON$Oa zblGYO5$$Z35aAGivJgjjLc8ebdC_g!7PXspE;O`VLb&7XUyg``b|E3Nob9``%bpp~ zp0rlrmFun~Px1brII%gOr{7HPH~$GY@}jkD%W59^&-t;w9Q$AU{y&$!YuQfmzsufi zTba65-Gh-j5^EBqu@KFTF$^Om_8xh;t8RE=NBloMre0TlyK=}HcSM5H*nd=ctNM15 zBNn_`A3lsFCLAV534YXsz`uA*yi=DoAg_f>piH-5gv>d1Z1%CEI1z33QLb3XOqhKf zcYmBicg6K}Krew0{0S{sQdaRC3kc-U2X$GYUtn2RU2W+X23c5^GTeXvX-(D7R_SL< z{URV8$OWwhvD~)!?^lMO<{?!)3<^elSSEqh)uR7t(N9yWs!vE)bkbDok#9q;U` zmj^!R$kUP`W)bBp;jQ#fPLqDc_UwCS-~}=Al(^+vN;p7aeDIMAs>#&L< zz3j9IVP~tVs#wbUVRFsnOt&?ds0QYjQ3PnV zX^$I*IyPa~s=Ji?Aqk*I+pvw0Jd;T;gz(CC$KY_}G}YVp`hI<9_7yYq6?|5VZ^+4q z?*Dy2I)AC(71R6n?Nrq=`Ra#%zrR0hDxm9N>{pm&50!Byz}|Eu6uC${qoTb@(dsNy zZH8efsY-d|!h>25LlwWUTN}#yF_$j(;wwjFFg%9gTaV!pnakK&{C`}o&lK3m3?i@AK1zFFT)xU;=HT8U6@ zLZ0a7`79hr9b!}AHgD{OpplwMPF8Lb>ttPzup5;Hn^biq_aIzstYz*3oE1>9XFbQc?F`?4?5vI;=*ZKYfBe zL%U0DPHz;P=3UXL>L;QJ_NX_3J;dx6DWLu}{!u*^q9D03*+40V~Qu9`lkUSO_y2 ze&ZX)7$s!co;}N8Kwp>Hu3aX5!*oe|Xq(dY>!ON9zs{zx;yo;A&%t*6+Z_~Z5Cx+> zTX#@YiTR?6mR7;L^~;p!zJPJ%3O?)*Mw$4HGGRDi`>0Gh@Pf*uZuI0!5noDwa|M1Rvig}pgX+P%S_=xgYz!GTMO))J)ZtutYZ zeK1~&r%#G!98)bbwz29d`*3}jQeebt1lU~KG(?WxRJ?Ai&lzi+V&56o=OpX*$H&^E zmPK5yb{ev)Zk-lVg@9=^)3ZPstFUJ*2<%T1c~a&DXW__^g6_fOtd=cA<(}$j7eU;{Ocwg~~UNcRfBA(=08Vku~ ze}TtNlDU>}353gH2{40!+BA#84m?=g4A9fD5xXxA5BiO5<%{&0Vv^GQrN+%UA^6zD$i$!D~FY1uy09jXf!b;APc_P`Y6Orb>s{?(D5 zYvlv_Sh&FA5N+5)2^*}bs>W(6 z*-8zIX-dUm*5ZaE^Y7aB@0VJCa7O(6(~={-D(9?wt>CL2AD?&P9LTMx==UqRueJVi zMu<4;EIvFe<7CdQ`h%_6;9GaHuKQN%%l^&!e?GMTP)Xl|phFsLljKK57D>5NluS|5 zUWjAPaLf+21}L4rEPYhp$~KGeLf%@RKZ<@9insZ)Kevh(?P+~pC;P&qC&jP0dQ@4j z4`i>2BC`z}l!2Ys0q|>gUmImKfX~)$)j#6Pwrt%=W%wsrC6HwTC9>C01kn((jO-w= z`N9f9NMq#3+p;@Vuy1DRPa2jMv1>#RY?w%W;Q1aggeoE4ZQRM@iz%#HeOQbF%>qoF zpCd9cB6VmR9u8kE>p}fHwAfW7j~6I9|+>%-sb4ejJ_@W*y9OeUMMo?;Gq*s8=u+ zrl2K=L5oIQrr2Hx1M`F7PH{^MaqJQ$fAjbsGzd_Cg+DXagWwrLq_kFog8y!#1Wb($ zmWT97b#)&0ZauWrtqm7c&Od2wrf?Qp$oa%i#TVn_s#`${BmgZy)OvZr6kkz)HD%u4 z;L>na#qYWtF7U5x$KF>rDjjfY2t4rF`_kvqj2nQxFtEykU^7@-wZF23G!}@oJPjun z^X>ZEY#VRS=R%P5`uqaxDxQP49+&4nkB0BKO4>&b1*1r%kQ7td1y=3f#}|mb;&uKQ z))h>#eD?aqEN;iN@ul`c8>PjAuJI7`FQsEUM#_#+^e0_yEAOxG}7TLn@()I zkxs^@884dcg(QvL3tz82w8>M__zvhAofJw3JPe2~^qD%SAHy~%}Ph`$nG5okH3V1A$QnB=$K0- zedHWSo#X$YN?CeZe8w9AukN;=)Z4Tc;4||7O3}DWO^s&Jikiw@DHp&)QdGx+H7QP?q=E5e=1jGub+N++Isdh8~Joa#nXE$2Ne|! z0*u}4YBf%c!%T`6wA0v%R4{srAL4rsnV`EwYu_ z27wc$3u(3+ZlQolQzx7R0N+bYq0$PO4<(X|X$K|Gmu@&>(iUMX^uVE*R-s=arY|acxO{dG9>ytyeFh zyZPlxuMJ;V*}mAYcw^mZ|oD(M<95t)FuvMo}jVq0ZHnt<<7wSh$|Mu{xejR(Z zZW)u@N?*R#ccCMdYwIT5{HSBO^y+Gjt+d?q_a^YPVv&>W!b%g8TnyN;ygE_+NGJh- z`P{WW?Ev-RBJj@b>T&R7D9sw>8h|eqRWD+Ta3p4?=p(K=%PX;4zq5MW|MX|d6`y{J zZLsK18R%an}&30nX zX)@q?(0{UEb?j~%fc@H&Y_n`jZEJ1!*dDg+w7qJ3&-R7w2iq^UY6Mhu!A#H`p_96? zzHA7)mR-+oVk_AO_5gc|y@*(7pRym=FRYr=4BwlL4bMJra-K8S<1~(q%f(MuY)o^O zT*z`eU^Oz}x**`%5pW%t=KtzC_5Wx1=>hNq>+*kf9SHybiYEUJ97lFjX0{%+V9w>* zQj<@;l-jpO*)?>izien>qOvO?!C#g*IWjR4|HF*0+aeRAq7ox_+bTW~3p1aIs96G)g8%yE zStVQ&N^L=uZ+2As$jJ6lc#Vrri0ou!7-oFwS4T#&Cn6)&$Vtl(|ggjVk>8XKz`}zfTkRwCsPv%D{hU<3 z>Rd+Fx}+eK642}Oq(bC6abS)e=Wo0HCl0Yl618mYJ7bu#b7z{k{vF6#R_Xta-7X+u z86>SC6d?>Tw&d2lq~6Pi)0n5R0)(99O@+*xo zqahq~%z#>rcmgzb00Vrp4_KafkKW?ldVtj@aVuK9_cR};hY)b(M}^L{wcx54i^9kf z4E%yYED4Z+0zc7GwCZcvb@}M(4r-o%2>WC(-zHkIPb#H-cNrgX?kdNl{wMewdLjFS z^i-qXILq-9?4Pp-ccy9tloyJTH4!6}EgEOn!s`Gh*WxT&c{)8}>dBMnNfC8=Q-Q?8 zN2VQ~e&h(0*WZF2skd4L%<{QrM|eAuH+B>Bx~zjvV1|b$D7Ydb)#4q_Bgy=C9H9 zLqNQ0s}5u*c$mz@ zzd?4QM@=qxbSqua>=HzGVy6epn0Bz`6G{vJXUY-(drIE>jw$EXy=~9ya-Jq57v(eg z(1F-8n0Kge&G3J=OJ+KMwUwui-;DLN2+40)Mv-A2v9d<&RG|Het|>P_%mx{wAKCo{KNi63J!j107IT0 zLaI8tIFxBPaTupWh(Gp=2iUOvOrAsqbSQo+0322Tio$LhbhTs#MKCtn1AQBTN2xQw zfJp5EaiNbzj#ET17BhRv38GLX{{itsW8UU(>q&IeY^Qqg3<@#0rokr(m|5*rDNf;d zp0WHMg5V!Q@Q%Zii*7bm-k_rRVH4h);9EKaI)UO%xX@SNNXP6-jt6SHM|DPNE?+vP z2I(ozs8kQj&qELLC8HNlYn3I|J`r)KPyhZKF((y&EIT-?-xYUnM28AF&!+7-GJRSW zKPdDiMWIU5Mcn;Zql%}+7V+Fu;>f$WWFuLRr#tzNEIP`RB}Kr6qp!H-nx^#4!eUM# zmjsVhSCinzI^*EV%E7g3jf%~Sc77V|9172F&=!3kJ&YQPAvU(+%~83)&G z*7aS)dM#Rnu6_T7=Hh-fT>E!*7TJ0@HlftAPL`d*zTdxS(f)dT;{X1#eBwc5ZEz{-MXfvAXjF9o ziOlLJ*lh>c3V-5YKf=N76n8qNRKKXq@vl%mZon%cm^a!Ga*GCi7Zesv@|-eExc}5Q z6N$if{zSlDcu4)tKTsQTZk@e)@Zen+T4kLum;6qO#5fIIIX2cB4Pl)o(9rvaQ|q(`r`(xV-o z1AoS2ZyVVO;Soz_d)Ft&7nQdD#j1w&Ju=}Q)6^cp_2&*-&dMpcdpzw-S) z)gQ8b2db54ZdukGyS&F#jv9TSARGJk{LG4yrqCIfb_r(FOzTV`*0;Ko3uYW6>msi+2#3e#IU&G)G1}8(XsZOJ$v?p z+O7pY#!LO!%rAF|S`e5KkJbXfr|S2x?AeG(`>}|$6BzNm|90_`3{DIDq+ftmVBsAG z15S+{k-S>6x0MIA36@?Z@3*D;kiKQ#S4)2fJ+ZCFo7vW2TfBgtc%3ks$k+a^eqY!_G3d;b&D)-d}+J@U)T3)CCn=UhUL?jnwz zjGnUzcB>#gk|#wK^f^~vfFe+*3ict^f>2l6HPm*sb(KCf@;=r)totMj#St?OB{V%L z3$g6zb4f`EqffgxzZ{Jql=orfcrhan4dj+Fv|ZrLRFVg<9@m&Rc(dQs0cO&@rw>5B) z=EC$epaW#2QPSgffaJiQTC=RH%PKq}y>pV1)aF^^uFXmWzL8;K&*OXdZe~p)oJS+VS@Gkq z@4Z(Xi(uC+=zlv80@4|wKTlhr_YBTJu(U9Ta&r2D1^v-h;4zCI5(#&Tg+SdJn86Nh zZhgd@10yty)p9>n$L{-`5!S+3UUpFM{(jv`ZzG}=c>H}-C|tAxQ*6pZw@ZYk!uz-=8~cS>Amc$2g7!mS;pQ z#}+BC0@x_kXcp8zzW_V;;7~N?nsMUuK9R{C2a3<)$$EF5dMD zw@77YwWvlo+@o8}@T0A|VP{^1b7Cud@O;Q6=!nXv>c}X&f;k83zg`SdXQ}h>8|y>( zT?GEVLq3NTvgo7E!MIaH@|s2$d4DO|r;oZIDox3i_dhi6%kc~O(+GaU@k`zZ+yFTF zHOJLefNv-G;Lj+LqVBaFfFA07UUdiA6?Z7hI(Q2IZEVkntW_PhwHnVtT!4e8TEhW= z_=#2pol)#P#FKsRkRF_PT6AMC%Mb98w7;nBG0vn?luITfyMVb1SpgOcWiSvd;m{$+ zbzQ(s#s^qxZXebwr$v{Z4?UDHyxrtEl^d>a->&0zg$2`#?pYvywX8V&yR7!jaz<5z zbrzdSGh0p{J9R?ijLd|jRqojN)uPVC1IcfBeF75pTB7n%#-Zw8nnZm;0{`uAs<~2<|u_|i`djc zMuQ_Z^rptbPlJ?Nv`XrKRV%EQ$>>TFxp~;T!+r{^iSG z!uM}~-&PJ=4_jOHR`o+$8+fi4A})SUTVLBiw3d&iS@<*7I}6eaOwV+17e*fZ(MB{J z?0{_@GwR5fwmG=>Z%9Yxc&05wq)n!-lBdv>A zv8+p)%g#C^`jQj7c1ue3CDGK%R%#or-UfLcDeVERVbja)#IqB4OazCJmSK$$Y?LR{ zxyqUkLY$6jX9^`nmrKo61S;q6?IY$(dwZNHHWmzqdHHvJ_7LFX+ zSYybeR^T|qE3SuV458y;_5v)Qw}LDHwpa)6#Pf3b`0qtW@mf7h3s72WhWN7SSUxf+ zxB&PT1oJK8%ZyZD!bY=)&(}w@-2hZ5Du}1{cqup}zo;lbWP$!o5Kz5qKtGZJN&t?* zQr9X-_h5AnyX;v`OajmD#B*D5U!Fx+&Kx(~`VsqjrbxS^lzprJy1Gab4OF;mz;(3* z9i&X188b|zUC+L{gMC{n1_BLA0`eBEuB#A@gVwlDeUt3Ka)h@Ga)D-Tj1@oWe&r{} z6!c*m42@B)XqT5O+{r`5p)Gs1G24zOZql(lI)i-=QKMkP@?kN}UrF_pd3h+-d==6_ zo!+15EE>o1vp33TA_j1mOSrKTY#PAk@z9$p57gK;y}iY;{Dl8;aixeCBYx%G*k{V( z6O`{~;PbPIPhJ$PINoSiv@@2!ebW;=m~GphEriW9R>_mtwL;fF5()k_Cu|IMGRn7{ zW+eq2Wt;B8O5#xPzFco`E-Bqbn|>B(C|Off$~#!P!{n>ZI0!C?GT58XIONUZBUoy zE#bpSaQ>h^%y*U+n;Cygwo^d;eyU%;pGi>9*pu^D`CQsEuq7rm4}`SScODr1dHZg>+8 zT0O*{8{sqnd_)ZJnIrMR%na@wKnK&oSrR)~%_n#jmSYoOfJh z*5i!C2Yg3uLfEr-{Y>!9Xs;-2$^O%k`7i7J`5xxHg9bzBVllwSs3SnaD}oRL+1NKMe%^wwv75FLXpUMw zdVa+!7G=_${4}IL1=SIyv!iruX7KW}bJ4%$IZoZ1G1Y8RpTUi01i9 zv)CdWU$}0!{yL6WI(r)(uXLQkj zo`LV2JZ=lfvH0vw_=!-5HYLb<23oztip+jnlhm+yD<4d#Y?`5lovW}E5u#S`uSO)&p=Brmr zqd9CU>N*v5jW+9w{M0H|Z3Ak&Ws5eA-7kip6ZENWr%(Mc`lL2jQTM5+dp$S-wI?bB zQUH{=EI7#{lD7;wieACv_y_u@!lt>mSCe_j;3LUnb+Xn0izwVnrQ;y)TRO5FWhOR zQGx>Dp!5`_NkceD69A_+O)VTy1APzuMB;-!8Vj!EE%`*vQ+?NVq78T=@HufUp2uiY zs!vicl(Y$ifqKVM`>;b65Hn2x9D_D8O&uU92V{Q+E|3G@ofzI?3wTtWbm3=77amjl z9Mm{A;k$v9G4{5;;vLXur!H=nZF5Aa=ZUG=XNv6p9LQ5j|(! zF0I7VfND^kQr03`m#(gSiD_N=W&=nzza$PwAArMTHI^D4$?ITSILMS#F%t(fox#tb zfsszOtmNnxkk?>)brOkei|=dG0UF6j^bVO$wvv?X1W&f3tP?FTkZqb$Qgin+VP5!| zXnJv4qAT?SK(&%q-$gyIE^RHIRC8MIr?I0J(Yka-`6#_%`6fr1G;M%`tXDl8Wb*2h z=-G9!>(R6p2a5rwu98pn&(!kSM?r=piJ1APT{tQWlc@kg@@^RAeiHmS!sbQ&LONH}2X_N)2ck zkQQ_#?Z=yEK-6;#nCKq$(^A<6Tto6f%u1L@Xu>pPwTUD3dMUw3)S5_MR5q1Ma>PoB z(+&a+E zk6P&oswH>L#94hJupCLv zT4`emafAGSgPY0slBG=6ua)K(Kh$z-(*DLh3mr`X8^pQn}JE=UyCmy`}`! zrA2$m8X7Z?ddYdsDfSA+nb!@t3UFk2W42c9P|qvw?c2p8G|Av>HpcD>^e1VDqVnZ< zJe%f0a_(l%-wZtr@QiUQmLwSQCyhf!N7Y_O<^8ZxGJ+|`LMts~4)#dQR;GyS39Qug zRfrt3e2J%KNGF17>RCvy=a8y(J+izGWgPq{;S*0mXSZ;n{(|;4qy~+nsL?CHa4 z1esa~uy-T1f87@Tf#Oyt0l0WXd*i~-m>W==OMTp^tE7t5$)(t4L=)xJ3$S=dy6}mz z-A%d}?H}3FuWy(HMS7t2wKKiqz;pw^1-z3-jyP|hV zUNHM0>P5Z3mh+Jiosf7R{9DWX5=T>BNLosXQL8CPJCA>z#F08A2@n%UgOsMcK^+e$fX^mi!&rR>2tOC6N0mOSR~D!Bv=PJPd+rq%Z#^CVB_ zM(3b%v>T7dJ@y!zBW}5R2zX`MLyT=-I3LRdavYR45F2=R>&4>t0yCqOg?u-EjbM^w zLq4?MYt=a~AL!&4Mb4EI=2N$w5|rl#4W$BqoakX|A$(!rZ{U4i<4Q{w!EP zWe{dw(k3D6AYozdfe{#5tzj0Z1x9{xsM%4+q9{l3H!wNAX23^*M{7FEwm?p3FT%z; zi@maJdS;tg?-^NaYoD>Z>OE8L@=vOLX3&P_b`oZ7TM$g;RK0xKsS7c+`7}?xXAaM~ zpKG7lyViRa)b+1dYM&WxSX-VU*JZy`O9P(`HpVzJpRz6BnX;$;Ge_XF#`T`@@d3~H z{CdyWy8+LjNXs$RERQt{eAcPnGuv&}GxXif)}xvlK7nZFSd4c2fiEDoAYWPZthTcM z(uigF9W<6ZP-u5?7NTSpV6P-~8`!?dAB61T^!-nNEBD>w*Een2gbzje50~2DLwK=# z`uuBI-8Cza*LmOK#R}x7OoR1xs>jC;YmMRZ_2`CupJnh%7=Tm6hG75aXxp{e1A3k9 zdh7$0bxcLwl)Rj#R6ni3H{JWccn-J{j`gjoABeFB4jiCQ`PMgnAjW-w7k$!OU;mL9 z^Zxtq)2Dp%@sv=ErKe&v-BOpXbxe?@L|7L(Z4y0}J8pM7n@CCTM*8rcL7gO`G`md+wp{OI>ebA8xuw zWaHW0#tXky-y!`p7(ze!t$rFzqMtgX<=~s;pMBWmAGY>ew)POKJah;?WHqPkUCqAm zrOg(EsZdRgT8jShqwF8Y)WNcU7~}1P02zeH7RGpB_NQa~HT0*`Mt?G7BcC8;` z@t9)~trL)3fh5C#131Bps*9w2rhEX4H1I+Gg?!P1tLn<9`!X+O^~R_d^riYzhn1Jc zK_f4vVG_Q2%t&%}5e9+RsBRo}knkn0#yu+^$^@<`^UTF%GFhg2tlDm%Y{0|XrM+ec z);VX993}s9c$D{1->jy+>*OzCJ;O*s;c%$d@aOj@&QRYX(kOwOZ&2IuDXrW zv5GS)lO;7`^f~)S-ss04_2WOzV1sxgHb^|CAIA|xK|lV;<8c2c%O@%ldz`p8^|8XsA;RZaDiQuf-haYc6MS%Wh0z2 zkZ5o!i-n3Ai(UQrrhP=_+XKhC9NFe9_cqa$kGx9{RW|hUPu|M^&>y^??GYc{zs8?< zhioj~dZqY)|G8e@!j!|k{1eNSJN1YSe26Gr$+Fh0@jr71+U`H#kxE5-jN*OxGT#Lx zK!Jz;(QPbO550?z^e6UGHuUyS=6`I^A7p!O6CbTvqx3ZpnZa^aimr^0Tn}v51Ka!g z@A^Yqf$hgz*Z7kNjQ}2^SUnNav#<&L*Xd-mmWbnNjPC~j^s`-wh>$~V*Vx8EU!zgc zmg>pLL!jb^3`Lgoz{jUf%0)N&^4^{WFyK^Z2eX(?TZOepTO7+7cW}Y3w%rmG_V`x%QdV z?!9t9sCu&@O29ntbE`}^+h#3cb0>IRb>41Sv z&Ik&C4RffL#Kn@S25qEc6C!2p_TSE)r)2AusWhq+-u3E~N^oF=B96X9ov?*~62OTR zR7RyHfym(J`t)@%QZL}YFsgxmA#uS|1Rp!0Tvz=BB@#W9X`+Xjv_39K3HoBnzPdr* zGU%&05jB#%YGA-)zDLW;l=Wz9;Zh5u9&MQc1FpOVGJ!B^$0S69<&t+11r~LZ(O*et zdItK`jZ&|^RJ_<2Bc6bmUmGu$_M_D0fepnK93q2fA#_$g+t1z;d9~4IV{qsj0&3xt zp6nO-CKQ6P9p%o4&tPLZDKi>wd33NbJP@%Bhj#muPomtW?64sK0BvJNL;yTH`1WYL z_U)rj@$H$pc>Vb&eWI8)8}F9em=EAu>>l!Mmz%B%=s_y|Os5AfM0%jz zj4VGly}%vgV2JsUo}Ueu>lkFuEjW|Z%$s>dLCf~d_}3ZUw3M6M1~#DbF=m>3*IQ0T98q;zKoZLh20kwB^sN*^(S37wUM_!&#^!HBpSEaA5j<0+wZN8Nk4s#% zubKiz;4jL1nu%vezef(@19;Ue3j%MzMa48^`0-cyD@o1YYU8 zu6;Iu{K^CVuS0^}k;?i=ckuMN;@-JRtiP42D4!`_|M*BxP_WW0ILNb7zjr>H4EaNG z7A%~J-wTX58+AMpO>VQ`c=B{jcJO+=L9JJ_KzVWzg^0W@;2Gngpw?N9s@zt!WjIEt&_T&1! zn2$HQt-iTFrs+l(_3x~Y49O{jeiA0_CnOO;p+V{-1Hn84fzS}9%DS(j-rt~tbufc$ zZVVrWu(3ONJ)r6pQn;L%TOUtI^G1*)tHdz@18bC%_^@av>-} zy_Uj2a*X5@oTe`iH%#tdHE96yI=%H_TZ90Kh39hA_zz`has>osToO3@=~7@XCI({# zHQSXo-w|mrd){`6R5L z987C#IQ!?QJp;3LirtG4>BeEz@@Qpj5}~b|5i(!{v*l;!F6q&8Sq>cJ^Rk!r?6D|6 zr$C&7GxCLAOL4OxHy1aT|DGgwUju&!h6CWaSMV7%q$QM(6%7`E-wn(mAZLC46M|q3|FUQ21mSw%h zAe$BwZ}DDy^*zeR2A{*E6C<_|L$i_9r*M57Y`$8`16BZEOlr$u>MdwU53vVkwBTSi zZ_XL?iIGoN%%e_mae4|v;-fBRwCcPw^JY`48W>yc4}1Yz%Ojo!#&*_rHWGpZuAFDE zD_EdGT8e3sL$W}*o5GgNJ2Ph z{6fd^NY$cQ=7bLI#y87o-YgU8ktiq6=zB|Zshj02mHJSCZH{J%)N`Q8|0<$Lj}Mr@ zUCxe2NiT25LoS+sNq3jo($sfpm_|BG_fY)Bra{t6>+pnbD=`JOl$>v6&x@Y=7xZZ$ zLYA{yqheiNE0#?zc+8B+iHVECzVFkvZJ)kv+x8Y8)=d)G#J0VAw=L*{qvUI+ivjd9 z<~_(wv!075mf)*8ddak)K``Gzvm=_P)=fdB?7Txgs;-xE4LYeQ$E3zle*l?et68|{ zrbV#d;&Y)`!a8l<@~?lERV zjBK=qEf*I?{3;@!a+nASHm>f-H(@phI_jUJE|<(tZ9t2V0r`0*d)}WU^Uq+<&CtJ8 z4qra6Q9ind{<+nFJhLvh=*2VG?#q--c`wQjWWNwS1F&b$@n*7oOUHBBl4#rr)K0K@ z-R|&W+d7RNG_y%}Hc+F^4IlQ6n}SYwzNY!ipMMS?7N}V%=fm?C{yL*-p)rlg57!UX zD>MG$G7&hC-oEo}hp4`Fhy!z(Ui*^Nl%^EIB`%J@uc; zuiSC0`N!D`M@NYa~Kwz0lCPvEqaPIvTRrOCtt>vNw z@rFg;OVpLhCCY;T?U=}1g1*no0rMM=eq{JC{lvRa&HSIwP$O=__ZT&z`gg*S1*Da>yld2maPuLzJ!Kn$2>Krw zaHuztG=u$PjXqd)wQ(U|+V4<#?P9U%FHC#5!Prb@*`Nu9lt1XhWTOQmy92GcOL0HoqM? zZc3b&nqz%Q2)s{6Rqd#;J*{4Etv~!`7QfHOc0EuMa%Vxxit;9FbM+rtkfw=qnlhI~ z;No|+tup@Vtk+?KX!Tla_K?i2wb8^cs>+;m+VHpA?Ae!nZ*yh!(`D=WI+wKRvAUo8 z3$0MI{=XhKoVR&fNou9M-9{OzieEH3?Sp8KQ&H4=5!*hQ>W9kY=g_WlM8w7>LDFS9 zu=L!{%tIg9o_t;teslNmIPZYi&Y^9pzwq^Mk`&{(CN5rCklD0JFZTYLJh!uJLQ+JF zs805YaS2@$ICl&#(BjD{kD&~^`V=e-v@#BYp-`2#zeB@EQCJ8 zbL@P~?#!Ifd3@=41xV*hj$}Rz;`upw{F+Rav$p#ZSyV(^X5ys2_P9ycl*M+5=W3$r zXz56gP}diRg=m_RwK}VNTm;Wt@z^1?g?hEvRv2s#^*Vc`gtDyWqEQbgD~^fQw4ffD zP1%v=nQCxKD_4s!HtwE(U2VhK{?#=X)Y;nO(CwU95%FS={$Sh9wjH*EEQm$1IF`i9 z*=*FuU65mk)gs4@{rCAWRoFH2TQR@Wu@4`eoc7_TrMscl8!^Ob?rcX)5Re{53>j$# zZmdZuGF%o&lUo4dr)5WCmwQfjET}`L1N%TCkK31wgXF<_d1xDoua%RnAZgBjnU=uT zPkTAAtrG#he$vaMz$7BEFdABS$FA(0)n&o3p|^EySx^}pziwF@KA=1%?z*ei zh#$p7@x$7oH^#ck%lV8{J8Q!1sj3>`Xwl3OX6HVYMMN+yg=^tKnazSCl&L8i3yq^dWGRah`0N4hx=R^#KeAceVAx}(H0B}i=)uLgH^ zsVoRdTwDp#+-}vu6_>(-f^bLS4%O|ZOy|>^r-^4XSY}#vM)S039uo%VK}vih6$xTF z0l`jKcu&VQ(t^4F_f+5qjBD{z)fChL_@$`az>h1-v}Prmqg%7VyjcrH$!w|e%$ADM ztc8fi`Scv`&EwYH{?SLbuNyZoiRbkgKW^;UapQYrC$O)k#ogc<{?iq4QB6v(f9Qc@ z#~yg-`m*>)_Z2^N7mE{f!^3kEm8f7P#-#*D@PzEhNQ4=P2vS`!YETqwotPUDK?xj6 ztV@*%A|fb3uPN5^6(HI!JG*WM}m_%96ThPt0C185kG57!|r<-EXYz zM%yj6jkZT^dk_WvpzX8`E`iMLz+pf*N&wv#eUs;Va6<-=>df-9SenCy2{{5^Q{RQC z!xW!p=$E^ZjxgGnNO2JiM;#0!3*_}b1^Rbc{xhaV3O2d0Rb*;Z_o2?TroNVm!Q~TM zz1b&T4GC>MCaugFmpkEw*id^+P)K7O^Axhc9jdv^>uY1>b$qBRm$|5|$VX7xW^M)v%Nc#zQaG2(fuqOwr?nwJFPjIN_ zj?|1_r|?Ur3|8VI?D|{ukTQmH{Cu4r#zkn!025(nOWnbtb~hdZPL%ednKU_=%6L6a z!m-Pw4u5YX1sp08pPT6yiuO@bZM!EpM2iata#Y3!Sw=WA(l4+j^q5F>gPKEj3VHUO z=1SFE?b&0?Zf1{(hi?`SiHDc*&Fn5Qsaj0FaDm+keXqSO26@^c54?)&auq14nv&`b zW!?t)TaQ7o+~_GdL+|17W5h%JL3XE@Y=Vmv@4fmiE854}igyT~cW~TLu=Y9GB@kRK z#({86uG9h=K?+#Da-ba#))%m@igwt zm&3)1;B|npdcF1)ohw0S3)BY)4kFSiqev{WAwJE~5L9h;bIZ6%AjyZTiuOFqF`-F8m+&)vrF zys~5af$1gPOVW99m3W5rsk)2B+p3yZzeN~$z>(K=bXlg__%re!wgu=v3GDES#VJxspkeY-VOC<@qRNYOt zTG6kdU7tSF`|7Rwv@7V_7eADA@%UeVipPgVM3k(&2G!{{VyLZ#O|{hw9oVUO<*3oO zl{j4$YH9JPQN<qiAEwTWc&=60M1DA2)e0Ye%9Tpmuw5v%I{pXm*jbm`ZP9~;> zhS?*XsbQg_XH;r|)pGx)W(>cFjr)4oD5SR;;uRyW16TU2qZ8rkflM*r`~V2CsWeUN3<5hshm@uPhep zLtPwhD1zx}1?;oQyHh)-=Dkyr;($t!A08jZ@^4<|NGX0d5BDQl=6StOw#m?LdblRO zY0bk6?HO&JN=nLWp~TbrcJ7-rc)f{>nYkTaT6Xh`FW$WDrPbrtj~~DOaC~Zfe5&xt zFZN|qdc+z=UI7bC(_qKGL{BBQi((O$b2<#Hx#_UI>IFts~V@DY_I`3&3zZo4ho zsoA~J&S<-qEM5hZMx}&?YEh9XY-Ok;0zYsoGWA6Jn_9N${*_q8W`5PZMa!Go?+LFc zk6a$K{r>*bvA`BFz5o5&gO*2@SA=`KLsAl_CahaDWI_yMF%yO?T9+_2F=dEX%Ju7P zsya#yl3v@;C}92ZraQ?hJX84@Mlp|CrVLgcn%|+S%K7g8yAx z(yamq)rWQze~8~%M;0pn>HyIS3psSIcWqazL5Md^n@Dn4KFfyXrnVrMmslDEXc%j* zI@G}wL})0&@rqZKp{y9Om%Hhwf?0LcU>*L*%GKPXpB#$KRIv_7hbA?Cb(fYW$Gdn$ z6mJ0u(aA>Jr*dd!g-KEBMHimS-wAm1|IP5k5_xQqnu+tQV!EgqY#x4T8BZAZ<|(mV z)XW3S)kVuF;<(Nb!!r?cEceX>78TwoJ#j)`%`r1yg$b>^`7cPij$$SN;+Zek8D|BSR!|1EH zVY2tS;k84jcEL~;(VYipCk%~RMx5vTz z9XQ9dxGwsTc;5S&9^tD0YVhisFhzWq!jijTvvA&BADCNef)rf~ zZxN*Owi&9U6<=FW-ll)7Dh|itaK9JFEo42~4v4yW zrn2UZoY8UY-&ye;2VPs$C9kiyIhJ~%L$<}-;%@CbX?MmcaW04&7i>CSh4HEEWM^Le zu-cXVCI+`tp3fIUweQ5N>Sq07Hv%^?vOWn&SZq&caQ1*$Vh% z_FGrZv5B&n9gEUFLFQK#@e#n9x$Ylk1{pP3Zm z&dYZ?TcwXENpO2Z8V~qhyz<*`tn2p!8i#n@2_+-aTOll7o;xHdQ_?YuZBg%6XWH6< zvyE9LhFeb#to3#{K;*(cn~jke%RA6T9VtpKRP$rEXjKt?}g1U25gAU#_VnOGSd)dfB+d}0D(YK2+bm7@1$unnslT|n>1~9 znx={M=KoyTgrrT{uix+cgZ%Ds-+RwJ_l)P9J9HE?C(}(h!_kqDOA(?GH!b{yJzcL= zD3aKzF0IMn)ovk=`7@1LC9tqe_>w)t;L$NN#2EdE)s{gNd5Pu>xs-)v!kQGDVV314 znKELc8EI~kIn$(9S@V*I%9V+7-857#Eelo5PW22sR9q^K*^TyLcYF#l`XdKvw>F~V z4_z=lH^WA(cB5Rv%+PrZ8TRlcO!%!&f@V32&!p!*k2anK?4y_vPiHZzcDZ zm+w^h%FB&)gwz#q+v*9azl40(beFi<@Sa*iYMH&}Ajx$23W<+d8=sWU6c!W~7L*j` z6&2>2NLw3;CZk%3a#S0Uk7~;yepk4K_W$j$T~tDcw2La>FXQ1SfVis;qQGjeIyuGlMrcm(TT*-=^eAkhIo#TltlpKK$JEx;*H<^yRoB^mnbTXEepFt(NhGjIZNP z)785y$){^!KgWb85Hex#m-bR&YjRN?Lv?yaq(oa>;cP=~0V_-(8+_hBw4!@XyO*xe zJZL1bo@Cl1ltk$W9g-4}p3)MiW{7xnvzUbPa-V8vdHKB((YNL0!tZ6wobvMUTy2W* zcAOXB*pr1m2gwYYnZ0$SHoS)=?s`&(xiT-&_Swc2)DvHRVNqUT32lf%COs)WJe4`? z_Aw!}hMcsGQj*p-CYm7W5!&I~f1n+%43}T$M>~cWY$ut!1{sU(yC(207s%Z2*$T zyi3=oxLUdrL7$StuJSndFd{bBK$F@fIwm>;4g3Mo^P*RvQT-i2%lDfPS*?0M05y=!B#$IoC3q88ow26B82O334Yj>7@__{ z$4enLWJ|_a;|0S8Q;Cc?T0bybK|I1kH7LCsA~Y?Bk-F0Y9_o^%uczhm1~5A~Oj{vb z7qP*^+lCPU7wO?nbVzt~n~*+)<}pHx3wb4xzoAr>^cdtrobv~GoWWE95rM}O5Mw5I zlp0U)I3;eRIHi|*BbSFFkE4%d7X5inY6Gw3mOJ9anL%A<#e*5=12uU*&Kua3w|-Ob zxW^HloL7-|*L$tm;vgFz>q_s@N?XiNHwvEwcw>}IrjW%d7iBk8OxhQ#Gs}!xBNse5 zd6ZQUnw2CrMV4BfA4j?lbCw#PpZOX0s;1Et5G(bG4~Ao6WQoq2%!>_&wB!|;*E%tf z;C{||%LzLl8>i13o3dLfb{Hf|EiWO-(X3Xc5&o+9t?nJ|VLcPnuwzV0?Mm$!ZJtS3 zG=|USWy-)}vtlRH7IT+JCC%VW)q#90}Zl_GvqFg3Ui#7y1I{bW9UB}t`n~cJhuFleqv?Qf# zVW?kLADiaV$@KL>YvIAwN{3o%N!+0;uXUap>3A&j&X~M)+^VXmvK6Z;g*h_-ZZC+> zj%w{tJv=U6AH^vrMc3=g1J-DMZIUc~lsjddN0PK&c>ZSj;ZRS)jsi_hed(lz_&Ifc ze_cscFxmwVSYnh%p2&HNt=S$)eqZ8Bk#KdlnQ>A;;+KNr_rlz`_HkaJq z=2vpJCGu$niF~5jD^AiS@kwkVmlTx*&?Dq0>9^l-Pw}rrY{C(t35m9KMmH6ModAwf zWhEp6p=W#PF38l+e6etRa!>euX%q8wiDXo`eEnF%Jn|2fv{@Q%O_w%D^RMh^XxchC ze7vaL{PHBW{fRSy9MjfWOeikS&}@6IIlcszH;N~Zg1q-M_bBWrE>Wha0C~U1qDb(p z>jCgXPh#{r8;!JE>bTa@nS@c{j^|6PvVpfd)PdhEPVK=r@iC$~qhdzdO z?xBweG80MYweiBYM^BrDXMfd9GzZ9in>T;)@YHv9|BUD#s)kMC3&WQAcY4#sN$$HA ze9$1={%3{iB+tY&Fv4vlHqLo+ig36*O&7Ae#ii-$d>eN~cxC4q;o}#Uki4C{j70m3 zncM0<88`|9<2+(szA1*7F0g|s)g(FAB)nS1?8%8lL@b~3l|M!coOv_vGnhy z@t(XCb9sCMm!FQHSTXc&39tqk5x<2M(si?FI_d@XAdHdV&a8*BXcz!tVWdM1OoN69 zFGI%tAsLrid%%_uV*vSug#=8o9N<#G>Cy-UZ$wOt_$q>MSL3m;GGUS!F@g^y9x?M) zCSVU{>BIs#pS3jAs4P1d&wqwerLuPET7qu&nYtx z&08eN9Dh+VXPsoaHBTEb%xOLm9;a5%STL3&BPLyLuDwz#vx#?Jt0gV05lsEf$uFObQfa~MmS^8 zZ48F!dU%lltF;){M;0*k;rRgLdSU8Ahr&z^>2TvloIQ|)K|g+-Q;$jSF>-lWUX>%A zD@z$u(RQ7;`T;q!u4FgN=QoeFC`eORq1N`6%#;B2jmu9?%E3r%V-%*D6~eb1vpA#q zMx^V%p66z!)yhd-g>W~+O{<#pOpKJNAl%lj{mftf&XcKS75m8tEO$IUcpJ~0uBfOG zjuH6-h5qigiZQ9cULF>UkLOMO465)xb-dbQQ6;F!ff-4$?OUfiy<-;EsM2zmWRV=# zM8=rIdNi$lLyw2(4HEF7v24yajRgs@#WZaWN8R?SOD+(8VIkJ(I8Ad{% zV6=L@$LlueH7rX=i-D9ij{I^S`=ZUD>GsJI6nbMt47(sVUKOPYs}gd`ZET0h5jEJC zZOZn<`BM$>?y9}MiT-0FjM!FZKY!A58_j|503*ggVkr$>SSALdnN#tb6q?matA#+*CHa!Uq| z9^8L?V2tqc=sm~wA3Vza<{ZPE+c|IC{GR(hXPD2gbX+I=Jwycg&(56r8TkT0cIkC^ zH!E5O*>5cWYi!wIGs8?Mh(v~%gDKVYembcdNS8&#ZUAOX#O^x-m=rm(L9^SC!DlX< zT(wFDm+jYV`zO<}~$ zKGijCS{K}5zB|vHx%1RL_X_7o*FBH*zkCmwCS3R#-zVfReq-_A1MD*w&z-+8ctzMF ztbFy=ci$yj$rOAy5j}@7nCG9TF%J=J83aNk%fJ%TRspjIOkN0|izTpQ@(bd#V)0oL zlt_eU#23WEb7C>cKEv~8_~-dU;=SUz;)DF)CRjh0^9QlBS9~b)ju8BOhq&&@{6qB7 zPE;Mto%993_yVy8YYPq_RStj5ucv(>mjsyCC)$yG{DSOoxP2FQ269TEm6!`@$9PEB`F5sHxEoB z+5O~ehR-^&F?;(aCcFO*-n%wa_;~9r!b1-frShEy88P1ZJX!pUMq%bTw)cc`_H6cC zF9N1%Y*-W)PjipJ6Wt`5Ok>{(m6+*Y0N)Su5!3_l_iU=s`Sh$m2(>nVVU$`EDZ($J zI!IuUK?!jW*f-?(VjPC75@2B=_tLL|s$8* zG@PA_Yi>4j4mNvy;lQq!?~mn<+$X&MB*W~~Y<2KCEhip*@C+$Kh330i-wXe#v08GHw@M4ia0L-j5ttfEwpL63#46+&YOkW3W|0gh@- z)OSF~II)q!86e3)`J#FfwbLT_4we8v9St$gqH|M~C<9Om9o!6f5GvA5&taRHURbAA zEXwdd&^u>+-vS-?+LqoLe{Vb^_vVX(W4OkyDK$GJdG44UY)akC9WV3R1&`;=nf<_< z24(YueO!roWQLox+6p%E9hHjt$+dNj7splhF5Z3N=IQE#9}0gL{%}0WyxE-`jPksh zwzYg#Ff^lT^XR)BOfdg&y!#lD5#OsfsOKJkZ-0uaw{q0|XFKPs%Y?*Dm6O)gFEm!< z?VHiDYGUpoSVhpchwu)Lh&^mbB!xLILRNYfR1u`0RS*vd-2;gYG!MJTuqKJgFPT#h z-MO^;$UJ7>#c{LY{icdS0N?93ScfaHO9dM+7*&&=tvHci^X+fVdAaQCvc z3-)z2u)@q0VguXqoRj(|PJL1#ARZi(z~P1%fcsqmC|Ie3Nj` zyB`Qoso4E$K9aQy49A!SSgMyQLKuAhJSw!Yt!YT?PR zx9&Q;+MbbNr#H|)dq$@1YvCr+i7O`yM}hQ+6WzgG;GHOM5iDJ`kjqCScgAGVG*K_g z47wenc~CoS03Jl{Kxhm>4hsYU2sT30qt;vlwdPU@5IjT-QOpZ55Yij`4>&R;*rCR; z4NigM7=m#ZLWl7j%*>9ZJ9314;BifJyWDPnw#y@ArKF72x0XgXmUJB~EZjM>s5z#5 zq+u+MD%;Crnu})cEG*nHtGGU zEAHG?Sh!_MadlMj&{55(;;8E4iMu~gM*TuvurW$`xKJhBWYur1>q#-0qpqtLPMK^m zv&$c{#%*funyHBTm8oE@M0udVMCpPDP2P$*H?z@)C|zXIxh}QfnnT8YFcWBYpi|m? zD0$La2SCxOadTS8=flGFRVcIl)TvKDKXvltsn0(>b!zdJ{>zVS*&=-O$mRYmS~13@kK*`_kvz|Q@cF6Jr|Dg|_tS^BY~8x$;YW$8zhC&R>^T6q zHNxMXIm?ah;3cCwxZ(Bxvh09iGrWuS8_?zv#o&KX_Lpx%+2Pv^EB!5`@qb?UCDP}F zPZU}rdxm)brS!B}r|* zHNJt`4gSv}93YZhr79Xs!!*!X1dcqAdL<)#;_*!Oh?88nqgr-Dj%P=cb#E~I4v|9g z`8&t<4Fx>#A!d4eW+dR@kqmNc!n&p|ylUbLZpurD2 z5&Y1oUGJ;j-lBh%FXFHM-bC<&?+MnCL4zMA4Btmy$?3{+w8vym@hzh=`w{TZ0RIHE z+!WM<4QQ%}{RCnO6iLiH@1b@Zqn^%3591(u3&kp_U<^dVY$Wn&!t%TC%FJjYsuec~ z7dLfWpGd9<_a=+mj{LF3BAmMEF#ou)+!6Gbt z*Tjw7|4GMqDaj$EoAzA>TD1gGBEK6dliLPkgNg)Uut6~pyb6(zT4zx}6fYE@T~`7# zjtT-8dq`L;d^C-0KYuWhsZWc7_r`7B@Nha*(Q%;W#5#|&%H#JKm0JW zZR*OE4i64(8r9P4n%y#L(@MwJuHKeWqerh;I(qb|7Oo)HvErU{izX@_hcW8m%i|x9 z>0ET~o)wN*qqFZ^lx+E^Cb76_)N)zWxjtvRxT$T$@|Nc2mgOtjXh0Mr+WqZeu7oeb z_=EmPt(Z~C@Z0Ude(Y4c*Z;+|X%dbp%L-B+6%aQX! z1Z%Wd72&-!rY?jxh5Rs&doj{c2{6K)X_1&2S6|)L`4oBiWxVp;-|d+PMtbG(ty{Ov zV@|Y>6+ZjIKEyr1X9B-U-;D-} z%oq)qXb>|oMvQy`ipWEY5jR4%Bx>5e%+2FgEbkaMu4C2e@$FHn^%uycb!(aR>&~Aa zL(IZ&XOnevh4&gIh)W(vdAERcx8pj#6q?tpS$mPauzsyX+(J~$Y+=n@OwIRk+xc^p zjtDYJCUaZ)GZB4_#u*K_1mb}x#xwHyH0v={vB>)in$d;}=eIQP{Nk>2%a%`lbzoqy zo=G4rE$`CCozI;4a>a@>#}={!U-yxz2nHjtLnU)gJRcf4Vum8teN0p^{AhF&Cq6V1 zf`isqJBg;dd*F^crti9a-nt_@@+)<=tOtWv}rY<(czeaNZA-|~zNJfBOU4jv ztz5jgue*O2NjP+K4vly?Xw_@C8)~g-H&btKsg# zoZ0jHXjvK2YocWKYqXaJc10kUY{MPEt{#e{qp&N=bSatq4(V&Go$(*$_=E?U(NR(1 zq^K>#zoJ4Jb%V2kKl6C?xNpX&!Y@izL`CrnRtUw*W9ts*s6Z1Y=I*mhvOsI+2CID-oXVgso^UKF4HB2g7G>t@e@*K-|lIZCR%O*7>PFVIl!^AMR z3h(Y*xP9TR;f@riGle;ED|U7gOL%KKyBm1?;KU|j9_T! z?LE{x`vVxnpxj>zOV1RkV-s>i<%OgJx8`)xgvZxsk(~U8adO)v@qVp z1x@idwe8B4ZCko(swv$S0;{(dG$EtCL=?e`qJTz&Hd0uCr@@P9qM=ATX|4wCQA`6J zZqaI#KZ9omJ)~koZmfA-Sy_(R{QP4_4_yA1U0ggSZ|>wVs|I&1oVy{(U{g5Krc8M{ zNoPu%x^S+(g_QW$mzL(4&1*}`nHf9IT{(P0s5&~EZ7iNXWAa&Y+o{F7`{xH%2gh8l z>Pbu-Gd(jaklme>R!km6QBn2`;RE1ARs(-dBPwB8i)eXPcsWqdkY98ZniZKD82)N6 zX3PZ_%BJ3l$Od8+jYR-p1Ob?kIKUhdMjXy(~QWx9YtKeT{s(zWg?3=Vyf6 zc0)Lix$-59#Aj{|SF>f;UthSXYFD^RXnmNldwaQ~^czNre#Z52AHWjgr2QU7NPECP zOe)|%I1q56eo^sMT?Mxq#d*JZgKQTT4rX55u;IQ;q7#5%lou|$Ygu7*49VL_CTtqF z;O2MUxp~33O`D>XwKHb!+c$GYtuh*QMnt}Er*Ox(C#Z((hUW(ZgApPWRfD{&X1I=2 z|5Qh`HixTL&9+zO7cl+(Ou^=~cwWKSJ?+WedQ;renCqr=Hkp*m)03OxHu#c4e;C(8 zx_0bjyCxTOF>67v0}4Qj%!&%)@0kr?xfcFM$LdU|4i?|OPxFgUZ@=kI>H zk~Ckoba(sx-Q76;%&ZWO`?GtVLHrF7O@ywn05%K@b`Y^C0o?}d3^8i7evLLHVu3o+ z5HF@M{>3Yn&v%m;lMp6stnkI|&n>@<`(l^yg$a%xA#5h{-Cx8p^{nu^@E!y7tm*&| zA=#|(zVJFpBqmmPPWbeI@CnkU5@0=PpXY&a;<=sN8tC&j@Yy!RS%_fj03U)&3*rYl zh@HZiD4LRH6pD;91f7T=Z`hER3e`A-9g7GAL#_eJ&#W+`4Pm)(lRDxk^Id(6f-ru} zo$Jk6I=8eqSB+@QSwyT+=N6UBE6C6Fn&Hv9gQ*Cwv{?fq+YU4r=2=X#nAXgU9 zWXUgRKF~HYJKiRY)jHK$hZaAzQ_Fn7GIqVKXns-A-1um*I68iA5q4~P%>FEtzW=`P zCUMKuN&82(9%wN!aal29HYr$E7EA)%Gb@fUwH#<2xj#uQ6W(O!>TEjvGzdzdE*OkL zqoIJW09LIUh}V&@F7*Kib3$}KXwKuMa5?&=Vu_Z8>GZq3IE;%w*oy$`hOT6_U`ki7 zbkZaQd;sQtD}$;vMy4Sjs&Lv0@p!ynJ9ISC3W}lH^dr8_;76riJxH62_*vg~&2_a6 zwZj))dnUc~&Kjv9$$%f5dNHwBVMsC>5{-;=m)%c{iF)j^e(O$`F-dPsGDMYCJ#IH9 z8t{|Vtq9L%rfwBJ*v_Pe@6A8Q^9q$JPN^`fRdEWj_@ik92xC?%;}ps`ES1PzR5KPH z3x!pI^NKi?Dn=|8KB{*q4DD%B;XaWem%*a;Dng)$6^6 zEESS2nyVmV;^#DnA7d66-3Z{(c@0V0@HQsovJIUpm52XIw#M0pZmSlK3T@={Z%*f? z-{fAkif}fv2a(ZncmZCl!pnsDCT0X8pX02ws91y_)ghq@HZ2N;#TpmIGT{f9Rfq_t zSL2gZ<|r`}K42qD82SWy6+Olf^rg9=kx7W7v%)IkjpX$eL1U%50)kB7DT^fSrw$!B zaUeYFk$o60$q*KhnbD`bK!YI}#fP8m|7%ZkbI+i%rv)C+p7-}L6@zn`x2wZN)g{dN zQWAcFxAyn%T(w>hty?)TuyP|A+^}kA|2Ic6Guhem+uG)bpX`}CwIrtpQosH7 zEB15lacC9gq84x)$ZHWPBO<(GFvS0e;4w^&R7$7h0Z~pov>6fHX|N_FewsKQzCXPd zV<;w~rxa#n?IIBARYDY#E3sy=G|TEB#NjM4n)C{dyToZPajRntMpLoNNr*EZsUu^} zgn4i9!{5HOW5=W&J2qyyiz|!W*%uhSaDyo|Bh6?^Gni6HMQTP?ib9@{onOk96%;w5 zr3#bH;Vg1EikuFcNf{OGC@LspOY{9UxgsSi6S3#Q0{~EJrnL9;v`-N}au+yD9F7ua zcAD^KE+aF=XiT9C+OIkEVlh{W@i88mIsCMjlOU8W%7RfxE-$SBuLN>7ByEc6FiK!B zf#5*3+W>3SNt}*Cf}zhVh9^a0K)r<|v_1`-5r`dz_#kaWPBN0{veP~I7a6IN z)TF!DL^KZ4_m@fPy9G8}{?#t|n%tD1G)>HbysrKv4aZ~k^-}bw$UXxt7 z-;yGa)g&^BjR~W3;+k3>d$>rOR}i&`-LdTJsmaNNIfCTZvY7>Aix6lFVwVhqF;v1&S^8F8FPB7p$VJv-wF^5lC8S#xLP=1sH6 z#A2CcS{`<+x_FimCcXBW@Ci{#Ri5qj4cqGs#GDqxGhSa|q0fty7infH6 z*C!iOwc&22-QzIO3k{Vq;pfOLan7OJ>V*8ay42J-@b1z~E<^KWl^b7F1n#KAEWDZ+f>Yugy};Cc3Zef{8{#*O1rSFT*Y zXu05CwrInKMJvebD;BL^`ORO_(&+mcV0^{w$KaFMA`~c+LE^s|J&4g>Mod8KS= zL7^i$N@=v&orMlZp%dmEl_c6xSb$S`{scMXUJExq>XiGyTUI;rN%y2O<_U{Xosj^!2Qh4H2sRmn%|GEf8}S_8Xa3*SUF zZffBj22((as z4Bxcnop&=vl-aj5X)ehAyn^rhfUTK*y1=vlc2d~SL}*cg_dUut!2U)fTBvasraWro zr63NG#5pA1ptT?jlOfN&(*X~XbJ!?M3h(JM^0En!obFDzAnf$;w{K z`ZSV1Vy`7pv!n&2QRPSgR-b)8b{3Jru|}b#VF;xK-6syF3OIU z^D%t$C82-*9OiUM%stV6TFv);+}bq|%#LPmJxja=w+a_$_TG>xxhHSg7JF>$?vsBV zEYa3h;2Q|A78|)IP{$AlBXvxDOSEK=RuJ17sZo-Dd#96Otaa^kPERwR5*m2HxAoRa zzUh(rq>W?S@2ePhmVPw zj_CQc9npiyVvI%{Us1bm>j>FPsr;m|GtBxM((DH-UN`!T{OCJ#GiLW|`E%)+ zca4;Z-;oIK!iO^hsFFY3o||!{T*i;zZM%K6Quuhy?J_p%Y-m|S!smv-m?l3m7EgDK^9Qd4sy9NAC0eLhPBR{k%z+z#XfLMh8LH7@L`5*3T zBjIAm?h#>?$f_oW{AzxaNavLwh zxfph>`q`O%-H2YI#?#YA+070CTd^6%u3cJ#}!pIeHJ1NcG zEV6SMxF6mQc-@B`eqar>$-Rgs0=NrME}v1&1V={2-tx`@&XW7u7~?Mke|*Z&(aN6` zyZ!lP>$h~oXEc?Sdt(PRyONLg=?gf_cM18olbgz)fQ}?0JjxbPdLl(ryN5~&BBS~I z)Z`6jJM%OD)3>`@8p7Y~ERKElcv4#(f8t^8o6z-%hq)y>HpISsY|ywiAh}+$z{VDH zJ7^m-`0hULGWww@Vg;iwfh8pbRtC!myu7sZcs>x20q#Ne)yvAu?WJtENb)56%PS+R zYnUs16Z_5QcdIwglV^d6zH-XCdumKJ$DCZVCh~kzA#$@j;18l%7-HBB65vCSsieWMO(Y4oMA7n+bMPG9M4|E6$|ep3kb78xP(kA!t0M^7YrP&$+9q`M@tQv zRmTUucY?W#G$;5|vI--Y-Egcr%gT%y!&tMbkKGWttS~FZpU_N%{$tfX3q57=RUbp0 zibd()eu5k~N^Hd-pFkY)IRQ(I+_O;91Blw9R*wiy#^`6AIEct`KO{aV{Fr8mMitPi zrY<&&r&t<*q@THD|`+_z(N!QBk8mUW4(g{EFBzwI1i6k-4>q+v8pSln=b7s_q zr+UYa@95}#>VkCUOeyv{I>wLh?V2(rqo;>WPfYYAM()5mk(AKKv<^Pis!LARF$a6c zPw42FBW$=Jn=wOnf%MJ6o#T7&zesm4_H0WO?k3HN+d$13z$xF%HRAi6;FCdEcp6}x zT!Q$|1IT!C7AEV zmwIU@84?6}392<40zfgLVg10-=`n}_O|2tosfPSIF}DHu9YxVjxpRzWRI+iCoc$xa zOzwF3kor)yesqj7{KCcM8TtAW2lKFE9#^Qg%#m(MTGEqbA+DOc!jCH@?Ou+n-xAGo zJfq&AELAe~+$04vmMl5Q=&Q*eIhMrP;uwzKr#0_mCF_gC+&g34Tse8VriK&Wt#UO3 z$1Rj+a23WExW?er6#kDeYudQ4lxmifO?F3p9J5}`yoU5OMEEqCSufo$WB)YcSG|qT z#=K-x=J^#-pRv)uY|^C!R!nZWwLr$D{>7|{=k$NnL4og1NaHvwCu79>qjZlDshC~= zM{aB^M^xV$Ca`bG*nXgw*eO=2ccOItIuwE_B zkhfO$@0qX?cGI;sOJUk6Oq@{cJcHeDHbdq+GqOCFr+sZfPKZ8^QmJXd0d& z$EgH6LvASeSpVZ!XHawb55HPTB45pvd?sv3zh3P$2a+8%#la>=$Lu(V?7HwD6XFU| zZ&#;ODa@8p#3tMkNV2h?6!b0Gw{J(1MxC*1(p~28v&$+9Qq{MoRK=yHdUj7bWl6M? zqOt<#Jf+pEwYb%BjT%K&Zd{g4+VFlT#~+wxuD@tr;dQzAc_wY;v?%|~8NMiQO4Zjn z!mAnS9=006yXK4au`6u6xc=)LlAK}07=!w#K%4L2k}*aU!uD|;>LViBz?JL`P#*!9 zGx{!Y?{tG&*S@PBD#-p@iugBm^JP>;-#mAtFT2`XURIdf-0IH`X2(|+1)H1`<`jfy z+AIZWC)KG{O0#t|aS68ulN_v2xN7OagFBNon#}7bpN$JYw!E?+U2`X@C@syiXYyT^ zBnJRt1u11UvY19gjLU6vm098}@iJvqw6rAX4hlDgaO~|*i64_d zQbW8m01wN5s*a!TAk5mcXO)}Bk6$YMMtI+0Ey=h?lU}E?#CMQ@Fp!(# zK&npbKQ#4{HGIpO+LBD|J?VAU%*@2Y)9$mTxR@o6kyPQA)w5^U2*1rQ2<6VPv^-{6 zp8`YivRHlX+^En3=r+k2bu@*}BR*deyOGS9V|lD4ZoPw(j1>NsPfC2T`Up)Fp^xlA z4n}K)3sB6Z9Utj{4g*q$Qusa6pcL`H`SRgTLY^Vje+S{#F!xoC~y!@D#X4kaCT%BE&rx}Oz@&W$r%~5QhcVO zQid-}Z0+i9o7lZfV6@Kd)3rTbi zv5@JK>{;IhbS>iUVbpAH?H}SxV6b{uXstUuBJCCG=FX&Dk;5|L=^~6 z__7k&#boyExJO#dYaP6#S@=gj$;*nxh{599MEJHk$Uq{=}&6>Uw%k` zUO_Ntc3ksie1OM8KcKo-5}G$RAdP%LzVJj=Rua2}^v;TVq}jXB-oFLr9s#h;DL&WXb40w7$ZU%g7K)P zkMJitT0#KRu~htWBE$EP>;+qdiMUc@L$&;3x$tcbyVophXtKF>J*}Ioax)wHn40ML ziP7sd2f`g|NZT%!;kW~0wm?^Rih*G^G1kEB*O+c#S5QI;Gw(>$(|GSB<)hI@Iv1copC!qg zLDo#=C$rpoOL_~VHh;5Hi6r{I?zzm!8yU5U5nr@V zQ%m2P5&c+~VnV0!PWHL!uBCZti4)!GbE$sqgO2-Nf0((qlApAhk@M9J&GFL81opSI zzM{b6IK&W6jrgWAK=oyynJy8ON`eZbm~$sW_9O9oz<1~4U=TYV927%ffcQt1fItX> zzmt*`1bQk2qNZuZV3q+$`aoFgaXuTwJUo&Wam_ zC(l$7&l+Jlku6^BB8tqm7H`D11w?@|2L&(oq9FL_XzL3&2je?T6w}v6+Yc`RJd}soEVp# zAjNkVho2XId2<-jwjg=cjWoat(Gj zAbbvvVI&L1bOwGn6KFC}uhac6wat<3vun%xHj*9^ythgC?aE`qmAh+5%33m~udKFr z8^Z{PnTZ24Ch_dDsY@nJS~hhl!%dnoFp)uWVa1YlE}}g%Lip>l9m4A;M=(`Kn8SN9 zC*#e+hnsH}9z0h;EGup&<@Xi~UF_b&%#rJ#H|!V7_moXoLe{M#OD2@N&2Z`;j2iTLNn%fT+6#*ccG?ynllHz2F;GdIax9neT5{>SS+ky)onuLM8km}myEnLz>%!GH zK%QB{jui{HI#);<^?*=ZUieL1X!hg1v%0gB9tz~uY^jCr9+DtMAJI4uD$Rf9j1tb^K~cj6ZzIP)W$k*GhHme0bE=@{wwk zPZ=qCf(={vXVjA~{^@(@onh(KLZkol->at#SU2hrHT#n#r_n+`R);@z{JXmS(Jy-c z+Gkw*v_D_lymtCOeI>>PwAHoi=`%>wzx{MEzMFtPIzS)vyE~x`(P-D7_`;t$?*1>Y z|MxZW<83Tt{P4^EXY|0DzM}$q!w_W%bw5&5L(lu+J1F4{)6liM!%^1=NAgc}(+P{w z3ixyWzt^DTr)vCv(R==znnl)_f5#qJ%a4$oQ2$-cU+a_C>hs#MAMK}4{YYC~V>pqq zy8yV7ecb5pXn2WeK(q&TyPs@@pQ2YpY5!=?{=cSs=Di=S#!Q9M1m3Hoz4+SJk5u^o zWe;Iet~J@e-6H8fa#|2wJNP3Fb*)n|CD$(eZfo$JYh4Lr6-G|@rxwB*8=1eEAbY=x zfy0SWXk$9@*M{ez0H^?SdR7`Y<6kP^dqr4wt+@y!b_t>`_M=oHYOEc}rG4|t z{sG#K%=gYohR(X_733bFfmu$M`v(SaB_rAoUrj!DKkOc~-hx~R!8aZW#Ck6^dIezy zR*PN0{S)_QvgWn34-Nc6)m%v4EPVd%=N@=Zn0$RB6PI$olYC;Ivev=WrKITXeRBfg z!v#+l3v_w_Wa8ktiF`bCQ<3(cpLwB-{I%>i55D#6KZLRy+qh5C(~ZuJOY_1rOW&vv z0D++Qd!gH&)$4ieY|1E#)QcU8+LB^_@j+GH`*pAGz))v>yy=wYUTFhGE{d7=m_UwE>}kM=;3C(+7q>q+^I(k7C{)vJYETFlw?xzawwAx1>9ZjtB^JU z&qeYTFj@TfhFC8>BqoElyaao$-H~gH&$Hhrj<+!^FW&Oah?wXq<3C35`7_%)>AVYi z;8SvX0>SRQoGgQZBnhvLte;uHuvK51s$`1FRTJ57ZFx5O%g67VKLX89NMn^ECO~3( zviYh+o0zGeo+OF3^z=>%g{JiOAX`z=^za2~Tw)c=WcLW42VxXeiB|OcwXp9rbF;A} zg#`gqJs{FpVxZ}#JOm54zww2L*nma{M;AT@+Awryd=6>>3NoE?%orlb=`A68FF~3K zB%Q#;@q}hR&>EeP|BW!g;|5OQQcBptb7G}ChcUgBqpQ@8Sd>AyG+U5e)L3Dy_g%c; ztG8A*E+QH6Ic(;l5!woU&db6K6ZsQ)FIE_3A`fyxwh&;+!ylKq)d|ZsipQ6J5J#RX zX_stRmY{NtFv&8-g&E>ZnUoxRH#Kc+sGrHS#S%7uRkGM8cmMj=Zn;mKyeb%Fh|6XA zLu1oY-zD$N31b4`IRe}}j4C?(8KZ~}e<6IHGJ@oGXUQ!|L>~W1Vw^myJC~G$v>`)3 zfS4^k|5x-s15m(p9wy+JevnBF>0=^^#8?*`DcGUe!FYgz;ac}Y>9jQD5?vZ65x%M-%;Vuq+rGN}wFe8fB;X09|g zHVTV5#V<$X%$-<2*@ua%J_BHWKY%!L;q^w&U@|2eOvxsbj{8}BO7u5-%d91tj?$5_ z874z!@sd(<(LJX-qr&4)Z=ckX5peol4&h!*1179hkwx0AyLhf9K33z6De-44+NvtF z6*_w*BrTeZ8h^;`0MAH>a{!8xt-*N8%!xT zC3+s5H0eR_W6bREp4{BXlKF>C6Cd8^PtOblI+0%{d?33s5XemTGcy4Xb}n4_*=GyE z_YA-)-_Om&+Cll=_ccV?g+ZoX4beJT#LFU2l~YSz-MTo*eIO?;#@0FUj-uGSnJe~< zJI$W2>MVY3DtWb}tC~wK636%D6{e)lNKGx+6l}`yy#ZUAU=<2z&XLI9W1t&GR13P< z44xPR|CH#57-_BEZwQ7k)fe@#hCD77lRyk5b^}wP<11w!FQzspr!=RgH>M;t-^y=% z;(*W%bBa3=gwW7%=Ji$L+(1Qr!g~8)tK`aBHGtN4c|Sr}$$k zYXk9l)?jUAj6Y>|w!6(FU(NHY<)*f)r-RnK_y9efI*Xo;Uh}Q!7s4Aay+pj@dm9>h z8|e2d(U;}i?R;?rho^y*Z9!ay2l*H>;Sp!liJkDin0+g*(9|vI~ysc z+Wo0X;&5hJS!PCgSrf~s5F>@DRJ0m3;^|15i)BY>iEBjd??z;C>CQAF(-|a8nlp{@ zHT({3q6|~m6dkfW_<*Umiy=|L|r1RUCWE#7rj^vPH zf;BkGwMbpqo4-U-wz__~v}p7A9%JT`asKl3tg^DK^zy_;!blx%8d2qTNHM}SL^*+4 zN#~mf3h(%{_@NGukj+Gy+Gq zLS{M&l*4((`QNzY343YE!m;#8VpNLqZ#6yi3d1k~;hU^cpNDl?f z1<}Lk6KNUf8zS$ezIpmSyd7r(*^xb*iL4`KqW8eyitCwaDy!=1?_x>rw4~Iek1+)Ql7mR}3CJ(&N!rR#w(# z`VkZr#|dvp_&AHj;v2K9rA=o@Pwmbv;U($G$>}7Wmt^@Y7V8;*W)x?(SZgXO^=?mc zvfHB{!Q7^dSF0>)wMC_lSKghH-dZ`Ll4a9t8X9WSS=QkkQQ4Z_Z?h-Z5^RoqlhLTx z8xaMRnVuFqv>lt4p7};iLrVI{$`LLX$3-!_j~v;}WDzD^WpMjiJG)wZZi6a~%Nl5E zX=xhp@o6f9%iq$~Ins~m9nu+6w7#mQrfR*};fR5WM1@@cn3o+ZrO}zraW2=0%8?l< z^{W#cC_;k$Oeml;Dby->7lFA_sojpaH8r)hHER$jBM~J-=DwXb14F8V|1}BmU#n=| zbwDs_6VpF2(qcheKs&p|IG9f85fB_j8Q~xc@&biYY!R-G6m^0y+VSCXkEw}^EC zmUR=yx1waXJC&6urKURGuQFR2+ZpEg-WqR;V;324xDxr=JvR}iz0sm+GOB%9dP{sN zk>{pn7q%KKmWI4gYMz{=#anb)K6P5hiH>n6IwssUX6$W3&9>WHQ z7qit{GlhEc^W^Y*iddyGRxz~13z0iLimTxr!-zpW(fK*O5&kDk^XJ5*CS0;y8-A;q zjFb#MA!mZqghv#ZmPjiWJViC~qVP$rn2|>pl`4zqvp&ZF|2yOa<*{Se(s@13kVOwX zAZ)vze_hz}%`qex=L`*y^2MtC0Xi(prAQ-q7+G5`zX ziT3-uk!Sqya^~3s&C7N143S7Rs#slotT|SrRK-Z8m;p-{Z!)J=l$fQem>34})Y2$b zC_lxl(a982sYYvv_4zdhX^d1Xl{1{l+K@{Ox8zjGg`|DqJcU9nS4ib7CzZ%zVz8}H zN~M@@Qlft~Mx~2V4xfrfEUP+NDUD`%nM4*v=I`djnD9)lGOCqQ6|gEesdC^5%Nq;k1j zs+MD}(5rhgm0U;Oli*x5W_gQN%4Jey(Bbhud5lbnN#P*n&^8wE_5GgHPKz92!D4ZY+;VM`DIveGk1RMLeAqOvAc~Kc>DBS3{McB% zPA-#0>s9fwR)0x@4zurK{#{*dx!)QauhK{3vvvB|*nCsGS}%*{qYCCV5$%bBk@mr~ zYtR1PYsf)7EgDUVna!k;-_W*xQJRhB;k{UiPN9-3 zm0HZBCRb?<^n_WZ##M49AnInV98=Xrr`ulsJGW44{C51QjIds+c3L0d)z2e0VA$i*Q{%1S;H#RHQ%r9?VcG} z-S_>z=lMU+f10Lm-O8sz<%%)YC zO%Hicq+!5LOP)@ry?63c}K(sf-yh!1T08jk&L~NviHw4+X>+l zQghE;d@*@ZKdk0D`p?>75xY^NRO>YkYel)+X|t)+2DQWLDXdMK)Edk$&Y*IL!KT55 z9(T~@FxHcmh&D$q7Eoy7BZhlUAwI2%<)1)|-t1tqy(-1+8e)nT-c>QCb5) z3_s2)mQH6d7`6QV-Bo^P?NGN-#~ajUm)q*I*`YSBvREB1hc$qJ7B>fx)MQqQT2aOM zELye3WOm{XvdbCK$^o<9#%onVol>JT8+AslUJXi)>7zFpFqPCQQJ`+6Mzk1oCaq4R zhJ$Af=9C^2T%+Lyw$IQg8p&wk5`hP8Tmz2ufZ{NGU=))o!fq-sE&!jt=^;t#2abx0 zDPc;ZgaI}{r2`a^ovLG$`expV)K$7Rqhy>RKDn`DtY-hnTK{|OaabhT!^llml)?Si zSg{`gf4gdSt4Esr;BAXx(T*Xd+%~3IJg||>x>c?V458x^zZ*|Ti-Ob$30$l+a*bLP z)k@2t=8{mz<98Vh2A$8A7YOGC18$!NPKr-%JaSd@tfbPx?1MU#1v8qjI?{M@STq=1 z9)CCx_4!=^4RU#GkwCa)P_y|jc9j}b5(|M64=kW!_f1vVz;DJxA|_ZZkm;1s^uG%b zy?3Dx*VNSl78#@0S>beAEm}}47Vwlb55uKn(QVsII>-%ymh_&Ug?h{b+la;zkJD?k zBB9n|bt0P-5Y#$cDf{c5bW4D4+XHzce1j=PKKH;~u2gG9LFLqGT(*FBu-E0Yf~x5p z9#@{vZcr9@W;fMp^bYj}yVY=XUfVR=Q=r1lTVKEq-_JUo&FzW1LVmZ~1}~7xm!TdF zv(?f+)WLjwv58X=+$a0VNSbK3ZYwA|3Hl&KKHh~`uQaeyH2BWt91s84Yb$hG?=t%gsfJZ z%dD|r1tZOE4dE+;Cdey!9`YDKOTeEJG`C7ILbyga086nO6&GQy_Rk*B#eU3W_&$II z!A@|%GS^RDWz5D@ErHKm2k=CcT%dLAUSFLqD3oKbj_VOp^$|pELhaN zazU`dYtY)clg>S}UetL#%KVVCq68*4JW0PnUtam)@x$nq}Q)j8S+zQ3D8$1xbDt8(EPOFQ#VIk$UQk#Querk=`?68$$jk2im zXR+8*^Jh*QJqEUe{_*C!Q_d6Z~oNw#fw+3Tsj}2R4RY! zgvCq9sWlBc{hyuQcqHn>?Oa0YvFX6J1C&-pxBXdZX{ebC4>WFHG!pkr#rkKpIlv6q zEOINrZ~~ugR+ENYn23)aGi}V78j=`A+-8*ggT0$u7mwZqoM(8;B=;gX@hzAN}zXwuf&ZIcx+=|zz|fu5I0X8 zQRy4CVr5iCYubHfV@_T6X8y(*lTT|IvvPR%!RnaX9jiXrJ$&VumeVHB*qHz3vQx*D zag9O#kC$mxuMpFUhLaoi*bHHVZ4aJS5cQjC&80W8wOE8yZ>4Y%f2nliCxSgW+C$=D zIFZCh9!Jq40uKxX9%It0Rd@~libwtCd2+|SWg5!%8K^4j;oZH0N_&h%@uc-rqwaBiH z8skk+`_jQprdww^Y57Uxc=#)|!aPc1c1js_o3S49s{F84l_;?2Ns-N7q~=@;6QWW_ zlrVp+cZGEZn=v1@e$+}{4ciE0Hqq(`;Z!2g5RP^l17*cVo*30|f1(w{X^ZvT(2!nZ zQ1M!&W*)b^xIpxd4QdjL#stcP;Q0luWBQdR1ue$PnAdP>si@IJ!tOGM>C90-xgyrU z$Y6A#dzoofMbjRWuc&5ZXz-{KuD*28ba&D9F43UTO$be2R{$nd)Obpq1+RA0j@7D6 zJkx$nLG#mNRVy{tJg-TUEX)s7#l2j9mCKN46a|ASHPxWDS)244jR3cU+8W;9T423P zt=W7jq(Id*Wrd^ai{nIVOwn5`(Rh9t9E2HEYKu)J%ru#k)g>yUMr|@`1b6^eWA5w` z{>b+*&16{HVE)(72Ibv_8Saz@R|GaN%wf!}2|AEWfR#m5U~ZPF#d#yfzLKF;6kg9* zyiLvq#{_tpjx%PLNn<6bfq1pO}JbzNSp}FXulQOrv9k6HN)jOMS zO}dTYke|CQVfj;geQ}e{+c2Zp;x@Kd7pMKh!jahAP|TW+g;zw1GJET_t6JJ3&XD<7 zbcjgK=KM~lQ~!aM*C|uOJ03TosUMy(ONL&uHj6dmpJr;SYy-7|aI?Sn_{ zsJ4}aoiGiUOfDVa$MHUsJx)=aBdil{hAhhm*;WD0=sK|fVEYX~r4+kB%wl|H5Rzts zNmD~?aZ)1^C!k0a43;?Kb;3ddqm2yO(#)5LqQrtQ1_m)MmZ&1hABA{OH1d%(O?%i(Jp=Lxv1F>nv_2xs6WF+<4Yk{jIygrpbMme9zYrwrx>^xUdT(6OzRom$SXq)frn8Q0j_AU zkybs9@ho!N*m!2VXXws4L$~b)BPVkHJ(*ukdUBYn4zi(?P({q#C=H&d)~SFZKoqw5 zRswM_um%&^hr!p-5@9mlk}|uqxTwzdgi25ww3!=qXPl`!<4@PW#ff_|pJjf1ybB%+ zfmWvh3#ZQ@HvtR(0UR{wuuW7lywhv3i9^BI{RwK#d*rq>ke1;Ir>KW(@k{xcxJ^3* z60)kKGcG#fOu&`p5gFaVM-qL-9b!zC2I&&xVjm~L1oG^|m<=&5BhYAV~k;h37Z4e<0F-D9godG!6 zA0R)wd>_x`PI_=WKl5Xs+o;zoRVt-kkL`;YyXI^NZMa?zaW#o%BO{Q?ovpU)&hy+6FDLlI{O$)~XFrx`a05DGh7S zi^L*MHjV_lgl=K0Fj%sOFrW^J$SHE@DpjJ2SR<(9r&p&< z7u~gz;0OPaRV%rvbZ0jUc9T_7ELqttmC>SjRG0v}swb4eR}=rY^i%rTx5Q6B{g(I; z=Im+yaZo~vNHxeH!$0x$Ul#mOMAkWQ8Q2vzVQpJfB)^c68sd zbc)Sxw7F6^AU7uTGtPPb9j%!1+A4_%GHZ<*AE)2nyW0dyUnb5JtaO+)Zui7nK0DpX zg?)ORH)L|n z+=tz3$bERGe#VT~!!H=GqmR(P!cW97Qs1i}qv`#07`>m2CXZag0vEIAi(xFcfj*r} zSf5Kl#?bI3^Z_#J63M|kfyF}=?3yYW{*k`gEMe|vat=LaAh-g_^3gQgD9Lh||n^4`7V08NoM4iFsAbI`p| zz~^^&HZN)%*h}&%DW$KHGIBkgLtmzI$o23Zd;=*ZeSzyyq2em&CKW*MMr!kbnh%j# zbnjuhm&`iMKYlpl{NTS0MmX88i`hbE&1Zh=__15I z;2PtjTeh47)@bOKyPlxG66F&_B{;UwM>F?sAZ%cg$ItW! z)0HEeI{2j>O(QD@4VpQA@QAAF5K9oQtR6mWY%W319ytLg1pI?4Mm0?0mrQIJo=yjS zD06taLMk&{G3flUGkw8ydU(Uco=Yb+jH;*!1ZJI(fbBm<;LLWr@Ezc4!3nzynjZo1 zZfus=!n`f4lMX(ibr*(HGF2tS=)9^@jJgo8)xZzJ{p6JU@28jGyXXG<$I^oN&zWVaZ%O_lZIX!sAgv-CY;tEoK zIq)t7I=dg5y5J0;&@IzW&?!clWcV@?n&pLL*s>^Wk{G#dWK5Jqsj}QtB{!rlT#%Zc zDhSuPcg?7tHWmV(*w|^+Gj_RuFM^x?yD2@prn4d-oI?@QcX|4XV04Bk{Jq}`_X+1K zwjhv@)K-8MvgWJAvB)|uKn2OWiex4P=X$bHPl=b2RTvqrNt#T!{Kn9QDaPP~ZuS=^ zmoBC1%f#dceZ`@4F0NPYC2Et?10$}@ZnqKVG;Vh@%({BKIu*AUEFgrDc`lFF>+uAG zBZ5H>d-VCOIJ-qwm{axsXI7_4O{ASaY5eg?in=(C}c$&60To z7A=ZZqgbg$(WYFBnxbftM~@ca=*q0M1d!P4afgD#LpV!DDb73;h^#m8XptKd&nAzH zb;jjsibR{;Xc2dV8u0h_ek(j6YzOUvq=zxlS%AosGRIBl7CC7~XD2L6k&9<=#z$t6 z`GIf(Nq~O@@O?ibuf`g6-Sc+ztwEE`UA;mF|IrZ)kcjrl!%p?>|Tw*rV5%_ zPG3Q6N=z=s98}p18oVxxC4;P(z}Ui~SR&wsC={h6VnwBqL_lp6Oelq$TNx?v!r-qe zFfLUTPXydfv)SegB;rLSkz_z+6wJYRyv*dl(W^}j4JqhI`B7K2z|Wd&4ytW>E$XV0 zo2){UQCTwJV@>u2lCh#fG#N4v*5q=e*Xgb5UP!Dm~Q$_<06;)=I&;?*=)gM6~g8in(Xa@YySP6b0 z)C{(0EbA7^wc%t9CCQCIN(Nh&(qhyaKU8V07W6}^Dcf{}OgLF%^`avs0JH%|Zha#P zwHQ_`t3(=7)rZhPVLb?0L`EOwBJ$6-}Hxe+gIY_t&I{4jDgg zSW8_x;12}SbeP$17{4xl2x8yQpj8q!bQYI7L3}n(c$_ zCk@l;vc-Kw%@?J&_V+i21Tc}1I%+@d;7Wp{-h4~!BPFRU@ zQ=aQuM^}-Sb)^CelI z%AYWP?%eKE7R;R3R)FIz7CP-Tgib08X`*ZZW1Y987f9J5GPa-1^m5d}{4~b1f zY$VKGKD!`460zVf63H(Z7?`$=JV>wE#(=bqUPB(_9<DX1R%k~Oz)S%ok9a(lw>ym`bR=>0+e!SC8HU%^|Ip>C2L-MiLCjzmtIb< z@RGpE1^H3ArP2I?fq`k~)1hS1`D794!hduqw`Ud^MIV@j`+#R(cp>!mrl758d09ze zeoSt8EWfa%3@y*IksWjzJqE8fB0WZKCeRqfo@F2oF`JPtIEqWEaBzp#<;J=nhF!zn zy=Tb&dxqTe?$8DFKB8YlbnHJpy>H`UJQqitKUb$BE#l*xJHHDS&a)KSgy-Aaj19LQ18%*-Yw)-dfOIyE8Vw+-bQZS z44Yvux4ryI+snNQZq$T|w(|0}3NA{Q{epkLkc)r0<6oEl>r(u~DMmi-{OyChhQm3b z8oLT3tR5&JA&!eRgipr9Dhm(7nL`{h6E5!Ci2jf0=}qJwbaery&v6LT{p6o^KAEO} zAhl`Or#?sz?&N0DS;tQ$)K;RfK<`e(nWPJl7HzPymqh<;E?YRxhaqWZ!e(JFeR^&8 z*YxA=we)GSZS9I>BtjLl=_^0Y`uV3>KhamXQ@)@(RlS$%ZKQo^h9fs9=fGA|{LB(EZz=N!?lWp!DC*^x#>fmOgV9?;=aF zMS9~t{G)rw()-@H|2}D-J_Yyn)(LX}Db{8fg{Vo2@fs0+(*_jF89O@I5<-_9y83ziqsz#}&tHwUmO<8YgK!!von19U zD`kg7XegQvVRP8Q{gt$(>D}Y#-D%QBW8{5$7aqp3mv_Ong_#B0X_UOj9wv+>?d<(~ zNH`%)?;MLdVxW_Mg3lJlxPcfLaF~Z9MW|-sP_L_j%%(q*`(SrSM{j7ThtiN1YP$#M zPh_^RuJ7&j!12-Kez>ZiQ!nK}bHU4h310rZ0eB?uPeGM%fiav^L1JO4N#fKcjH`4Z zVo?FD;=BRpFFFi=F@d7P4S%0b9{%86QakJ2>C@@6fA6FtK6r;dJL{d!&UGZYo}}m- z>*?F;*3!4v(>F+JJxTH_X1zCK#_>r>-QQ=BM?QFu8_$xzH8As}@!h3)~b&LwB!)g+dbmFMmKN`j#@ zHYb+1nS{ECgMQsbKia&Be$++3CXOx=63&xfZSH>s<0hdlR$i?4eT;RNgsrw3J`Pnn zSKOA=K^7p^6qBULyST2Yhv4So030IpVw|fFO`ZHgn*Mk%WN33Y4i{kv6{{|LiIt5l{f*MW zki7elH>WZ~0KY{}W@w2eVuwxaBkzV--E!F>b^ysWH^qud=9Lu1nhYMhdS-QAO?jc! zQs*%Xx{;Oey{pzNZP(&NyJM*aihxa(BXxq=Q)jUjme=Ifbn2aUL#}{kmC9w)cjEPl zC7jZ(6?kp?Zr`te_^Ec z!z&xL8uii%T0zisEP;Z2W94u?#<>>bTvijRnU))8mc3c6bX)b)@H&@YH$u+eu7UpW zgr#Z?@{eG6lFeT`MdNTQxd)^}DWk;#eec{6RW8(|?V3~DG9if@R1;ci=Pr~mpk`h} zD4?`446xM|1WJ{-H)IjZg86keHh?x|Ak?t1k|BV8(Y!&q+=J#V((|0oqN-dtAbWnW zR0;esDN6$d1F|oc$Db&wdcPJf6+VzGc(Dr>Y__nuB185+MqHl4ERs#WWCB)sopNG1 z%%*E@uCl2oPgZ%N_7`2lSrhq}bq*bCbVZ__bz?_F>q?SSs)~keA5v5`C7Eo^A2O!C zGZJwb$BvkCVQDg%ynOl)mN+)GY2?UU;$b6OSn5<$V(8eq&S=za8Z%vXvcs$^mP z^oAyvIhC4luFuKxoHV7drKNaM$8h9vdbW1tvph}H>I+lIgZUyT!jRA0E&Lh0-4%*^ z6wiV30eB2-m`V%~Hd!O$x5(P>!RbVj#qeL&U^y{{A^-0T(TNp87%W|~08wP4!RnS< z1}$hj<(^q-xw^Q;uF{aFV0eKyRJzMlG|3k-8OPL(Gie>M8D?wgpkevdO{S6Q;$g!_ zw-#5AG}R9(7+O;()c#`F;E*`pT zSaEu!si7t{WKgNqJR|1Nn#R>3W1eqPA$_eb?QyHs#TDgBL1(GbXuYvIN04055OmbX zyjpdYRVOGbDvH%Ak0;IR$Jgh#*4U#_drfP8J^fkZ#l|#M7Y&s}>)k>y(Y`FKHV>IM zdfcRf=H{aIaiixAF{?wTb;LuWw>DZ5iq;oko8;A~Jsim^sE>wy87Zly~(UM@SE|o_(&qC;H`F$a~*=G%yd0SrT(E9qJrFk~q z9I*P#_K?pn?{i~7nm-APL2seg^k3<1vVX~v=`9;KV1P7QGCA!N`my_Y(nrRSK9N{X zDEPY~G8s+e^116zgJsbIo84|JfQ`|Cfth82!h%#`JPKz`W>Yj!7%y`=;@&98m^Bnl zBudKSg@L#M%bm`e7mX)N%3?+Ss0qT;5ahMCvUstNg>rEvc}ljbv6RK-*_0w5vpeId z(z4ogd1)%{v`eA#bZr?6nF{n)t0@vpCCZBP zn+wTtu+U-=EDk?Z&!m(Q6E@iqoh}zb1B0 zC9=t#ODIt$FjOo>pYEJI=jB-sR*WG7*Tw4$i9k`Jyfi-%4O=Z1Q_P!iy2|6lff!(D z4JTry$&!LV1sh0HEKnSuCq;qLP*y;oR9KjZ$=MK9?s6u)a<*t9zqCA26i66!jVsHP zN~21vaoRoZTDJ%H0kkT(bFB7z;6=>Q4pF*Riz{h}^V)3s{k+2xo~;u79zW9B*v% zth68z^VtNm9fJLWl8R(uC}y-;4JoZISzdzMszEz&3vsEE@}y3if}+2auc8Dd#t|pj ze6d79X&LfGut?j3$*7OpZRh#1akJm+cGz&mL1%Ngy?%3iEYD}Y5q0jkD>}~R^91~! zT)fRo##(H375RxY6h5^&^apn$*o7~gO&yz!?q`ef_yZoFZCun9ckBLP#Gw>~o?d?l zx4vw+-^KCiM1DmbgmhYk6X!pV2$w*oa=PMmBH;GvT=ECP_Oa{~n<3E&qyiYqaEzgW zgdSNj7mjf;19HoQ%hW(f0sg2~PFL$JO;!GGgOHeI4BRGz<$;T3m zhsS9iOCYiH*%}5uqhP6546{}8JdtdRG9_nu%3#v4nb4dN zx`w4@9|;^PT-rGE29*kWjqVh*#9o68AT`HU{;h-F{ryNtf81nv%lXi((}(BQ_9Xy|#-k2_O(k0%t0 zh9kgcoU4XLgxI-iFc1kxajVK{!u6qIt(<3i-nkT$0D( zD3bb;dB}uosYaZo1_>O;FT*ZPtI@F&30%A(1RB_aZo5vs%ZtMm4NbC1-<3y8i7W!agLDTWm2wwj4?-uLH)@z*yL{m1Fq(Q`&ZQGX&7 zFzCHLe<+&tg*>n*83;zgVK#tJwlw&Y&AD^y<|K|m^#&kHUN{oY^BIvV5R5??#O>7^ z=uVAxhxRz|Yc*OW1HZA&q{AVWTe@9h!ts#KLq0Q@#+$U#ps+h9cx%>rc4&0lw1S2k z0DL9xV5;fGMus;^6nGroXm{w;yFIv6t-{6&Cs{xn)I`?mG&?+6^MJQzEozgn23XNw zgrE|%H|q6_>W4ypp9>B~5pn?*z-YHaPcIe;rkomkPx+EqcFGa)TE7V=Ww^PGKa&Lq zSSCL=mxxyeFy{umb{PX#isTN1Ql~}{yZ~g!uA+#`oTK-cM@4g!mCdw;dKyI|9u_( zfEO&*AXti`;$$)s1eanBMv}?mBJeCh>jJl@AXS%cuCJ{rg3nAAs;yZ!Xb=k!OHpdl zM0UYw@jP5GDnh7Z@uF2Y0qblpE>cQ`pME<1Fk5Nf>8w(~QKhKBx_X^h3wi#<@LPKe zY{5LCcm*q}1q7Ut;{X5b_e{isRfI8jHnt|q%Nv2sA*ZaGWs48k1y)uVnCi8>V6kPE zTO7&vgo@8M7It`oCc~)OF-DC&I?Ze;Ne@X>H5i9uw?1@ab5YfBQ*AnbaCNcOGA-iJ zn8pkmWi$r89VwHkpxqZT8b=KpZPqv<(=68FYS;*CFtME5u+JZEtV`#&rb{g5X;Hhz zIHq=#0UO5l)W%4@J6ODnq%9R{ttVP*57G_vIZLG+2-MT(a3!X!yil!nxvR-Wk_K@u zD=Si~-0o_A4%rlU)sHA@rGMA@c@isWPKGNJEj}@vnzkmUv5s2SHgRV0uwiAL6Wf-J zvT7phIt#+0zd2DEPPP=s2=CWwkS|))nhaMYoBeV=wPn<@2@_|O3>#K5W8#Emqb%y^ zT9(h-ny82*n@gg|_XgdNa5ju6Y9Z%8k!Ka0(aO>EUwGmjcp`=;Y(a}N5)2aIy(jDe ztAjoAkeTK|zI%^2Me>Z0lP?XEOvI+z*u_ri@Wg(v6v5Ky}v>}eJ^ND822XG{kL*hyHdax0DOkA zR->I3sihXFjcBC>opM#zpl9&OR1?QnR5_Xn-f@FY{^pJHx4!-6&GI+CVUKTq^X*%B z+`j$m?c3?}9ox5)vFGEdbNlv_w+r|FvW*^DKXLuGZD&qePrpC^-~T?JSk_NEbK5q& zB<5{-*R@^OhJTaV#*c5qx1;U)w(Ic^^O)dPhA2EJJTAfg{~FFUCyW$Vdvf=Lr{38+ zvV8Q42~WNC_EQtON0pD+`v!hl#9Mnumyg8n+iyPA-aV##)ZTXyA^c_H;9V zsfmSycP&3_!-`$4g%b<6e00{&D|QW@*gkmYieqPew54!js&)5@^=IK-;lzS1A8qJa zzH2bLfId_}c6*)hmSQUcS+-ds&MFtkvdo$f6uUB+I9OoG*s5e}72Ica?$W5L}}i{d8Z(@z^s@uI?H9Isrl zWMM&m!s+0jwwU8ZMPsInDJqJaEl=|fn0qQLO0Y!8I61-c8O-?wMPrJjk_P6ABV}Jc zN0Jp@z+Y1om+R2zSFC`GX(uZXs$qC=Kyk}z>Hb8ic8-~fjQG!~R({fLu|m1aA;&`_ z3n{aCk)khxWfV0mqr+Lqa%x05XUyev;vg5A3Xq-Nigi|nlP(j^m0dV_9flQmB}OM} zvyN%#b2TImU40JLE!oZ>3oU6?m4}C^o9Fm@iMyAFfsH_J$1`9Q{guw9 zDp$EX9(R|!s+ydYek)n^o3FWrvxW?rH8}GDiMP;q$-^YtLf`*{zS~0L*(Q97d{vHt z#W||{R=V>yi+ioK56|_X*36;lcGUpX8!jcGS5tor+lH1FBPAhNcn<6Uy2`-drIWuxDC4(F5JB! z^T8*rQqiA~7@jgcEO<^XQC|T)_x(o!UeEyUP($(I-ihD(KAo$VwlY zX>j5lX`)Z!9pFh65uDrKCHNQz&UkEej%Vg>*wmFKz9`u!%4%@O;Y>z)Elp=0YHE-0~481 z-yqQs-J=2rNjlx-;Ucx+aJ}G*wz3R|acm-GAPyJ}zQ!*O@syeqFU&m*LtHpe3+4rg3tAqIM%L#*`V<#{SK z4qR>jmqo?WS6j_brv(p^yZH2zdZm=!=puHw5FO#rRJrp2Lk{QcKSEwU2oyF9jVC+! zC1y}L0y`Uk2%fDmKmm{ttU#@3WH#|b`@_Ha%b&j7%xSFF59#9<6XjN`)oR&Jlo!#* zKelkr=jbOS@Z83KY}oLR%*li_eY}gPb`i3R9=qUU`Xs7Fy~BE+5OxY0Xf8os7RTKR z7rVBBOBRB$XSsfuzzsV_oB0cSme;b!UMWu_HeZ+EZcSgFIJ@Uj9kvMeo_YM6$BqmW z%ysE-(@EBe!mVM`5a2=<)Be|zlBnS#B6-`{gmy-+aX*tggV7J@&!8Ttdvt}a`p6gG{q z2s(QL?IEW@E(jI8%+vTq7;mIsu9m%(LL8;^7>BtIeXb0>NKS>m63*AF=k6D;M!DGg zL@nI?SBY2uvO;+Qg5U z^@w|)f0_G1d>fK@1?~pbRH`buALy6s=Qf?rzf4^J`WGwvHU4RiiqB-zz@9^t{EZZx zyLiY3@gV)~`|lOKy+pyk%)ctWZBFVM6z?k(W|gj?7YYgr#3_E_pXT2cpFvz>Hm*^Q z18f)d&J>o2n_#=P164^BKesHi`NvjcICGW-bbZ%bEb_zzL9DKEgqaUoIh{0(`&Rp! zG*gTs4|yES77s)^u&{&sXl9ea2xCBMgV|v7R#nu;i|x)|51cyZZ+HIMO&r}f2BQ_} z)|R@-HFdE9tIg&}gkaNg+Eru)O!S!DPLJE^hUqWZUNacX=D5YGGr`-GFIG}fQ$qra zrti7(&o|~Dn%}c`^3VxYwV|Nh5lWjr1ixs9=AkNex zjf3|K1cO^1LZ7|c(=BWHdPWtc4i*1e@ew)85{iA1WXyd0f~+F&Rs ziVm_+Lh2IMi4w(P=NUrFHKi}D+ zNAgLKy{tK4Skslq4>MbGtitS9Uz>k*Yh!&`F@(DA(vrryp+oB$OG@34?G~5SH@03o z_cd<&8hXiXZdZ9p zjh#IyzcCzbZptq(ln-x=#4Qnvr=%)kS#{FM)%?yxtSam?>7AwilJ16<^x%rI`)8Lm zO^7ZXb@o~3zCuM4^3YrUwf+3g9?26kPXN_qLmJIQDE7HST%8kB&r_vO#lsLn+ zzQTFqDjC7z6y>B+xSl@<>U|R6!zd6igXEz%=)H<*VXz(o0H8Ox>BkT!J1;9`AhLOp z?Ys?1Wl%6c!XS8cWxU$iQjsQC(pTpsi}Lcg#*^9|>1bGa`V?~@lUw zs)h1Mq{LI6n0j}Ky?wk!(^~!P1>B!?!GekI(sFv!OM}uy@W(#9wL@PQb>}zks9V)q z#+h(w+gRJ-_J@Y%LByPFjaG-;^v(6Xgkpf0`ql&$Aoe#QA4 zS1qfpOQtJc-*EPx3(wxLWMNGWgJ*wT5rx84Cfz{<$N&^}k0gp0GIf{OGXVR@%(nKH zA*}qZCrzAo+4ilctf)fO%a(81z95;dS-51w*%$6Pd&BGS*;ZG(Y}MJ@ueki&ZKs@8 zQ^)Ee3wyWnOT~8Z(-=88XK{rSFx6$P;g_7UWXUP?`?YJ~HGRS(^kRBGz2M=$kQMje zN0$FZY9~1rdFP2SN&m4d>;!j%p$?<1W{#XnG-s@?uRopsytt}zp%{CZUVZo7_ul)^ zef#&5Q^-82?jgPF`Q73q=+i31s0PP>{I1vOPO|ECx_vYEHTO-1kyEsBDAMi9rb99f z-jLOF=ikUGx-*+F;{e1-%Jo&|xr=bb2g1X z`-5E@UG9xLKRA0l`t}PfJiR3@hJR%R3|2`6v&q|6727C*-RP@~ZNYx6K6S|O$&+Hy zA*WW~^yJ{dsek6c-6Ih4qZr zf*b=j0ph$lGyf89*29gNKa%a-%srX;#F+VGlT`LzVFUc>u$B7TLX!(oCFtw~TC{ zo4H$~w?)B3K1Z2?6v}-9<=!rrn}mKe&o9jEy@b1({*#;0$j{8o-^0y(xGD2Tq%9^l zz$VZ~tj)G?QV<2PCS1bVH$tcSEt*e%-U#O#-yeN^&YZ`ON^KrR3WRM!BYb&64uC1c zNT%d0LZX4tkcQ+di5sX*93;K~wzSy7#0us;aSGdDM}+=OZ?z=D2BQk5@C-XLb8KNB zjC87fVH=Ya=%@r#B4&QR%z!v&R?d`XJ zI%(4GREpm>_nn!u-kD2or<3}>5^kIWy!%1!ht!$@{VgH>eNulp#T>FqSRuHv>PbD0 zyEGi9C%0yHt)O=bmSf*@2M-;B2L7G&PJj`q&Ln>nCJV7_dR07(^ybI84(g_l^Y8Y= zxlf;X0`joO>EkRtLHZEV|5@65071#BU!+vuk(X!%We9^bX|fZrY=kb5!e+_w`V4^8 zjPYQfw9(-6=E2)m7lUEu@>pJ;*Jm(tuaho3`aCAX9{K=%V2{D%@#W>oW$r+k4N{p| zX09?@Brp^o$M2Q-uiq#U6bbZcJW=wSg%5Ku1rBiwnA$os-@#eQlekA1 ziP=<1e%()|)0@_^BRGVX?j!T}(VOT^AMYa(64`fDDx*|5MWQqRy$q9725v9>Mj6$L z2ZXC(3rxai+|j9laEQQjY&Z^cKdP`Q{USGM-iRwQzbr9jGTi-h$@A;xW^UU_zGuz3 z_yYRiZr?Mx7O{Svtaw9M&fhMVXR8h~f5mV_oebm71a3{lPbTk~=8+F}w@%NzMV`*Q zwTa8`TtPdzYtD3?Nk2W4K7A444_|cb7%OYN;$2~)Fb-Na7I5rI&;kI7`7M&5WZ^EZ zrz^&g=iAAtW9UUElM4D0O}~4_rR2La=tY-e7d`3>Qb8)tpxaT_M8#%dz0f3=g=JcW zPO=@n3y?=~+@+ml=LEW{lbR=xyUVDV93f-r0ilVm+)Gz(;@mfWN|$URV_{u`Q&fi?3B!}I+{j#+S9d44C5aBQDnWO4WR^cTg*%0$>GPROxE067 z6^*4k@o(+1$JSy6saeZ#7d}w_EVKxBND>{!u!3bjp6$x+ouxMaAul~@TIZs|gCO&m25&#?12$K0_4Q zS7^~H#Y0#R_x4d+$;v3(+Tcu&E!6R9pz8kJ%IKO`@cd-?F>5 z8VwP5qkV6XY4n!T&&jmU`M+GCjI2IKZuS~7^>Z}QL8h{D33fCO30q)q1Ed!&q9bf) zQ^PKHFi8var)0Fqt*#|}0CqwT zgjO3&UUw`n9?y%py(R-W1kDg96o<)3o!);sw`kmjT$C(1h+R5 zj)#0fJ2Zui!C~Vrl;F2oaTmtrG6p}%LLqAGR}N)>l$aa9O`1X84R_+GV@RN(5SjW>GOokR-T)#s~eSP z{mBQVu25dUMQ`!JJ4iGc2?Pu*FPZ9ua*y8iGiM0ZVGRfFRFf3w_%~Sl3MG3{7&>{) z%K=ORpk(L{<67YYhnJJkFwu6l4^kA9aN{76=O6s=w&~2=7?hy;tlMTr>I`nJ;^s zhv7s7&qhOv2AY65=2$cgI>O@_p_2<(!Q zAOWI<+ePsy9)d{N-iA>@Co@ebplH~ng;ha*lmJaOQAv$TomS*#^88GgB4l>y$Wf&T zB`9GOB*sYk8L|i>$Ma4(-k?X%x|MWIRkR?Dm@}$J{$$hu!@rffYm?cvqMIE{yzm4_8Bgi zhU7*1hyeE!GQ37e@KPz2V*mu$JU~b9lUk(jF({zxuso>RufzbrkRNJdFndbP=V0~~VD{@kn7x*R8Rnv> zQtn4?8KAsC-xD#hdGH!~;X3$_u)(rHA)`M?6P0EF5WJMI<0ukk_<@ZJ;-n*PJR&kF zT(_usNlm-Dacv--4yHIvG)yT~r)VN@+ zWyfk?GT~pn-Lh&)16^H|s;U~XU_pS}8VD>{Fruxf+jPVIY4YM%`X;0eage5-_p7r=wH80fACXSFZIbn1|@Xh7# zXUe_w9Ho}9Ucxt`Kpn4S>!^07Yhp=O z2_~2dt01d{6O|F7C>%F}z~C=E$6KCxfBBoihS35?&V+s7rkWS%{*QQr()rC*{GH2Q zAmoAht!>3UV;-P)cHp>*(I!7xB;3dE1-Ii+D6GzkbX6jvWWHP(Zewy|*4{mSW!v~w zIBjLiA===85|+IzGk$&G89uwwl9rtgX)({4Gsw>{3v0}nu>!VKkVJSo{pl|~W* zVGHyF)l&oc7rmT&m0m^`XG)c;kG*^BHKCX<&!~HLqsJW15|8qKQ`(Uijbpc1Sv!~! zG;+gU`Z;$y{epNhlW>0YlComWnqOX8gZ5{T=hnVF*vs0$WV77}U$%Gen#?2!Xugng z-1hIkuR%68b`y|iqteP`MUv<#OxhuwG1HGpkRIVSv(vhs<-e7VKO2_kjv&>?#LR8( zSZ!J4f-WbdGdRFI&~vIZ}Vzx!JgL;KW1m z03C%Q!h8~4vsu`9Y~$uN^nGp(3w^j5KgXxXR*TJ;WDSHU^!+uPk8Ko?0X*PWEQAac z2U_TBUme(CNp&Cxj&!ka$kxO!V%b=xo-6umWKX-D6c)20 zu2OOi7iRt6zw(Z~27l_Qy4PD9vzd^is5 zrdsmT7WyS|(Z|S({Ilf8E%d8n*U}#_&)-A(N&V@QNDnL8KT+)#r2bMll2-N%qPi_u znC22a()Z)90!Fp7c$>pj#1B@?5OxW-G7BdRLuJ!>%*Y^w>Iie+e0$))xAd29@4x?B z?pJarZT}9o8t!J_?^uZSp|1>B{j;$$av#|YA1g~L?~=DKz^AQE`e~O-V`Usys#G#& zOdBl~HYs(|u7$NN&jLkSi$x(X--gn2-F z4gXP3s9X4Jj2y{aD?ELyfwk#`w6+t{VxAv4c4szme_BZ{R|C=iz+(9ivnfwV2b~F) zPM9Xw-j{4Z-BNjR4Gcq&L$o?`EjO2&m$_y%d7eB^)7;$5wV7*=YpayrMl2fsTJn4@ zIcKM7{*wQao-G9&GLS>ZUXyEJS;+Ib3QlOZEvyl)<@fZr2f!HE9PEN~a27$~4Uhpb zo9H1$G^_oJgQhq%ax1HC_@8~D0nEI9LuVIMrSC0H5US<(EDm4%FC2QYb0z+Mxbw;b zME8(!${BqQ&wkZSis|U`49oSDN8sHhlT9e0wzy*uw#Y91FMQ)52ECbiF1=14o{v%ZX*Cq( z%wl*o2j}w}#3P`i(AOc-iVco~?Sw35$vX`@(a0XjViV1Gk{ErjazgvES5~e3>aCN< zkEh)Y4S#EDY;5{lLxY&U?$^S7b1NziJx{vH>Ey!Fvdpyaw{F{Z-jVOm+qP{h=J#au z^Gx)UNvWY!1_B#~w9sP4Q3*S&spi*T`}Osd%-Mernfu@?YsbxR7w*WcNq0NaL8zPl6BJO^3O~JFp0~(92*=COL!b=mgO*a`SpF z5MQSkkQEY+9@lTC_Y-Ee^O#`EV&+))nH9$D!8W=NYq#$aI126WH`(3a?`y6TUzfX0 zchl{3d1)DU%fN1<-{+&PBhgl@mu&X3&-o7j>i!Wv4>qc8De_}Nw!2jNy`KI{L4FV}VRBOlV<4U)a$yqVD`{ z^yB$sEtb=|PJjQDWoz2Tau-Z`fTq-LwYOSbs zi*`+^Y?q3Pj0{SPS}fhAmI^MR(c1s>|9_sxfHN0*IM z6D3lZQlULylhvw`)$Z!O5m`}T*od4*rS0&})2Zv_r zZV^5@OtazTF^yQZx=yJbW&Zzms;2y1&z|8D>%wKlIj&e*dOIVS;dWVPVtF!;0rx_F6urJ#xK_ z8E^S%eJM>Dt+cm9H3777=s9f3HzrV51raW7JnksE4t*u$4>ge5DyLjb?@Au~QtSxO{zr%WM-Xsm(jWI(UX=SQw zTS<#@hGBxOo?;k7ZFB@D%D*aDH}L3D%#dHncI|uOrk5Y)6c}(B9DXuVwa6@w$Q4TF z8^bf&H^>--=gU$Q8+lF6)O;#Qn7U3SN}`~B(YLqeNW*t@!(% zs%h_=V=SL&v!$EXHpw#}IqeU<%`_@ne$_@cbsFSwxvahC)BysZpZ>bB8haTg}^FEY;ZK@X@b-Gfwz5q4zbJ$?xBk-=&r>jTPh#welhU)F{EF zOEpx#REDz$K07;g_MB__uaNc$A4zeNA=)#ytiI>A-mS)>LtG)^PIeiS-x3%~+18EZ@8}d?oaFe|zI}DUf>*zNEido2ZynmUY}r!S`+#~ltF0|8 zT&cd?kfiM~*6ttiVD?V%V&T2%Ts4_vofg=EUod&f2}cW z?b&A7+CKZ81MP__+sJx>oWbNhON5(R(gW(4A5U{)8EQqjB>Z@Pqf*8h7}XWjeFSx}aLzhoCUUP;1Yjt_20QG3JS=-WM;|@8D$D&)Klv&useFIb`Yb zP8Po_^iR^=JuO~#{eAoUHXGk}3@6-=wM2uu?*G*D!|c8q<2gr({?By#Kh{zWe?@;M z_FwP#H0~`{chP8EV|7Q~7xz!C?sB1_1$V3dBo!|$%^~*+{e$}TpV8tRV*B+!(69fD zXmvQ+uiwzG|BTFZh)`p)7FXkQhI`Qex%MaV6@7u_6byrqy{X2ZwU^m*5@RW_RL83Q zU*FCuF}MzmX){YX`md@?cJ|(8EHo@9ZrAE*_c=Z4R^9!y zu}60=vbt+-eQB4)`6JCy`2V*!)2E6YrrMYP$2c3D+uJP%iN#O<+jvhTk+iS=Z*jIX zUKZz%Xo)ncI9o1U7Uz$sMJ`+x=T=P<2Y)BdX{_R5zs~=QOB-`ps_>nil%ZO1`;5O# zo%mm_@Q}A;^k2g+C5fl0_hP$cHt95~J!$d(+jVxdrH z?U%)0)uL^e#s7>JE&gnazwxqsK2A)qrhsaEklX(+so)r+CxLvTeO7yWL0IVjCJ~-K zpi*Er7hk18_jg^E24_T%rQ>(f;0z1xk_LUJEY8Lc931qz>VA!T zmvNO|R~1nQoU^$HDtFg4y1SD9v+-+Fw30J98S~_V-q+A$l~;8Ma>`wN+xrP=?9z9K z!(zu$^wz3-eBXMGHOEr5hP+zcj)|>No~dKQ^??@kx{PgphppD&$(lOjWg9{^>~`5* zWU-W$T3(Kmp3yfaT~nUDI5u_kH6eqBL`;v>##-(e7xtf^_<4ElA=x?862q3sxF^j^ zD%YC>BI2_0$Hd+EPG-cEU~^nym~3P{`M)NndQI;=J*hohj~n%{k+Bux`k;RNCC3cB za7<^|7MJBtzmis8XorQnHBQ7`#mUvFkGKcub;=i7o*1IiTsiCbi+N z>($-q8R_mcXM13CvRCZEn(8_()sYq zcR#=VsyOd4tCkhX_~NjQY39&&-NwiJo;JR3=pl|zs=B}LamJG}m=hbpTcBp_VQh)o zo(8@3(lOkuN`{(H#gLqldfta6UVKt~)Q~NkkNOy{n)$_GegFqy*(o9 zp2+YJSATbw&rMi7cf!qbpG4W*%fi7dm1|>v?j&su{ zvp9%K|4!nTqT=TIlpZ$*#`L)P@Ww@|5Rs!3)m)LwBEx6A$%+3%e4^!%jLT!dV)F_A zQyfyRFndJ14Emoem#Uqk+L@}KH_TCubx~d>FiPmH-Ir~->D-Zj#wE$1g$vu`lGfDK zoh53Nw>I)1ZBV^0&m^l$e#k(K4n=57%wJiaxbQe$Ba-6&$Q+dWzsk;5Dn9*mO;Vhy zQ-rV_Brj|tFWjQ1-wPJnG1>^y@34N{YH2oX(A$q6$rMX7?zZ-?rP2z)58XzNqm4Yzu(~RDan`uj@T3z9Q1c!LanW8OF6ZPveYOA%4E@~{ z^~y@P;dD~m@|oxFDZHB53Y*4acHz}8)6-)NC$YEIP}A3qj@zuqDr|?3Io^6HY>uPV zF|O)~it;ytH$SXlS6q_AmS`i#1LP7d2W|SdS>;Hpi=rJljxWgxi}5wXhmKvi+1VaGb1X@lVb-n4IS#zq9YBOY)KysPSvu?eaTCjHHb!a=0JdZ~Rfoiz3TP z^xv%O7wSG?yomfWy8fMgJ(gwYf2Q{-gBNvYwDFFgRs66<$!ku%PZ_^f?z%mW#yiw7 zvptU)-%FO`7=*$U$YNWrwYA*euUlb_^&RWwx@>EW0gb z_Oc=B`c4>!8CP?U`AB?isKnlKJzSEBbp8eX)W_U2K9cT6KV^^Viy77`c{xS9>ykaH zFNV9_o{waXc9$*PZZM|U(+yv#hI#$zrrh;(!+oN1x9T^(t=b22;+6Vwx9k5{Cid&U z-r-(dKG`tuQhc%hqJy&YVmTll+Ar$yWZyB-NguU(c*ZC`Bs4O`Z?Z&_YhRB6n5ukXKhRh(2Et=b91iT48Z(L&y>9X)0& zk3sdPpX$D^kCUplkzxAC?c5Vs*t zj{oL8j?|U^3LWjcDK9IdeNNJ(;i~Xi!y%3IuN>*^iGID-_jXmVYAPVzHhY7D=dDu$ zv$j6;$Xm8RYV8I*_WZ^3(PMqX=8ntAt+_cv2Kyx~PPc}Z*Kdb53`2(c4v)O1{g2F3 zvR&8bjH(UQEL)8MG(4hG< zuUTyQYW%zhSKY94Uc_?|&KXmmk<-^^&yp`s7?}|7*?!AS5l+!vBL5cd)doNjQ zbl@uy)+SWAk8zM!bjVd1Hr;XZLH-%jAKboT`RK0_9gR^wVZkGU_$0dL@P7_*2^ty|>ErQT zn0I)B_Pyo9+L4~^*^JtzWTz)g8)wi)F4}YJ%);WO-+X%S$NO%|h#C{Qr1a3$%fCC2 zUpTciyZs+KW=WHbCOWDt@LZnwseXuqYM@>!WfK@_wpIg|Y)!GQtf3EZAgRUP8b8a) z^Q!a}(?*!1rd{wJI@fO3#VG@#GsF;+IWl?Fu=dF5vlC$~?9ng#Ot8hG8NS)I)mx!yIbZ z>34IVZA!ScYGeM9HmYKA@I)W))M;5`wG5L7uR^4x%nEmjx%TMkVWZ=WK|@zxmj9wg z1P%@Lbafy6ou}KB$=e_MU|xQ^cU)9hNZ{N|Hy<}I*`DU-;T<0mV48pLx?KaaUwF~o zyB06bi%Ge9>TXS2xqc;072?&`Mx91HMHnj<^7heh@?O8Gdep`ajJRBwG0Z=D{MA!O z#KtE6;FUf5{=L}q$DEU=pa1Gov^<7J1$qXx$0ihQm_6IOXofZP<3;iPhWFcXQBU7- zJ&g@-;(n9OJydJ6xnDH=3HNfV zyXeq9pni7Yn!Kd957()*0c-ovRiDFVPZ!mD9maE7z0pAABULYq=HnPO*-G=@HY;x8 zQ18*RGNxc6xAwdOe)@PU!+va#JYj;Tb zwdHV0zRDL(RvXCg!B^yW-{JanHfuO)I*zvJQdocJJ!|Qd-YSIGSLD~<)*r_AHs#mc zT)U2UG*z2fZ}a~D6Q{;T72@%02gE7Md0?E1xNiOFs_uuksCJ)`^u^tlzFY_TWqSK= ziXn;XV@m_vRe#J0UpozBaJSixdqux|9D1^8C%$4_fnMquu3H|*U4}SjTTLQQCt8Oe zBBQNMJA>Z9<4c#;foUfB=qr}!J$?NW+Lm0hW$!S}b?jK97Vqih;}#R)9A1{NKu&wJ znL+B*r*F}60=LDC89#LBbxU?Vx@d)$`?TaWb2HN`+nOxT$&;ax{-(i3>EPjQN_Mt< zH@kG!l$&p~Fj#%E>aoS^qYHwk&KNslTzYC;T*|m;bKe*o?6tK`CrM8SBe`zEgGVRNU4OPl4mxrDjQq5%DYHMa6!JaypBA;xcbl=| zUg=SqGxP`FDe+Th&L16KVEO5-TiaD0Q|+m9q))i2duUIXB3E7VAJ9e}? zPFYwG6Q4b5%&_?Qk@3mXQ^J=_nr-r9ne@RvCN7u#`Z+wWm+LXczgw>(?)r7q+jn?x!+{0v%1qiQtiP?n|qHguRkks7_9VbtwuFwG2mH@u?BhT zvzTVB&G3dz|Md7Sk*{4fI3lUB)ukRrPm1;sr4^c4xg;p6A|m z&Zzodj4tW@wJ!~-|E27|UcZNaBtFoeNfFKf{i+`~&Cr1!!a=`t-$COWdcCw!fZP8j^u~XUl^0u04J>VKXpl#+aHILk|sX?X@RcrE>XQpMv zPfZL}metf=q z=k-a$2UoZRc=|^;dqkv7T{$XRKJ)9^$#k3Z@?u9zIX0(l=IDvBvr_`cjE(?*W`Hb{A4XiQw%sCn(VwGp@fZrD+adY=h!H+{LtTF+VTG49r{-zMFbmpEn| zLVx-{uzjZ%8d6QW%ZI`}jpmebA&IMUV%*ztxvS%@!W(W_lQc3urFeBWQ)=}vRhbVUOg9pPdxt#%n8*{bkhvpF z2RVH@E>VWa1D~xZR6~Ep(tdyE@aIjs*~bo<#BCoev5p#O+=zGMu&)vFI4 z^YV3;VRURn=)&D$9&YP5-uddHWXm_@lW)>)oAq?jve!bS#j7mI6m4*j#*nbYRPPWO zKGJnidy2brmeg{iQ|Iu(%a=~B96Q4F;HpV6GoEwV6X-K`Xtblhe_+h`025{G%f2RK zjCO$8^&^P6&w%hT(z-m8Y8Uya4w= z-5GB}zdr7zsqswOW#kimyvwkexAumSPbe6wl}v?@%!i1=xj)-`Mu{;bd`y(8Gqi{J zribgwjJ48mb73T(tnkyq0@9`}yuM?7OwL^g{0b}|{Jc(^{0PoIKr9N{@*HCn4>(f3JwMTX!is;aTrzdS{Cl3im-PirJo`B7=^CRy z;_z{DkwLj>COIV}JY;rE{I&8i9&Mz*`~KId<2FpYJ~DuAuW`y%`a=)PN>8thtJL$2 zk%1w@)bkBxfA2ZUSPyNlSXR;%YFPm5;%kw^t!s7bt$WgOv|7~5num$aaHc*f+f^f1 z_C!xj8$WgWMD1hCQ-xWxjy_eC6PxU)7UpzJj?F20>gcSjLb<5d*K6YRspHe8MsLdA zv1;P1Ih$7QUQkq4Saef)d-+X8g=IwxcCXwtXV%13JLtlx>#UC>YqebGn{iO}0prKi z2ZQxdDMHr!-gNU+$ByTN`mhI2nyiUy%jG;)exC2M}GgOJ{cJvH6qA&`*43tL2Y^7sD)h_E0?;sjhXhue+v9k79E*6 zkyeqi>#}DY+%s&?I8=W;N{tR#?@D8Q)v%m>%upGq%(YetDp3u3{jIVmDLGdA#?w18 zAt_;YT+u@FRX!m>u91i1My9w8b{~;5aprXo|KXPVzVLL6l70blT}JA-m2v5VlRZ46 z5|^!+GC9ygCXX-J-hTKQ2gygFTu0=T-j|V`GCe9y`V`)kyK%jbtMqZ9Y$)4%*Xqw_ zRNKL~cP(ja8$0hUCT&Nkwuw00TTGcftmGM!t~OlH^BUXOIlhuD)ws7=_UU8Nm&Sl6 zS@z+6BV)<)okEc335b@kIpQ`uz^@fiOXL$i` zYx678=N|cS&CH?&8?r6#EX#Xq0uPBYEhkQ0JF7PA-(k7N`8|JL^;hi(*WRX2-RJz( zeU4QC2kP=P*?N11lIJb|yh7#D3A0vjd-jC}hk-hKM_Imq{oZzA5Th(#8xK0I(dQ;p z%kgfhdcBkzs8=dWVN7JgA9plICr^ErB`-#KFeQ;Gh@-Ua8*Ty&WbesA-~1j#F=pey(ko@jaT1|AMbL zGjT8NsIjQWue{t)rafeN#`2e*Dua4|`6J`^hIB_YtJ2fVs$VSPYnvO}%-q;;L!=fi z10H|NaixW3IOSW$I|xIq!%xUNi6pa&Q8;SOlJ6flo0?noIkn9hr;-!J%sS7!{J$_` z*39*Arq$b!<~cTP5kqnMbQ`U{v(vJvv(w=x{;6xG+flFUO?!#?xdY8WnX6J}>}x=o zkV3We`r8xU}#Wi zuz&cd#VkIj9>7~?;?i>AJsN$wD?_r>W86nsOlgdRQ+!Zp?4EV`Q8S}6hQ^qpVwgyq zKWw@~XoSHSkdf>dvgUSwzZiFqjByU$j%&90Sko=g_&sYQtLx15U@hkX*}|R-zk59l zTn_`+!@%|Mij>;elW$qRRF^|KtLq^ya6Q`5>nN6)2N{Kf#tO8KP9(fFy-zU%Rb6hC zqSuh5PI^*1k=d+CZ4diOce9tu3m!(58$yjLKO`6jkt4h!W1J%8dvf#_FP=Q{qO#-h z$FH!X#5{;>FPvy#V#jgaj^oL?9fPsM_5WsvKUQcSMh^$<&_a!&4p^ck7!w?L_sfvt zJ2u52-~0T<6DME%!uY*(K6ucUPcgX5c#}b`#hq#9<9p?=z(66_js^ zK5tt3-|f9DXI7E-UXSPY-T$29@{9=?6SnQ*eaHcR0?n>Y!Z_I7X|c0h%uJc)&gM>4 zK3b0_C(0D-9P1P{|2p~#bxv#T>d^Ov<0kE2*kBMQy^M>2RShdRe8I%%^G<825H#uR zxZJo*mvs^eW*5O{shs)tyc6}zsb;g&9K$3-0xQ3$S^U&EWS6=5uj)0!A}pdJFes+! zl|h~U*J-WFgCw^mt|Kkpw&~{GOsY(fyH!rr?pJ^9vU;A?WC4w^n|MFNptoJAU#Zje zhL*Ku$Q?_)%1HUMHXLX~ILUfB*z%)dh!!|$l#6>v+~f%}%#$Z)Zr|_YA2r?8O|mrO zIeG8HkGOBlO&>9N$kec;;r<13wEo6f=FIu&8;TaY&{rVc;vMfZ)H==9(@hiP)hp61 zUM;%eH2at;U)%e9jI;ZmM3%KxM~53{_l!2Y`(2fu=N&os?tpXe{+e!l%XaRYJ|Dw( zm(Cf!>*+NZ^mCfbl_w0_4F91`r&bL}=BqE%E^6TqAKSEgt)zTT?C?K+|LEh-t)Dfs zY_{R2yqMzjjgLS2{U0C5DVv$YV+8BHBi&Hzn1pTWG3gbz0>>olt$;YFf9-6x;y^WtWAC9CUZ&EOiW!0A4&!(6~6bU0tJ>c}jB%IRH7%Ro4weBytD=jOXDt{u!X#b1{Ji|a zXHJeB>lF2!_wZ@wiWlZCG{>8K{h~+AT^KsEAU!3vJ#bW544oj%vyK@VK4nZZk#xAM zcfofrRHK~^vg!ue8mYEEskLdungf0@-u@v0e&K%pBYWSycz(=O_h?VQ>z>P7=IpzF z_Ld#9(?=&wO=?i|MI5D3B$cdPRh?)xxOsaHr zY9BYQ-NS#$sGP0YB|-jQxv?f(U}R9Tm+z=xmV@{AW=LP_)5qZqMpnr(lLxTo@ajzeB9+~ak<9+M?0S0X!wv(?_A%^PIPuW6Ymx(&tld!+RT>fH6lfSfDbYQ-@ZlYO zme;RIiIm2aZAtk`gU8^g@Tf@dBxjF=;OUtz&Mu*=H{GS$|4lu%)!>)mc;DurYXR%ZB4Sx?$r(s5qu5JXRL?g(4+w0VH3yDrn`3A$~B`xGW-{;S$N&Z!m$a-Q^Ke1 zt0@0c4xhX%A}Gqw-z8`yv*03TV>D&UaaXb} zkDaJS)F^rM{F8lUN`U{2nEAblj_Z_Q33wR!=jS|{I}Jc`B!hAG>Py^ zc{i?@ceaKIvpLixHHKkL9>YwUK@<-eT;?)Fnheo{jiIJ!5$t8^>Fha9vyzu@nmbKr zlWAJcoS*MxGQO=?WPRuB(u;cZFiNF|{8XCMYkIs%XGynQ@9^g6r?z zo1dEgBc(JaJJB!esv}fS*6YZaxG{q7(vPv$SJ8R_(}y9X8e+J-u2Q!Ll{eL-OMNb| z8t5^s9&R2T7ff#=Zg`C4ukWnc6ZP=+)%%=B{wZ(y!MWEi95uV@LCe2CKX@=v2B`t& zEG;%br{%_3gP|-mpn}eSF&+i*K1x zNdGdhx63wns$Ew0cBy`{G!K~Lq|dD~?xg?ul|HuBD#saW@u$yO;yWJEYVL|Y_w2}} zcL*FA0kpdF_R#ANxpsNSZT;>aOOr8^{;-<+@rluqId8k<#NH3+x35y^XMMlJa69$= zczbbcU)*(dbsbf=(tJ8X8rKu6A#~NInNgc zWmr^sLHf20E5@d{g-*GzaI-1?rt6m#Et<7BQg((!$4B~0IU*!9)8F5+dC8dA;n&FV zcNH$F+!`O@H1nb{?vPdFFWa1E zHO8+>iq-c1t8Be@jaGA*jdgkdb>?!c===BqHD$R%x?C}3`7zShIyZ46Vc%>GTkNrz zao5LmjEr-r@er=lE=#8+3im6<8YNd(ej9csZzERJ7_+W;8c< z(x3Dk2i6}Nv1hxEcbd+;W%{0;r?0I(aDUs=cbt>{cTt2gRm~07M-_OZP`%dZsW-WK zL(e+;KuI)&TB9KcPs}Zt5MNk0|D~nN-d^$cxvVAmnbA_JxLK}yc=_G47NyVStDDo+ z8VBQ8;$VB>LUZ0EKE%Z!jJp0utZ^RVH27t%Gs|Mslw`PAW4=R9Psy*+gTe@^Qx?!`>9vi(ADpzKgd-tYj2qJ6|l^Ca#lj${R$!zI{vIGMuy3 ztZQ;eyeu~HdzkNzZQ@?EkoBqx#X;DKuL7|~j3d}Uti3@#iIxQY_@r1O_T#qzxg%m3 zzW1^n;dmbV%Q#mcBiXx7)QDXCj}__YtmFOiqgWuY{(i!FO*rH7j8xBM1;_dNUOWp% z13j4R4`hFo6*3B6!wqpCG z%^kmXSrrGhsrW4G-!d5`tFdkA#4MfAm-M4TAIP1gfdHlTN;aW$Ab0ltjS}NZXnU`u zubYy&4);x@!4a-Y!9e;xrJUV_9~*u55x>KPxU8Qn?nOJf20KNM{=1Fy11aFz*jYpD zeh(tTbx&8AFk4SilF`R-zae-Hmnd&+P1NzQz`K;CuSw$ zpICGsTMDrV5}Cw(u9(5wB%{PQ8NyS9x$-KuJLCd355@`3@Ex=+S;zJT3(cLD*)p5; z;x1@|WV}KSmp8~q*wndEtZv|sT#kHQy0W5WBcsGIeAYzbYlwXl`{mu@B(=l^WK5Ij7ktLc8KOxpm8S{w3&X2@9>nVn(xzH-IPXl( zdH|j7B8R>0r0g<|RgJL}wKasuszH+~j;cxn9%uoxw-7p6j`1^!-bC za2&?R%O}9tIXA4)j5DV15>Da68cgrZbW&9n< z{u=C^P0ZGCU8i%bNQRlX%;G9$>oVb7@in-Yp)m!0p_HtLrKhNbDYOuB31u?tFz@B> zQTE61`xK>e4xv1Wbq{gwF7c#v;`dRGzr@E~q|=k6{aossP3V}5pJi%gfB9F+O*$L@ z7~5M!TlkQy5pD7XkpqJFQ3APl2eMgPAsx(AKgE{8%l>)VeC)jG=H z&QV9+RT>k;S((T-f<22&S9;mfzd_Bzl zDm3+mU%&r}g!8e@e--*lX;1AXJ*T7hRz`aQ$el9@X$$pZ9_gDcOq?l3at?$NCq{&* zW9NyrJ=N&m&pmFCTrCIjZ2dp-UwyrTb)?uUA+?H0$3W6h)!c#lU*%@qU#g!OLY=D4 z1mez$YUIFWQNEVj_SSKJ7Du^aD>dwGSg?{S?yjF5PPrHdGt`pr>UB%dew=V zEZ~f^uD^X?5&dZcYbthM)(oPt8TsN}dCMsk%j>+6DGDmikq#XMvk)U)$>#`>#FT z>et=^Qgw@JSq((lq1saev9{<`t1g`qfBELocc%B@-YU!WmeGBAeG$|N4~To|Kk(b< z+2_e3w}0y`=^aCuhjn-L%Vzn)@VCiOY3$w5 zYql(~EWpzKt*;Qh?LD7ZqIM>-OnV8FH5p+(PN=( zRo0v&Y^7akQob&a;TUmc9F-pxM?EILjmzaB3-j-WeJKoTYRkpG=S8?YsX5A%D)x5G z=pJl&y!X82X7c5|;z!P@bi!V{lx4W(B`hJ$`qN=QIZwreC&ayCQ@&x@E38v7u++|kh_t1tG^kvA(Hi+?azLk8oQ%SQow!5g*tB!XMM=c z>By*mGeG%sLqfH#MBjP6=a@j9tqAVx;x`h4`5VBmH}?)pKM!-~|06ByOty4!RlmDB zw#zB$OWQc{3U^DzYqVXG^(~V!JyyxcZe6$i*H!nY{#y6!S}ujZMLfc`rC+~gfNe_J zfxhr$7`SDUUU9fwsZ~iU!nvc|M6CWOCh0wnV(u)#Z z9Oz5=upbZHx4Wrd)fTWHPvjmQ@SDwgosx-#b+bzc>3$sa=+pn_bD^(*OF@-X}e{T`bzH7rmV9c zUE0s&nkrYT%jHMk=x5a5msvl#Qwbs!mgtbJ!c(^L*CaoKbL2Qjv7WY1r{*UcDYF>^e>FdK zBpcOvtIY2oE17|EcKQFWzjk~2I%PQ_m&2HFyST}SzeoX z+4-%{fi9YQ(~y5WVV#Dy)tAm$_id?fzxLMO&%|fSUA5`@&)eKMqo32=?fdp$yB5_S z`<+d#9&Zm{?W=8|+;4KFHDCRXCcTyVJogMo`kJF*5%uhNwnl2xk&N*V;hsE-I@g&N z&T>Y8-qw3vY1Aaqkih7MJ9WATxYC|cYYNV$Z+A0#Pf??W;IfLdfk*|ChppQI?*4z_ zu6i#cC(~&&P2ryT3HOQ7$fPo6k-*4CGJV9MShIw)3+WY|VZ7u3ZM89CAAOrujCNF@ z^Iqh(^3>~I>c3HP11+&N3qaQJd-$ z?5AZHLoZ<)Jti;iRWpdi2;4^yw@UGEEK!o= z!QKzp-V=Y9Z?pM}pXo1c)QRT~I-l5#;qQD>@K!e3OL7i>SFnxdx~g843jJQ{Bjsxo zS9}D2N0W1+bqnWHFG?&35}O#^>BXYC#O!L`4q?NlKDk-6;zQMjx!mdU+45wPOcJ}5 zmHg#sV1Bmk@5G{o#JWiDD@^A8y^IkgXHxqHa#6m$7N;-UKkoFqdsF39R=QG~TJ7{z zHu@g&O~$dllHU-^Qmk4^QU97$TSmTiC0|bMYwc_M-~RH9Y>r+&ZNJ1%z0=$I-+t-m z7Afe9s(Sd#{$H=YXZs#!>+CzNhcEhGP`@$}Th3~)&<9?7aN9!+QU)+sPE?PL8L1I*M=TW!qcZ%$;F7-#6!y z681_-BlS$hHWES#s1Xk@m9jh|`3lSQX}TO`T>%f~MGNV#9?(}X;h>zxaT8DSadyau zI+_mIZ~&0wiJovugkt6Zus^6!2$vve6Jl_YAQJ+9+}LqzWdLgrpwA-;%HSyU@Fejp zvkqVg=e#!ai8ET)-s+byhQ>jM5I$LOfNv|K%l8lvh9CGB1Lp$>FOYMAtrX%$A%dL& z`$J5EiV4skRsw_(?gzO*Ji`ei!U)-{Q)C8?qtF%A&8&n&EH57hokGOm7Skw1EHbgj zc)toABfMdc5F?$TR*1L^sAHh>6x|2pMiIXR^d_>OgnSZVC#OM=5Gk>M-qejY&^@|R zh%sS2&O&x9_NE~-t`H6|U|vsWy_!KQY|TJlMyU`J4nvC&6Z4=!h)LN(m^p9Gf-WH@ z=fGyz1L(^vgEm1G4q;#>3#39mAeVIrnuVBZ5@Om8h6d9h7fPT4s-X@Vp-qTv!phD7 z{9Gj<3b5g-jZg!}=`5jRCNeXN0G%`OKNIk-Lud=t6PXU zB~Sr`JBM>~@HYp4xrCb=1gVfC#N1-o4Ex|PAUC&*;WBU7$iOe>=I;Z}&2NS-A@W?| z5OfN$APlf`K`s#H0>WHCmsLI{8Y#R{Nz^x{_^Xg2|84_6#O6qir@f``Qm`{1zkd1;|*C*2pfU0t|6>zjzO~! zg<*i~;vH}Z8lVL(2(hFTa9=`rOORPYc-Io%wS;$VBIH4%5JiMrR1Q^ujv{mvp`!>L zOI-n*mZd@oAhQgaWymZ;W*IWeaVxHYdT4?U!L14WAQ7^m2+9H375HC){}uROaY2Zc z&JYG!fXvEPAyyIBRW*RzsxBc)f&d#za-a+Sxp+PZiY@F z)))aDYtXR<9cvB?vDOb-0KcV#U0MYfgjly3a9dvprGSp>(qNwuWpS`ai0cypnGNXM zfWI3|uu;&=fNa2RBj-1np%R*exDnYKE1;1_$++K?4`t9MM0p0(3UM!--=ElwiUv0A#TTx z+X>_LT4)erJN~x&K_X-W`nKa|dlei4CDQ`kLhLXBayyXQQ34fE1NG1d9fGDegn=3I zp$saa29Vp?1jyYXzz@)OM>Z5eIaI+RA$A!d2(Wh-@!C}k#Cz91I1I;u`0eTvqS6(j zAOrHC6n4M?I0~oWEc6I*r#Hkw78Jrp*aNk244R=+h`Wps1gX#{#O_=ufeJw19_-yy z2k5*Top+=2Zgk#_&bv3mJ~#@<-hCF3yC(?HcTWx!Lz57D(X+Qjh^jO|_FmlY<@Y}H z+}9?={iM}P*}l@Jdi_aNau*vj;UN+BLHL5&a(d&3^+ z5#o_rAr52%`+sN>;!)fm3j^X+ga4WXLOhPY$IIY259INCupBN3@y85c|Br`+sEvhc zXcpoLY8N7;24bwMb@ZqZFL^_y z5HAzX%e6whk_PyD1>N=Nu0IS-LcE#_4MMz@3Y`D*W+9Gc2=NyaR15JsVZYuZ#2e^r zAk2mmI3&cI=znt$v;vpLeiSYU@m3sQ-&<#e zIAMkZfd3P%LY#DkAV`EPCpI$4}|qjhY;^#%e#kx zFisK1sUkqnDRi7_fo>t*L&tmgeJ>W$ARF>w2cYLY{QjNuf9L$)Hv;Z|S8iQG{KEus zfc!topca~;M~J2iQHGXeTBcTPC=^>XR+mMCG-e! z4jt!e>3AApGjs~^O$K1cH^%|_Z@Pr&aD^zq{o6#S2K0a1D8zTUfb2hup-G5N&UYRV z;yixN2f-fb6ykgKzb6g9zaYd970?Fk^Iu#j2X-!&0Q(oQ?;>GbY!c#M==s-1Q2QN% z0TJ+nM5qVcyUGBaT~*KsEkgWg26X)74RMeKg@DXYHA4J{`1~go@Y~J#?hGM*b_R6+ zjK81jph1XV(jXi1p#%=YF*pUSLi`#gL=XOY@YjRxo^IYi#jm9ZknJ-;&wy6w1pIh-1MVKkd7R~yQqG(3Ybu2u zK-iwhcyjEy8IbcN{2{mv$$<*M7BBpH5w_O_rn+LMcNi1{_IsmuXcXiF{)g7WF+kP_ zIiEx*0^EJj<;$^eIpEK?OGrN>1VJj)Fu8|gf5P_PCuD#t6hj3Nen1^`3K@t@AT|a@ z0k#F^0dj#G0UH8q0UH9F0r?>0gOCqGJ_z|BHxWrCTIg>LkTYwo5ErN*|0_-!xNzp&>LZf z!_X~cq#qy?g}qT_Ks<(30{Wt{J-SB7802I22pJm&CD111aP$rD5OPEsQ~>fL(KC{8 z<2a5ZoOtYwZvf7X!lqH1p$2eEaE4gmIDz9tGgJwgZUHtd#FmBFzOWXK!f_$5E(Z4V(UXtNq9CXivVh|Pj;}%IH5Je* zWML6B3b{B6a9ffA$Ar8#2RL6uI7R4R8V1zr0MyVgZMQToD9mumd=^qD{z^ z*tK#qu)iuBYJ@Ctg+gcm+*ij!i;!!KfZjEnTXRatwYhLs$kHYu*I~!HE+N2m0i8l_*dyc(_`jiA$c=e`4VyBcN5~t|b5o^|<>)ML7V_qOLf#Su$A!F= z@HY#26W$Hg2Ql@ zNBYR`DuQD|R)#?yVBehr2U#I4*1#A zBIMnKb$5l3_ZXp2$i1B3TLSe$RiBtu}}id&?Dr2bnHiFe;VY#DQFe)!5}DuMj@-wUtJ^QL%2PJ-iMlmd>DTZR|4{n zu>VLFY=k-?50D-Q@&G>vjtlvRLg4pN!gv(7NAdHR8ThTiPfdf6kE8qX9ndA@!D840 z$AtW&Gn4_cwNa1(=&mgVwmm_7o@j$^A)hos zESMo52EjTquDGsD?UdgbpE}MebSTo<;6i&EY z?pfrXMef-)=oa#@31Yzv`A`OxPzw#v0vCjQ&KbfW4RWCbDxezbpb^@jTgW3ONCf1L zAa?}0Bgh>=?g(;6kUN6h^T<6P3uefNGN^%EpS1| z7n~ss(g4{PkbME!7m$4c*%un24Z4MV(FCzzhI}Z4N~nQ)Xo3zQ|0KW<5+NIkpd6~; z5HvswToCf8GlW4J_*f{2&psp$N*M z3JyU7w7>-+UvY*oNP}D`feNUGI%tG8=w>>p31Yzv`A`OxPy_YQ1RX-YD!>mCAsdRI z9ID_DG(Zbn5b`x=2!k}pg%YTMYN&%oXoGGc|7?O-Fhf3+K_%2cJv2dwkaQX3F+WIz zY$$?qsDeY#04;Dq$iFy47^Fcilt2YkLmf0i8*~f#x(Q;z4Eaz7l~4oq&;%WT>>J3w z5e8|H4Ml+b8_2&=4Rz1}Er6c}0e+AO$TuM0P!3ga2#{?+w&8-1Z#qL5q(Lr}Km}Ao z9W+84bPE>PhgdK}K9oTv)IdEnL5Glk6W|AlkPSsp4pndn8lVL(2zlHY!XOQDp#&QN5~H| z0QV0M2-zG3T!ZE^K(4t7I)(hm894V*p^a7{KSuAzRYHCuU^CPT*^&!wLVjw3ILHI+ z{q&fSjQPmZVUP;hfUeVJumh^$Ff>3jbU=@gpP}b7!u<@JKFfh3*a+zS>;TlkacF@~ zAzKA_Lo8$f=RYroE+NmPLXD7LBtor_ZF_`dOhJQ6=QJL68ScLVkx`-{I$9C-FFs-t*-`eowgH*9!RqI)5Nu z7dApYG(rpDcCifbbFodxe+dW!GZaAu)IbBY3HfgUVPJ+LsDNrf=fBa_g?(MQfO{8V z{AdDXeXy>5b*2JDKy7aD1$noIdRUZ5^#5p1N=B2295`11AYb(mP-^ALk+YE zZEzSMJGfqGuGry<4X&JX#h)8Cxs}6FxF9rlj@^-U$3Ay-c@PheJ%ApQ84d`|6CIxD z@KpP_55doneb6B^uPms9Q$q8`4)2X{Txdg)8Cne0fSeEKe5!=z8w=?2trwc#4(Jh@ ze;hOlEdT-wp<8G{T|x`4gj(nnT8KBGJA`k371RA^~Iumiej-T0q}CV>ue9UEGOc0(9cLXFTiqH81W8#&%s4TqosTHu1v zHaUYIlt7ozZrmrdn>Gur+$^-4a{;$o@OLXRw`M^F5Vu>Kg|^uh2zxW>w;BDLYoQT3 zg|>xrTM_}iTL^DUx6p3$h8#fdHtf6&x2@=8EJfRT6q*3P70wU^`A`Mu+-8Ifz_xA2 zg?76MQURIUal5?+lzWHJwiEXDM977WPz}eR6?%lWBM6A!4s6?j{vDj#fxn&T+==_n zQrHK$?>sBCJ8-`v1BwCnJBZI6$nU~^7w)^zvkN`D>H+ym+$+v0lW5=LNy$RZlP7h0%29*zY4wg8X*hNdG8_U5ZZm%cpu^1w+EVq zcE2BNgj(QuAAa_wLLQVs9h?IEKESyLu;+mc_K~;e-`eah5KhM0zC#=qUmQN z&)I0h*~3BLaW;6IjkcV<5cCk}J(ltT2cWE;SeYtcY=q1p%nts`8 zpcu3}XfEh_(2tsa`5_?Wfgedxrel6;`7JRO~6!fX4Ux&2oiXiZ~ZX#%jh7Ur5wgNSSQ1A7R zY5EN-fwl#;fS%Iy8w1c7&@mv~zX|zox?a;44*@LzA#L%unttDEY5HSm z&tu5uEyp8t0eGCX`?{sSVyQu%YZ8iP* z_i6gKb2a@t@c9m9zn=&~nIBNc4?k-9kDZ#1-&ysa@6z;N(5GJ!|2z8h5A@@oMNR(~ z>iQS%|Gv8>wDm!YHBmrVct{g^09vF8(FsBvy0w5lEzDmuVGReJ0m8MtGiV_Q*Ukx= zaK~!GtIWF&P`0i?6X_wEfUYI7C7KvL284P?f2)ZxF$n#t$Mtrdpi4pTX=3~J zK`6KVVoi+2^|$~uUlZd|--OpRvBLsQH2k88DX4Qt+~4sSP3*KL2=(sV0{T=FyP%D` zyrhX;w*uk*u1MQ$EC@VyN8P*610ijX;ULtvC+_X7X<{m`fki5}eR0q@?sG%*Wx&%R9)`y<~0;5T=HCJtN;gt`ty-UF`(y{CzThJ(QKAk=x# z2_U2&ggOuURuc!K>>&mSX@?%6iNiDy${xNz6GtF^1o9k-x{sU(dQB5Y;r>xWKodc; zLCAO1V<6-^dNt5o(3hGxW=+r-P!9-sj(JWK$Kv|f`Jjh1aokFvW)RwQ++84)Ies}1 z(vH6kv_umpAbvsvXdVb-bz%%U1oV_9APdDwsP81CpL_)9Elr%VK4`8cPDOYs>O5_4 zO`N_J=rv71UWv1YgU}Ah9dS15J{#rF#=Ut%K+PcVnTNXP{iq52rXkKj{&N~YM}ThA z#JMPUZXM_tkc@-(c@AhSXaNZ2=7Z0Cl${U0^HJyg6F`eW?`h)v0E9ZvNBa5mK;U)$ zFPgYueGuxnpa*m*=p{{DXnE<*W>#(-`Ep}vd3`{KEvC7OUd5|``_ zIzkhd4h5mEOMlbEWh;SD&t(lDq+NCf2s|zWZ^#~T`I?|QP#XyMF24(e`mO-4D`HRs zXf6n4u0WY9zSP9R)j%k-uoHxSFI)^lKdu}OY5~myp?z0v1sV(L0U-^)M~JIl)5O(i z>(xhqUed&(A_!#`{ium+P~Wwf7yLFLuDu?F{MVwMYk$$ibx6N%2xwc-&LHHy?ikPl z&~2dSK%Z*jdJVK1s0K6!v^Qur=oHXG(0!oSK;LTO1_x9G4F^pGwSW!*%>!Mpi5qtZ zq3t)G07Cz7LY|wD=O*O233(PHz8LYvh%ZL`<_1t32z|SGK4>xMDbNxS`ghAIpame* zeamB@_dvgB;@0IrMG(r|x=0hZ%?2H#iQ8*H&7g&#+dwFDJIdUSGIuy2l(_?W?m(V9 z(9S!+_YTx?2kN-vA<#>pFG0U);?9*o>w~rejRm31opV8FfRO)Avzymu`IJq20<`b`seuLK$jssrr~>H(bqx)gL5=q1pXnz+XRtqF=jV?oUz zVtxVIDZqbBYPKp>Ws z2QfAeVr(8-4ur9J2-goEqKQX_g6crKgL*(GfKbPy$oDAtKe`0;nR10cd>?@;;@3T0l!cxc4-!pI!h$ z{At9WnWu?oQSY;;<5|@4Eb4d`>Cd5#=aBv!?mxdX2x)l!PrPsfXuc+190S@LG#hjZ zXd&o6&}*P?HSv-IDuRZCjsd;*=k#)$CSG0)LVI4>3Ur1hUVTavudNSSq>0y&_B!~z z{+uS>Kz(nF1%cNa;Pd9rpd&yFKzD(V_7?KIH3qad2>0GX-ER*8-KU9nnlR(6>H*H_RW%D<$>p?dH3!A7E3B`XnxSdhDurcauKeF#+I_q(;6&|6 zUhA4s*n`(XTe)x&uMJ$oQ<|4FwLsT+ZD}jQ4W-f@ZFzkLuYGMT{Z3vFa!+3+KmL!> z%V_aBze9s77%pP>fYfzCD;A2p*74r9$-EZYCWWcIHgJ6@uT5>W!pFR}v<>w^yvAux zy`I;;wuOE$uLrHTq5e9rm(g0*ITMFqIMXgqoXSs?vaoJZ_cOI*vOciBj;%_r@ zdRiT>_CXChYQ4zO1ip=^Wja!2iN?JCB5G+ztP^>rqTW{IE24Y{_%`PEJWU(b(K)B9 zb$UxraY)m~#jvI(Do&kK9NF5_-P2WVoH4Xm-`+H=SliZCoFsE~7bjJ_t6ejz&BMI9 z>OPG-_7xSb7XLEnPvTiE}(kmaJ6i?oXNPQ~9gl%9o6AeZ&PQTe}Lta90V zf3k&&*aUKOG=kH>Hvi|w^fY-4`v3Mn$^Ad;{C~gM{|q(;_PLc?Uak{43UUp|4c?{g zixKI-%>P*p1A#~OOupu<3*}^O{mWd{-ICv{62zwGT-x(h*_;E|G^D7RSKJgFsnsU= z^q>_Il-hF;?96MEYg2Bd4%FI%dlIT7P0w@6Ria?EuLnI?>2hri+!u|=CG*X|`d790 z)gW`Lwkz1HqGq`|%s^E_dk=q^maeb134FxEzxn>;<)lB**?Sk>l2h(dz)0UT~2u>}ySP-UB(Otr(+T z)FJQo@#tIW|H(ntF2|t>E$cR>iT;$D<6*;;PXFokfSO~PQy6J7pTaXoNu{C6i2yIWKTNses?3EeBoym zqb0{%<>})i*RkxcM9IDxl0BCzQO=24Vco!WxjP$jPIAnqB9Bx9`sbj3ruxQI^7>CC zkiu5hD_5E9NB?N`?Unu!8;Ah|%gNqJRYT2`#Q8t2H8mQtKeGP+{d~%P%Cc(iXXK%Z zOSI}6qyPPE%RF=PIh_VRsz*vb^o`ViD=X1as$;7ClDiypxtC@8)!J+W2f1SUQdCPN zx=MWQoAds4+^=lOeXhp27b75J{XLRpCAv;W|NB?>bmWu0X+r)dm^UemWP6)KDcH@Ob`DySKeva6WyU^#xWjk3jZ_55)U z^sg7yyFbHlIVZg+E!XtG5&pAL?blc2`1a3X|0v2{{kPWtalJ{5l@@|*r|gN8|8m#K zagggu>Vj(TNsU*wPL>!bhgF#-=tzyZRxC$D$wj%U`q8zo#{UF0V%;Z6x`PM=99{nSUIpfh}!7dOugyv%XfzniW6UvT=w_Lj7ad z=33NUpVuebFZpMAz2oyzvYZ?_+0t6jMEsouuJx#43QEbCOr3&oBJxc}Db)@+ezLXW zk#{`mn3RX3abLDT&4e1OQOGqByk(BjXjent3du?KPUe)YYQX(kjEF2Rxo)4Qs+P$y zk+Uq@(qD_Tqa<(D4mtiivOc*6WdG&s7vah#lUNRc`YX{ugTYZ0xIJ(2BJqcH{X zI^>k&AbTk5koV-Q$nhMzG^ZLjwHD-@)*{EayyddI?1>za{?#zBCw;a3ad!S}b@Z(^ zS(ltQIZ|VDE|W2`DdtMHOQp#2a$U)lKMFnQUvX;P%kl2Zt42Z2&-i?1cfdTW8Bz5~ zJ9S_$WL-PuGtoaEY6fHr<+_j@`^Kz)_9ai*=DzmG)ht(8-#qk>irjy4jY&>&708(6 zAoqw|V{(?{y}tdac=XNVl)P+Tt+L!7SHE0kav$~O>nr!)utSYeA8%QAf8XV5m1C(| zC}&xX#{XQeLirSOO-jhl9H$j-D~-3${!?+NJ=EteyI^jJzeR7 zQs+~)t#HXc^|KX8=}^Su7T z@G3SIRn1EswBBa_^`GZ0&H4Y?l{=u>IpI*(%T4a1)}wAj;8Y;2!X?1ZxvzS54VJ@5^; zwoeC_CitIa&YqTPQTa6+o0>XibRxUV(9?q2;ZLr%cVmDD=R-1hV^r2$Z0zptXliW) zKRBD4dS_JIdm4MBD|T9I8{E-DWQ}=&;^dBLJ+m-FgE!7w(pBy3>S*q5s^--+x5Cri zI<>c_nzuo6SXy8x9NJB7z0I;Evs!yvI(mE1m>I2PBst{1b2wu=ioM)aLI-7>V;&ts_Mxp_xdvAYVFI&!z7sqFs0v6g*AwHPxn$8_|LW$F;LTb zyV_g3TQDLh*xXUS%9nl>^qjh37S(D~(e-W>)ha zs2>FK1}t3!?HxUs1}qHOEIBKA!_*2;_ln&ujp)?WDn|{?!0!PvslT5c?N}FG#Tgyg zFMrnUV$Yn;>a<2M!hVpA`oo|UXEe@{_0Q;NZk^UD7g}Rm50)M-P-$axbKdiOjPsu& z8oSWu-nPcByz9-??$+t}kpXf!oIfj*N7&zx6LWG{$Z(O6uPSIjWg7Y$&2nH22;*W-xjH2-BncwW_5HmcNYgQ zg^9tEw`{V!Q5-C{?%;gbFgs(pXQo!Mn`EuMmYv}k3-+n(%4gMY3#=MSKF7)Kwc%-^{?>eVsCph8{FU2V&1r7-oyVkv)%Z` z2RpmiiK&wl)mX&rO-FUz+{3ujv~S~dKr8lQdq=)pWyb&Wh1EB;IV*q`e(I{WO_Plp zlNPfH;~R>TCu9vf)lN!_^^=PeCr#L~zAmjR4z8Vy_~4<%o$4FLOqkM8M2<&MnN>@u{N)i;cnb!Movwm7kNQbYZyDPwCV z6(>%aG;zY@6m`_0+VS<{vq|8Rj!V%AR5WVB#9b!Uj~>%76ond)IJDR>skSa1S37C@ zp|XV&(B(Y;FCxp~bq|akZmmclwyfZ0t_|aL59q)A8w~+Ob26lP9L5 z>g5H-v3^oI3av#>j6FsIsiFBe=&r1% zVZtN~2%EA~{p56Lv364ZWH}?*qzP!QoKKXHeVl^vMArK8Y_FUnnI`Z3adjYr7vvLuq z5N;_B2vs%@BxT~G*a-}JhKWE?3Rd+J>4O}WL7JLsT3_;9Wy#8_qrR~zzn69 z<|;N<8{1Hfz=%!$M?mNkh@D-nsCZUaYY)Jr*w_m(+10u~MKL(!z54eaNG|{0{;q0w zCnQzt%xc@5VPMuJ<(X_RkQu*A&S2MbY;5Y;qEB7uDNdIo1$hU==$byP2&GK^4F7-k ztLWyrKYm~6w3~yJcWX9uJ?Wk8MA{$yeE)!<$r@8^Hh8}9M4g#N(bob^ez9j+Je9FL-cY@wwi4bI zy$arjyc*t&ygJ_1x+dO5yf$7{TGZBsn`b?3eY}@=L%h{_2!43l1kZE~#SftJ?a=c5 z${~Kkj`8;5GJeS(j<+>$p>3&cg*Pg1gLlMlo12rPawkQWyE5wWcIWLe0OMe4N+-t- zFj1wWVG3Lk@*ViQpf9^=yK8&k&DDEpdqde?g!lL#f!Fult(~QPir4dF=})w5znAv>)*f=Zm##@XqZ=@s?TnEtykb z+&l@z|1s?e?OE+9`3`5i+kKk$qV}BjJl^6xUHcaAWqw6_NqZSn^##7Fbu4~-X@!Gt z1`MKhZ2{Ew{V;{{MB4 z20k@u73_ke{S)8waSL7nAC1IYoHe`?e;IrurchW8AFW-Xuwr4Q!piuX#HxkW@UGp} z3u|b?&q3+oluFKked-;o%CFUV|C*c4whcokoq*$iKl*&OdP zF5zo5Q6VlQg)-i1J{(`B*aGkS{t(~)+N!X1VHjxU^0II(b2 z;pD<8g;NWs6;3alQ8=@3R^jZzyuvy7y3=`u`GxZf7ZffmEGS%5xVUgh;nKooc#HKF zg@uJH3s)7cE-WfsQ@FNp9lil_L*d54O@+mUo8@P>tF;O)XY_@df-_}KFYc>DE|!bgRV3!fA|Eqqq^yzoWg%feTMuM6K4zAb!L_`dK1 zzMb|H-kSY$;g`a%1^IQg-wOXM{HyT0uHg&8x-N7>H+4(5bw_t~PxtjeAEYm%FRL%7 zFR!nluc)u2udJ`4uZlPD|3zP2UqfG0UrS$GUq>(M>*|B`_4M`i4fGB5jr1Y<#`-4u zrutBQGkuu8xn84}^iYrVSWon_UeSl^BlIowE%mMRt@Um2h4gLpT79HGO0UyXJ<~_) zWAu7`JAHe7tUgX3uTRh?>O1I@^vQaIK1JVA-$~zD-$mb5-%a0L-$UP1-%Hay-lB?x9c5xr@o)wrFZK+dapiHpQX>%=ji+E2k3M41NDRS zgY`r7L-oV-!}TNdBlV;7qxEC-WA)?odQ}xrd*R=Qb)Acj-Gxf9d zv-NrUIr_Q!dHQ_)eEkA^3*as7ZS6h09`9ZKLVbaLk$$m$iGHbmnSQx`g}zX~Qol;S zT3@7JqhG6Er(dt%px>z9q%YQQ)^E{o)o;^p*YD8p)bG;o*6-2p)$h~q*B{Uy)F09x z)*sOy)gRLz*Pqaz)SuFy)}PUz)t}R!*I&?I)L+tH)?d+I)nC(J*Wb|J)ZfzI*5A?J z)!)7VOg=wIqz>0j&L=-=w!>EG)==s)T|>3`FI)_>7| z)&H*lL;p?xr~WVfccF=b(1j3&Foh*-;RsiF!WV%UB$g4&isi)eVg<3HSV^obRuQX; z)x=-K>e_{34Y8(JORO!{5k;}C7%bKk>x&J}L|iH^6PJrC z#6oeUxJq0t7Kv-bwc~;wSMp@w50v{3`w~ z{vm!7{}lfczZ;rSFmyv0hG80(VH=L&8lK@BficKf##q)^&RE`9!C28)$ynJ~#aPu? z&G?J4y0M0_rm>c>wy};;G}bi+8|xYC8ygrK8XFlyjE#*=j7^Q9#%9JaV{@a%C>fy< z8L^QVWusyYH%1s+7+V@!8Cx6M7=JakHENBK#werCNR7-GZHzJMjqQx>jj_f!W4tlJ zm}u-^Ofn`L4aO8>M`I^rXJZ#*S7SG0cViD@Ph&4*Z==zeYBU+mM%9>ROgCDLR%0Jy zU!%>KVYC|^MyIi#(PeZSJw~rF)0kzW)ZZ&Q*Za3~Q z?lkT)?l$f*?ltZ+?l&GV9yA^@9yT5^9yJ~_9ygvao;02^o;IE_o;9AsSI}QDUNl}Z zUN&CAm%d*!UN_z_-Zb7a-ZtJb-ZkDc-ZwrlJ~WmX9~mDTpBSGSpBbMUUl?B+Um0H; z-x%K--x=QQV=ikhXD)B9V6JGcWUg$kVyA z&5g_<=EmkG=BDOQb2D?8xw%18tGS!GySazC zr@5E8x7lb;HJi+4vuaK=r<*NitGSQ4ui0kKFx$-zv(wzq>@vH}9<$e+Y0ffdn{&+l z%>&H2=7Hux=E3G6=Aq_c=HccM=8@)6=F#Rc=CS5+=JDnU=85J>=E>$M=Begs=IQ1c z=9%VM=Go>v^BnVB^E`9DdA@mpd7-($yvV%Ryu`fJyv)4Zyuw^)UTI!sUTrQiuQ9JR zuQRVVZ!m8(Z!#B~H=DPZx0<(^x0`pEcba#ZcboT^_nP;a_nQxx51J2|51WsekD8B} zkDE`JPnu7ePn*w}&zjGf&zmopFPblzFPpEJubQu!ubXd}Z<=qJZ=3I!@0#zK@0%Z( zADTvuctre^lt(B~mtyQd5t<|i* zSgTuWSZi8qS!-MCSVe1HYp}JRwZ651wV}0a5httkKpOtKQnq+TI##jkCsE6Re5W z4%Q@VvejTsv39g}vUaw1v39j~vv#-ku=cd}vi7zbt*KU%)ofL*Y1VYB#cH+ovG%pv ztQl6j)nRp7`&nI9x7B0yS~IO#)@*BzwZCb8EI?OuUI>I{AI?6iQ zI>tKII?g)YI>9>8I>|cOI>kEGI?X!WI>S2CI?FoSnrEG3ook(E&9~0CF0d}N7FZWq z7h9KDms*!ums?j@3#}`ytE{W7Mb7VB2)HtTll4(m?q zF6(aV9_wD~KI?w#0qa5QA?so55$jRwG3#;b3F}GgDeGzL8S7c=IqP}r1?xrYCF^DD z73)>&HS2Zj4eL$oE$eOT9qV1|J?nkz1M5R;iS?27vGs}dsr8xlx%GwhrS+Bdwe^kl zt@WMtz4e3jqxF;ZH|uBX7wcE+@76!8->iRH|FV9!HM?Nzwy+J`v@P4V9ow}%+qVOI zkiCq(ti7DQyuE_GqP>#6vb~DEs=b>17khPk4SP*{EqiTy9lL0+YY(>9v)8vbus5_f zvWM6k+nd;%+C%Nl>|yric8y)KLp!o#JF&}l#U5^tu(z`~fc?Pl#^yG}bydq6wdPPMD;Onby0ZI7|*?d|OC?XmVaJVk%6J>H&R zPqcTiC)tzj278LVqrH>8v%QPGtG%1OyS<0Kr@fcGx7}z@wVUi_yJ}Cfr`s)dtG$oC zuia+Pu-okpyVKs!?y|e>9=q3`Y0t7}+jH#w?E~z&_JQ_6_QCcc_M!G+_Tlys_L17p z_EGlH_A&Oc_Hp*{_6hch_DS~1_9^zM_G$L%_8In>_F4AX_B{I>`&|1xd%k_XeSv+U zy}-W6zSzFRzSO?VzFa%OzQSH;Uuj=uUu`e4ud%PSud}bWZ?JE)Z?YHLH`}+^x7xSa zx7&BvciMN^ciZ>a_uBW__uCKH584me58IE}kJ^vfkK0e!Pufq}PutJf&)Uz~&)YB9 zFWN8JFWax!uiCHKuiJ0fZ`yC!Z`<$K@7nL#@7o{PAKFXokL-`_PwY?a&+O0bFYGVv zuk5ewZ|raF@9gjGAM79PpX|TcKij|9zuJGd|6%`T|I_}L{X0IBSa5VlIEG_7mSa1P z<2s(>JApIES;kq`SpL4b8#)^~L!6DBO`J`gq0VLwzJly*?$kIXZJ`r7krO+KQ+6uOaA$;euCs-9j`oeS zrL&c@wX==$SM4%qTc_3;sh#GGa_XGa$(+&77^hyF?`-F6?~HZEIpduP&O~PiXOc77 zX>g`EJ32c#J3G5LyE?l$yK7fCdpLVKdpUbMjm}i3$!T_~&NOGb)8e!``#AeLZO#m* z-RW>To&B6Hr&~MO>2Z3Unc5lJna(U{wll}s-#NgU>m2ADF5@oiF6S=quHdfduH>%luHvrhuIB#5UEN*7UDI95UE5v9ExPNvgWdJq_1z8J z4c(30A@0WRChn&0P4BoIBo~;7)XRa3{Hw-3E7xyQ904yR*BCyQ{mKySuxG zyQjOCySLluPIa5yX1D52bEms4ZmYYGyRX~k&T!k^4!6_Y&+T%%-5$5so$1bUXS;LU z{oMoHx$c4PLGHosA?~5>VeaAX5$=)hQSQ<1G48SMaqjW%3GRvRN$$z+DekH6Y3}Ln z8Sa_xS?<~HJog;;T=zV8zI(oVfqS95z`e-5*uBKP)V<8T+`YnG=w9hwGOyEnVHxVO5uxwpG_xOcjDxp%wwxc9pEx%aydxDUDyxevRKxR1Jz zxsSU~xKFxIxlg;#xX-%JxzD>VxG%adxi7n~xUagexv#r#xNo{|xo^AgxbM2}x$nCl zxF5Pp+>hLk-A~+4-Ot?5-7nlP-LKrQ-EZ7)-S6D*-5=Z^-JjgQxj(zVxWBr8cmLu3 z=Kjn-Ok@2%ji=&j_f?5*Oh>aFJe z#arE5!&}o^%Uj!9$18g4dV{_7y!E{ewA;N6y^Xvf-p1Z0-lpDAZ!>S0x4Bp2mAuf4 zyx2>;vRCnjdn3Fpye+-0ysf=$yuW(edbQq2Z+-t29CN(Hdvm<~y#u_t-htjh-of4>-l5)M-r?R6-jUu> z-qGGM-m%_s-tpcE-ih8x-pSr6-l^Vc-s#>M-kIK6-r3$f?;P)3?>uk5cfNOlccHhy zyU4rPyTrTHyUe@XyTV)OUFlurUF|LMuJNw*uJf+nv_j?a`4|)%I4||Vzk9v=Jk9$vePkK*zPkYaJ&w9^!&wDR;FM2O| zFMF?euX?X}uX}HJZ+dTeZ+q`}?|Scf?|UD3A9_o?kGzk)PrOgP&%DpQFT5|kue`6l zZ@h24@4WB5AG{yEpS-_$KYPD;zj}Z7{^9-R{nPuG_q(t81z-1tZ}_Hf`L^%)uJ8H2 zANYg(W&CCR<^1LS75o+bmHd_cRs2=`)%?HstNUyCYx-;XYy0c?MSop?u)m(azQ2LL zp}&zo#NXK8#NX5(>Tl)`^EdZv{E{E~kstesU-m2haDRlqg}5ua3{M66<(f$~}-rvsO-XH6a^T+!W{E7Y!{v?00-{4R2cl3AiclLMjclCGkclY=3 z_w@Jj_x2n8seY5+>{tD1{&c^^Z}s=__x0QS8GgIp;dlD``CWdu-{bfCGyPfqY=4fw zzkh%~*FVrd$UoRW#6Q$O%s<>e!aveK%0Jpa#y{3S&OhEi!9USI$v@dY#Xr?Q%|G2g z!#~qM%Rk$n=bz)B>!0V(_s{n)@GtZi_!s#X`}31iJ>i1-l1(1bYU11$zgL!PKBBXb!5uv|xJB60`>U z1p5YU!Hl3i=mV1z926WJ91>*T=0DGLhxen zQt)!{O7Lp%TJU=CM(}3vR`7Q4PVjEtp4QWXhY_mncI}MDrml{5yHSN!?bNR7%&OIx2X<}8bo|D> zuidCZe^gUz7oK{V)>fVEH}zk8qwqUeV-p^j>G7JDURrfcji}mcRzV&3H1^mj8R97) z$=FI2!)hLQ>C)0(b?K#@vKdtsTB)kBng{;q{)YI|`>(yxODpiEFTD&#fvnHuFbg4E>8o)N_8W6E2sWx<}V6rOJod^Ep z{-N```>%tB0Tl#210q&~s-`Coj0QQSJ#tE?s44ALQ#ysc>SeE{s9yEvfjOlMzf7CG z^6#K21N$_ncVNt(!m007p}$jq3;kIGu6G%5J*WTL+Ew*+|2*(^UAlI?{g+;vZ5{ZL z-0p2}ttkz!VOU}qGK?6;3=@WBh82dx8IE9B%Wx#aQ4H%CrVKL`jv)ULnb!>MX+g-TFdP4k^*H&zw8Oz3WF#B(hYYW>%3ifSph@Ui?BxZ zBCJuP7}h9$VU6M!)+l~qjT*(UM)3`6RKLO+)vvHd^((AV{R(STzrq^Tudqh-D=d+J ziTq3CUn2h!`IpGQME<2pFnItV2HgW9sz)WZq{Nn#*pd=kQesO=Y)QzLgltJj&LKI6 z8B_7M|-bZyXVgn*J zAYua|HXvdHA~qmm10pscW&>h2ASUCOjAJs6Sx?M*5|&F?E@8tHmQPqdVflmumvG<` zwmV_F6Sg~HyA$$D`uMTk3EN#J|1$ZP$-hkgW%4hRf0_Ktzq`(X*FhdH=kODKLzziucLki50f- z3d)dzGNhmkDJa8HoX1g|$5EU&3e1oKGo-)_DKJ9{%#Z>zq`(X*AVUhskOD8HpbIJJ zLJGPt<$6oG-cqi&l|IyWQr)6B1)!+k}0BOiYS>PN~VaCDWYVGD48NkrihX$qGXCFnW9KdcocCE zD3~G&rig+mqF{_GWVNT!9Nh>5Uafi{C;1t>;+6nE zv!Ml7hGb}Nk3$BHFq&sfZEn=Z_3Gn$^_^Q`y5=p=C$@@7Egk0M*6A}EMMGn+&DMyC zEv;e{XkvG3AnWOC$+FDQ7xx;M4nR;H&=Us@P~DdO$gfuFRrmXf=80xr-k6H)=5*O9 zv$@*V(`d6UV}INb@+O`~Mwet|=DvBC+VU=`F&H^YZ|~J-x7r=5U!tp}!@{AH8I2_~ z4@3|8M*gA`{b~ZCIVK)pp57S9YWteC?7uZLV4Z5Vcr%Z9dExw0HKVS^%9~korl_te zVG|K7qq^7t?~;|5>$}JGPs<{rWf9S`h-g_vv@9Z877>9qqGb^ga3cb4MBP8i$R|?* zH_8+MN3;nd+5{18f+%BqXd6VZ4Wxw~Wdy}c3H&Hif+Nb5z>hK|@S;o!yqGpZT%-8M zv=L(32r+Ghn9v*(nqxw9OdBDljS$mDhzZIuK{+NU#{}h=pd1sFV}f!_P>u=8F+n*d zD8~fln4laJlw*Q&Oi+#q$}vGXCMd@Q<(Qxx6O?0uavZAhk3%*7G4VJi9>>Jvn0Oo$ zk7MF-OgxT>$1(9ZCLYJco1O#P>f@>{^D4zzc^OwFQ$PJ z)4+&hwf^Fm>yHLUOoJn)!4cEoh-q-dG&o`!95D@!m~teh!4cEoh-q-dG&o`!9C1Sa zG&o`!7%>fumSk6JKL0v@sRhmy*B*c+~IFb-Y z65>cg97%{H32`JLjwHm9ggBBAM-t*lLL5nmBMEUNA&w-(k%Tys5JwW?NJ895h#LuU zBOz`i#Epcwkq|c$>a7X!BO!hybWkL8P$YCvBy>d^@u6bT&^3H9oPdUZm*I-y>jP_Ittph)PT zNa&zQ=%7gGph)PTNa&zQ=%7gGph)PLNa&a-Q=cePpD0t0C{vFpQ-3H^{+GG#%aq?` z%Iz}ccA0X!Ou1dA+%8jYmnpZ)l-p&>?K0(dnR2^Kxm~8*E>muoDYwg%+hy*zGWT1V z`>o9VR_1;ybHA0j-^$!?W$w2!_gk6!sLXv-<~}NOAC$c2wTjn|~bDfsC zKFeI6Wy<+7<#w6!xJ-vqnR2#F2TqytuT0!86Zgx+{W5XCOx!OM_shinGI765+%FUN zQ{rmMeU@^crEGV~_NH|BrQA;`9eXMDl9YN$O1&hdUXoHDNvV&d)JIY}=u$f9Qab2T zI_Oe5=2Ge{DfO0=`btViTuQwqrQVWKUrDL2q#VbT`btWDC8fTSQeR2wa7*cMOX+Y+ z>2OQwa7*cMOR3kSbhxF|S5i9C(osr3O{u@6oWE2#)=D)>e?gerLkM$y7-4P?Ak6h4 zgt#K~XjFNl-B(q9lKf2F@5PX1~gmul2HM#%oFb&NRsuhuc*?7v#a zh_nA{9V5>ED|-}i)&DwWXO`-e{fJPtw@%r6r8;HjAyoaUQ~C|!YP{+c{+H?$P9s$P zsZ%&zs#ExkP>o}q!e_+QIMykAMqG_!ox*3t$xq=k;%t|~XT;Sw)+v1makfY8*HWFr zZ-nHl@EdXRRrrlK`6~QIoO~62BTl{wzY!;2h2My?zY4z*SMyh=@Viu}@Ef6;zdD8A zh^zUlQ}~Uzn!h?_Pa&@6uTJSjh^zUlQ+iRUPT@L2_DA75;_Q#oGfH(z&p^m_D}A6; zr*H-#*MY(r#5s-%XG(SIhX8~eM};?tldr;M#K~9v5P&$xQT-5rILA@p5#nr*vZD~^ zI4WF1oa3l)sZ^(M2_eT(;S%B;M}

a~u^eAx^%^-a?#w6)qu8zDkZDuK1?PA5%(| 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 literal 0 HcmV?d00001 diff --git a/src/libANGLE/overlay_widgets.json b/src/libANGLE/overlay_widgets.json new file mode 100644 index 00000000000..0f65f75351a --- /dev/null +++ b/src/libANGLE/overlay_widgets.json @@ -0,0 +1,85 @@ +{ + "description": [ + "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.", + "", + "overlay_widgets.json: Layout of Overlay widgets.", + "", + "Data for every overlay widget 'Widget' is a map with the following keys:", + "", + " - type: one of WidgetType types (with constructor params), such as 'PerSecond' or", + " 'RunningGraph(64)'", + " - color: in [R,G,B,A] format where every value is in [0,255]", + " - coords: in [X,Y] which is the distance from the edges of the window, with negative", + " values representing distance from the right/bottom edge. If a value is given", + " in the form of 'Widget2..', the calculated value for in", + " Widget2 is used. is one of:", + " - 'left', 'right': valid for x", + " - 'top', 'bottom': valid for y", + " is one of:", + " - 'align': the requested value is used", + " - 'adjacent': the value is calculated such that two widgets become adjacent", + " - font: for Text widgets, one of 'large', 'medium' and 'small'", + " - length: for Text widgets, maximum number of characters for this widget", + " - bar_width: for Graph widgets, size of each graph bar.", + " - height: for Graph widgets, the height of the graph.", + " - text: for Graph widgets, data for the attached Text widget. This is a map with the same", + " Text keys as above except type, which is implicitly Text." + ], + "widgets": [ + { + "name": "FPS", + "type": "PerSecond", + "color": [127, 191, 255, 255], + "coords": [10, 10], + "font": "medium", + "length": 12 + }, + { + "name": "VulkanLastValidationMessage", + "type": "Text", + "color": [255, 0, 0, 255], + "coords": [10, -10], + "font": "small", + "length": 150 + }, + { + "name": "VulkanValidationMessageCount", + "type": "Count", + "color": [255, 0, 0, 255], + "coords": [10, "VulkanLastValidationMessage.top.adjacent"], + "font": "small", + "length": 25 + }, + { + "name": "VulkanCommandGraphSize", + "type": "RunningGraph(60)", + "color": [75, 200, 0, 200], + "coords": [10, 100], + "bar_width": 5, + "height": 100, + "description": { + "color": [75, 200, 0, 255], + "coords": ["VulkanCommandGraphSize.left.align", "VulkanCommandGraphSize.top.adjacent"], + "font": "small", + "length": 40 + } + }, + { + "name": "VulkanSecondaryCommandBufferPoolWaste", + "type": "RunningHistogram(50)", + "color": [255, 200, 75, 200], + "coords": [-50, 100], + "bar_width": 6, + "height": 100, + "description": { + "color": [255, 200, 75, 255], + "coords": ["VulkanSecondaryCommandBufferPoolWaste.left.align", + "VulkanSecondaryCommandBufferPoolWaste.top.adjacent"], + "font": "small", + "length": 40 + } + } + ] +} diff --git a/src/libANGLE/renderer/GLImplFactory.h b/src/libANGLE/renderer/GLImplFactory.h index 2f989cc35f6..199019a1295 100644 --- a/src/libANGLE/renderer/GLImplFactory.h +++ b/src/libANGLE/renderer/GLImplFactory.h @@ -14,6 +14,7 @@ #include "angle_gl.h" #include "libANGLE/Framebuffer.h" +#include "libANGLE/Overlay.h" #include "libANGLE/Program.h" #include "libANGLE/ProgramPipeline.h" #include "libANGLE/Renderbuffer.h" @@ -36,6 +37,7 @@ class FenceNVImpl; class SyncImpl; class FramebufferImpl; class MemoryObjectImpl; +class OverlayImpl; class PathImpl; class ProgramImpl; class ProgramPipelineImpl; @@ -96,6 +98,9 @@ class GLImplFactory : angle::NonCopyable // Semaphore creation virtual SemaphoreImpl *createSemaphore() = 0; + + // Overlay creation + virtual OverlayImpl *createOverlay(const gl::OverlayState &state) = 0; }; } // namespace rx diff --git a/src/libANGLE/renderer/OverlayImpl.h b/src/libANGLE/renderer/OverlayImpl.h new file mode 100644 index 00000000000..eecd08b2477 --- /dev/null +++ b/src/libANGLE/renderer/OverlayImpl.h @@ -0,0 +1,49 @@ +// +// 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. +// + +// OverlayImpl.h: Defines the abstract rx::OverlayImpl class. + +#ifndef LIBANGLE_RENDERER_OVERLAYIMPL_H_ +#define LIBANGLE_RENDERER_OVERLAYIMPL_H_ + +#include "common/PackedEnums.h" +#include "common/angleutils.h" +#include "common/mathutil.h" +#include "libANGLE/Error.h" +#include "libANGLE/Observer.h" + +#include + +namespace gl +{ +class Context; +class OverlayState; +} // namespace gl + +namespace rx +{ +class OverlayImpl : angle::NonCopyable +{ + public: + OverlayImpl(const gl::OverlayState &state) : mState(state) {} + virtual ~OverlayImpl() {} + + virtual void onDestroy(const gl::Context *context) {} + + virtual angle::Result init(const gl::Context *context); + + protected: + const gl::OverlayState &mState; +}; + +inline angle::Result OverlayImpl::init(const gl::Context *context) +{ + return angle::Result::Continue; +} + +} // namespace rx + +#endif // LIBANGLE_RENDERER_OVERLAYIMPL_H_ diff --git a/src/libANGLE/renderer/d3d/d3d11/Context11.cpp b/src/libANGLE/renderer/d3d/d3d11/Context11.cpp index d4a52014b6f..7a177eb6c74 100644 --- a/src/libANGLE/renderer/d3d/d3d11/Context11.cpp +++ b/src/libANGLE/renderer/d3d/d3d11/Context11.cpp @@ -12,6 +12,7 @@ #include "common/string_utils.h" #include "libANGLE/Context.h" #include "libANGLE/MemoryProgramCache.h" +#include "libANGLE/renderer/OverlayImpl.h" #include "libANGLE/renderer/d3d/CompilerD3D.h" #include "libANGLE/renderer/d3d/RenderbufferD3D.h" #include "libANGLE/renderer/d3d/SamplerD3D.h" @@ -243,6 +244,12 @@ SemaphoreImpl *Context11::createSemaphore() return nullptr; } +OverlayImpl *Context11::createOverlay(const gl::OverlayState &state) +{ + // Not implemented. + return new OverlayImpl(state); +} + angle::Result Context11::flush(const gl::Context *context) { return mRenderer->flush(this); diff --git a/src/libANGLE/renderer/d3d/d3d11/Context11.h b/src/libANGLE/renderer/d3d/d3d11/Context11.h index f0961c5d382..4f89a2a6f30 100644 --- a/src/libANGLE/renderer/d3d/d3d11/Context11.h +++ b/src/libANGLE/renderer/d3d/d3d11/Context11.h @@ -71,6 +71,9 @@ class Context11 : public ContextD3D, public MultisampleTextureInitializer // Semaphore creation. SemaphoreImpl *createSemaphore() override; + // Overlay creation. + OverlayImpl *createOverlay(const gl::OverlayState &state) override; + // Flush and finish. angle::Result flush(const gl::Context *context) override; angle::Result finish(const gl::Context *context) override; diff --git a/src/libANGLE/renderer/d3d/d3d9/Context9.cpp b/src/libANGLE/renderer/d3d/d3d9/Context9.cpp index bd9ccfcb446..5908fa7ceec 100644 --- a/src/libANGLE/renderer/d3d/d3d9/Context9.cpp +++ b/src/libANGLE/renderer/d3d/d3d9/Context9.cpp @@ -10,6 +10,7 @@ #include "libANGLE/renderer/d3d/d3d9/Context9.h" #include "common/string_utils.h" +#include "libANGLE/renderer/OverlayImpl.h" #include "libANGLE/renderer/d3d/CompilerD3D.h" #include "libANGLE/renderer/d3d/ProgramD3D.h" #include "libANGLE/renderer/d3d/RenderbufferD3D.h" @@ -145,6 +146,12 @@ SemaphoreImpl *Context9::createSemaphore() return nullptr; } +OverlayImpl *Context9::createOverlay(const gl::OverlayState &state) +{ + // Not implemented. + return new OverlayImpl(state); +} + angle::Result Context9::flush(const gl::Context *context) { return mRenderer->flush(context); diff --git a/src/libANGLE/renderer/d3d/d3d9/Context9.h b/src/libANGLE/renderer/d3d/d3d9/Context9.h index 144ae0a0960..f0963d6f456 100644 --- a/src/libANGLE/renderer/d3d/d3d9/Context9.h +++ b/src/libANGLE/renderer/d3d/d3d9/Context9.h @@ -70,6 +70,9 @@ class Context9 : public ContextD3D // Semaphore creation. SemaphoreImpl *createSemaphore() override; + // Overlay creation. + OverlayImpl *createOverlay(const gl::OverlayState &state) override; + // Flush and finish. angle::Result flush(const gl::Context *context) override; angle::Result finish(const gl::Context *context) override; diff --git a/src/libANGLE/renderer/gl/ContextGL.cpp b/src/libANGLE/renderer/gl/ContextGL.cpp index 9958efc3c39..f93fe030a58 100644 --- a/src/libANGLE/renderer/gl/ContextGL.cpp +++ b/src/libANGLE/renderer/gl/ContextGL.cpp @@ -10,6 +10,7 @@ #include "libANGLE/renderer/gl/ContextGL.h" #include "libANGLE/Context.h" +#include "libANGLE/renderer/OverlayImpl.h" #include "libANGLE/renderer/gl/BufferGL.h" #include "libANGLE/renderer/gl/CompilerGL.h" #include "libANGLE/renderer/gl/FenceNVGL.h" @@ -190,6 +191,12 @@ SemaphoreImpl *ContextGL::createSemaphore() return new SemaphoreGL(semaphore); } +OverlayImpl *ContextGL::createOverlay(const gl::OverlayState &state) +{ + // Not implemented. + return new OverlayImpl(state); +} + angle::Result ContextGL::flush(const gl::Context *context) { return mRenderer->flush(); diff --git a/src/libANGLE/renderer/gl/ContextGL.h b/src/libANGLE/renderer/gl/ContextGL.h index 650594b69ef..5080d62d7c4 100644 --- a/src/libANGLE/renderer/gl/ContextGL.h +++ b/src/libANGLE/renderer/gl/ContextGL.h @@ -85,6 +85,9 @@ class ContextGL : public ContextImpl // Semaphore creation. SemaphoreImpl *createSemaphore() override; + // Overlay creation. + OverlayImpl *createOverlay(const gl::OverlayState &state) override; + // Flush and finish. angle::Result flush(const gl::Context *context) override; angle::Result finish(const gl::Context *context) override; diff --git a/src/libANGLE/renderer/null/ContextNULL.cpp b/src/libANGLE/renderer/null/ContextNULL.cpp index 6012029f70b..70669975a16 100644 --- a/src/libANGLE/renderer/null/ContextNULL.cpp +++ b/src/libANGLE/renderer/null/ContextNULL.cpp @@ -12,6 +12,7 @@ #include "common/debug.h" #include "libANGLE/Context.h" +#include "libANGLE/renderer/OverlayImpl.h" #include "libANGLE/renderer/null/BufferNULL.h" #include "libANGLE/renderer/null/CompilerNULL.h" #include "libANGLE/renderer/null/DisplayNULL.h" @@ -427,6 +428,11 @@ SemaphoreImpl *ContextNULL::createSemaphore() return nullptr; } +OverlayImpl *ContextNULL::createOverlay(const gl::OverlayState &state) +{ + return new OverlayImpl(state); +} + angle::Result ContextNULL::dispatchCompute(const gl::Context *context, GLuint numGroupsX, GLuint numGroupsY, diff --git a/src/libANGLE/renderer/null/ContextNULL.h b/src/libANGLE/renderer/null/ContextNULL.h index c1e74415f0e..f929da80194 100644 --- a/src/libANGLE/renderer/null/ContextNULL.h +++ b/src/libANGLE/renderer/null/ContextNULL.h @@ -218,6 +218,9 @@ class ContextNULL : public ContextImpl // Semaphore creation. SemaphoreImpl *createSemaphore() override; + // Overlay creation. + OverlayImpl *createOverlay(const gl::OverlayState &state) override; + angle::Result dispatchCompute(const gl::Context *context, GLuint numGroupsX, GLuint numGroupsY, diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.cpp b/src/libANGLE/renderer/vulkan/CommandGraph.cpp index 77067d2589c..fa6c5fc3fbd 100644 --- a/src/libANGLE/renderer/vulkan/CommandGraph.cpp +++ b/src/libANGLE/renderer/vulkan/CommandGraph.cpp @@ -11,6 +11,7 @@ #include +#include "libANGLE/Overlay.h" #include "libANGLE/renderer/vulkan/ContextVk.h" #include "libANGLE/renderer/vulkan/RenderTargetVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h" @@ -217,6 +218,24 @@ std::string DumpCommands(const priv::CommandBuffer &commandBuffer, const char *s return "--blob--"; } +float CalculateSecondaryCommandBufferPoolWaste(const std::vector nodes) +{ + size_t used = 0; + size_t allocated = 0; + + for (const CommandGraphNode *node : nodes) + { + size_t nodeUsed; + size_t nodeAllocated; + node->getMemoryUsageStatsForDiagnostics(&nodeUsed, &nodeAllocated); + used += nodeUsed; + allocated += nodeAllocated; + } + + allocated = std::max(allocated, 1); + return static_cast(used) / static_cast(allocated); +} + } // anonymous namespace // CommandGraphResource implementation. @@ -579,7 +598,7 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context, static_cast(mRenderPassRenderArea.height); beginInfo.clearValueCount = static_cast(mRenderPassDesc.attachmentCount()); - beginInfo.pClearValues = mRenderPassClearValues.data(); + beginInfo.pClearValues = mRenderPassClearValues.data(); primaryCommandBuffer->beginRenderPass(beginInfo, kRenderPassContents); ExecuteCommands(primaryCommandBuffer, &mInsideRenderPassCommands); @@ -790,6 +809,19 @@ std::string CommandGraphNode::dumpCommandsForDiagnostics(const char *separator) return result; } +void CommandGraphNode::getMemoryUsageStatsForDiagnostics(size_t *usedMemoryOut, + size_t *allocatedMemoryOut) const +{ + size_t commandBufferUsed; + size_t commandBufferAllocated; + + mOutsideRenderPassCommands.getMemoryUsageStats(usedMemoryOut, allocatedMemoryOut); + mInsideRenderPassCommands.getMemoryUsageStats(&commandBufferUsed, &commandBufferAllocated); + + *usedMemoryOut += commandBufferUsed; + *allocatedMemoryOut += commandBufferAllocated; +} + // CommandGraph implementation. CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *poolAllocator) : mEnableGraphDiagnostics(enableGraphDiagnostics), @@ -852,6 +884,8 @@ angle::Result CommandGraph::submitCommands(ContextVk *context, // function if there's nothing to do. ASSERT(!mNodes.empty()); + updateOverlay(context); + size_t previousBarrierIndex = 0; CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex); @@ -1160,6 +1194,17 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const out << "}" << std::endl; } +void CommandGraph::updateOverlay(ContextVk *contextVk) const +{ + const gl::OverlayType *overlay = contextVk->getOverlay(); + + overlay->getRunningGraphWidget(gl::WidgetId::VulkanCommandGraphSize)->add(mNodes.size()); + + overlay->getRunningHistogramWidget(gl::WidgetId::VulkanSecondaryCommandBufferPoolWaste) + ->set(CalculateSecondaryCommandBufferPoolWaste(mNodes)); + overlay->getRunningHistogramWidget(gl::WidgetId::VulkanSecondaryCommandBufferPoolWaste)->next(); +} + CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut) { *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex; diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.h b/src/libANGLE/renderer/vulkan/CommandGraph.h index 03e610e4e41..89cd970ba60 100644 --- a/src/libANGLE/renderer/vulkan/CommandGraph.h +++ b/src/libANGLE/renderer/vulkan/CommandGraph.h @@ -182,6 +182,7 @@ class CommandGraphNode final : angle::NonCopyable uintptr_t getResourceIDForDiagnostics() const { return mResourceID; } bool hasDiagnosticID() const; std::string dumpCommandsForDiagnostics(const char *separator) const; + void getMemoryUsageStatsForDiagnostics(size_t *usedMemoryOut, size_t *allocatedMemoryOut) const; const gl::Rectangle &getRenderPassRenderArea() const { return mRenderPassRenderArea; } @@ -514,6 +515,7 @@ class CommandGraph final : angle::NonCopyable void addDependenciesToNextBarrier(size_t begin, size_t end, CommandGraphNode *nextBarrier); void dumpGraphDotFile(std::ostream &out) const; + void updateOverlay(ContextVk *contextVk) const; std::vector mNodes; bool mEnableGraphDiagnostics; diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp index 2684e43f4fd..89e5d203e0e 100644 --- a/src/libANGLE/renderer/vulkan/ContextVk.cpp +++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp @@ -24,6 +24,7 @@ #include "libANGLE/renderer/vulkan/FenceNVVk.h" #include "libANGLE/renderer/vulkan/FramebufferVk.h" #include "libANGLE/renderer/vulkan/MemoryObjectVk.h" +#include "libANGLE/renderer/vulkan/OverlayVk.h" #include "libANGLE/renderer/vulkan/ProgramPipelineVk.h" #include "libANGLE/renderer/vulkan/ProgramVk.h" #include "libANGLE/renderer/vulkan/QueryVk.h" @@ -2130,6 +2131,11 @@ SemaphoreImpl *ContextVk::createSemaphore() return new SemaphoreVk(); } +OverlayImpl *ContextVk::createOverlay(const gl::OverlayState &state) +{ + return new OverlayVk(state); +} + void ContextVk::invalidateCurrentTextures() { ASSERT(mProgram); diff --git a/src/libANGLE/renderer/vulkan/ContextVk.h b/src/libANGLE/renderer/vulkan/ContextVk.h index 521a23903d9..63960df74a9 100644 --- a/src/libANGLE/renderer/vulkan/ContextVk.h +++ b/src/libANGLE/renderer/vulkan/ContextVk.h @@ -14,6 +14,7 @@ #include "common/PackedEnums.h" #include "libANGLE/renderer/ContextImpl.h" +#include "libANGLE/renderer/vulkan/OverlayVk.h" #include "libANGLE/renderer/vulkan/PersistentCommandPool.h" #include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/vk_helpers.h" @@ -175,6 +176,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO // Semaphore creation. SemaphoreImpl *createSemaphore() override; + // Overlay creation. + OverlayImpl *createOverlay(const gl::OverlayState &state) override; + angle::Result dispatchCompute(const gl::Context *context, GLuint numGroupsX, GLuint numGroupsY, @@ -331,6 +335,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO bool useOldRewriteStructSamplers() const { return mUseOldRewriteStructSamplers; } + const gl::OverlayType *getOverlay() const { return mState.getOverlay(); } + private: // Dirty bits. enum DirtyBitType : size_t diff --git a/src/libANGLE/renderer/vulkan/OverlayVk.cpp b/src/libANGLE/renderer/vulkan/OverlayVk.cpp new file mode 100644 index 00000000000..ec5ce6794e7 --- /dev/null +++ b/src/libANGLE/renderer/vulkan/OverlayVk.cpp @@ -0,0 +1,281 @@ +// +// 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. +// +// OverlayVk.cpp: +// Implements the OverlayVk class. +// + +#include "libANGLE/renderer/vulkan/OverlayVk.h" + +#include "common/system_utils.h" +#include "libANGLE/Context.h" +#include "libANGLE/Overlay_font_autogen.h" +#include "libANGLE/renderer/vulkan/ContextVk.h" + +#include + +namespace rx +{ +OverlayVk::OverlayVk(const gl::OverlayState &state) + : OverlayImpl(state), + mSupportsSubgroupBallot(false), + mSupportsSubgroupArithmetic(false), + mRefreshCulledWidgets(false) +{} +OverlayVk::~OverlayVk() = default; + +angle::Result OverlayVk::init(const gl::Context *context) +{ + ContextVk *contextVk = vk::GetImpl(context); + RendererVk *rendererVk = contextVk->getRenderer(); + + const VkPhysicalDeviceSubgroupProperties &subgroupProperties = + rendererVk->getPhysicalDeviceSubgroupProperties(); + uint32_t subgroupSize = subgroupProperties.subgroupSize; + + // Currently, only subgroup sizes 32 and 64 are supported. + if (subgroupSize != 32 && subgroupSize != 64) + { + return angle::Result::Continue; + } + + mSubgroupSize[0] = 8; + mSubgroupSize[1] = subgroupSize / 8; + + constexpr VkSubgroupFeatureFlags kSubgroupBallotOperations = + VK_SUBGROUP_FEATURE_BASIC_BIT | VK_SUBGROUP_FEATURE_BALLOT_BIT; + constexpr VkSubgroupFeatureFlags kSubgroupArithmeticOperations = + VK_SUBGROUP_FEATURE_BASIC_BIT | VK_SUBGROUP_FEATURE_ARITHMETIC_BIT; + + // If not all operations used in the shaders are supported, disable the overlay. + if ((subgroupProperties.supportedOperations & kSubgroupBallotOperations) == + kSubgroupBallotOperations) + { + mSupportsSubgroupBallot = true; + } + else if ((subgroupProperties.supportedOperations & kSubgroupArithmeticOperations) == + kSubgroupArithmeticOperations) + { + mSupportsSubgroupArithmetic = true; + } + + ANGLE_TRY(createFont(contextVk)); + + mRefreshCulledWidgets = true; + + return contextVk->flushImpl(nullptr); +} + +void OverlayVk::onDestroy(const gl::Context *context) +{ + VkDevice device = vk::GetImpl(context)->getDevice(); + + mCulledWidgets.destroy(device); + mCulledWidgetsView.destroy(device); + + mFontImage.destroy(device); + mFontImageView.destroy(device); +} + +angle::Result OverlayVk::createFont(ContextVk *contextVk) +{ + RendererVk *rendererVk = contextVk->getRenderer(); + + // Create a buffer to stage font data upload. + VkBufferCreateInfo bufferCreateInfo = {}; + bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferCreateInfo.size = + gl::overlay::kFontCount * gl::overlay::kFontImageWidth * gl::overlay::kFontImageHeight; + bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vk::ContextScoped fontDataBuffer(contextVk); + + ANGLE_TRY(fontDataBuffer.get().init(contextVk, bufferCreateInfo, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + + uint8_t *fontData; + ANGLE_TRY(fontDataBuffer.get().map(contextVk, &fontData)); + + mState.initFontData(fontData); + + ANGLE_TRY(fontDataBuffer.get().flush(contextVk, 0, fontDataBuffer.get().getSize())); + fontDataBuffer.get().unmap(contextVk->getDevice()); + + fontDataBuffer.get().onExternalWrite(VK_ACCESS_HOST_WRITE_BIT); + + // Create the font image. + ANGLE_TRY(mFontImage.init( + contextVk, gl::TextureType::_2D, + VkExtent3D{gl::overlay::kFontImageWidth, gl::overlay::kFontImageHeight, 1}, + rendererVk->getFormat(angle::FormatID::R8_UNORM), 1, + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 1, gl::overlay::kFontCount)); + ANGLE_TRY(mFontImage.initMemory(contextVk, rendererVk->getMemoryProperties(), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); + ANGLE_TRY(mFontImage.initImageView(contextVk, gl::TextureType::_2DArray, + VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(), + &mFontImageView, 0, 1)); + + // Copy font data from staging buffer. + vk::CommandBuffer *fontDataUpload; + ANGLE_TRY(mFontImage.recordCommands(contextVk, &fontDataUpload)); + + fontDataBuffer.get().onRead(&mFontImage, VK_ACCESS_TRANSFER_READ_BIT); + + mFontImage.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst, + fontDataUpload); + + VkBufferImageCopy copy = {}; + copy.bufferRowLength = gl::overlay::kFontImageWidth; + copy.bufferImageHeight = gl::overlay::kFontImageHeight; + copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copy.imageSubresource.layerCount = gl::overlay::kFontCount; + copy.imageExtent.width = gl::overlay::kFontImageWidth; + copy.imageExtent.height = gl::overlay::kFontImageHeight; + copy.imageExtent.depth = 1; + + fontDataUpload->copyBufferToImage(fontDataBuffer.get().getBuffer().getHandle(), + mFontImage.getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ©); + + mFontImage.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ComputeShaderReadOnly, + fontDataUpload); + + return angle::Result::Continue; +} + +angle::Result OverlayVk::cullWidgets(ContextVk *contextVk) +{ + RendererVk *rendererVk = contextVk->getRenderer(); + + // Release old culledWidgets image + Serial currentSerial = contextVk->getCurrentQueueSerial(); + contextVk->releaseObject(currentSerial, &mCulledWidgets); + contextVk->releaseObject(currentSerial, &mCulledWidgetsView); + + // Create a buffer to contain coordinates of enabled text and graph widgets. This buffer will + // be used to perform tiled culling and can be discarded immediately after. + VkBufferCreateInfo bufferCreateInfo = {}; + bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferCreateInfo.size = mState.getWidgetCoordinatesBufferSize(); + bufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vk::ContextScoped enabledWidgetsBuffer(contextVk); + + ANGLE_TRY(enabledWidgetsBuffer.get().init(contextVk, bufferCreateInfo, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + + // Fill the buffer with coordinate information from enabled widgets. + uint8_t *enabledWidgets; + ANGLE_TRY(enabledWidgetsBuffer.get().map(contextVk, &enabledWidgets)); + + gl::Extents presentImageExtents(mPresentImageExtent.width, mPresentImageExtent.height, 1); + mState.fillEnabledWidgetCoordinates(presentImageExtents, enabledWidgets); + + ANGLE_TRY(enabledWidgetsBuffer.get().flush(contextVk, 0, enabledWidgetsBuffer.get().getSize())); + enabledWidgetsBuffer.get().unmap(contextVk->getDevice()); + + enabledWidgetsBuffer.get().onExternalWrite(VK_ACCESS_HOST_WRITE_BIT); + + // Allocate mCulledWidget and its view. + VkExtent3D culledWidgetsExtent = { + UnsignedCeilDivide(mPresentImageExtent.width, mSubgroupSize[0]), + UnsignedCeilDivide(mPresentImageExtent.height, mSubgroupSize[1]), 1}; + + ANGLE_TRY(mCulledWidgets.init(contextVk, gl::TextureType::_2D, culledWidgetsExtent, + rendererVk->getFormat(angle::FormatID::R32G32_UINT), 1, + VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 1, 1)); + ANGLE_TRY(mCulledWidgets.initMemory(contextVk, rendererVk->getMemoryProperties(), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); + ANGLE_TRY(mCulledWidgets.initImageView(contextVk, gl::TextureType::_2D, + VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(), + &mCulledWidgetsView, 0, 1)); + + UtilsVk::OverlayCullParameters params; + params.subgroupSize[0] = mSubgroupSize[0]; + params.subgroupSize[1] = mSubgroupSize[1]; + params.supportsSubgroupBallot = mSupportsSubgroupBallot; + params.supportsSubgroupArithmetic = mSupportsSubgroupArithmetic; + + return contextVk->getUtils().cullOverlayWidgets(contextVk, &enabledWidgetsBuffer.get(), + &mCulledWidgets, &mCulledWidgetsView, params); +} + +angle::Result OverlayVk::onPresent(ContextVk *contextVk, + vk::ImageHelper *imageToPresent, + const vk::ImageView *imageToPresentView) +{ + if (mState.getEnabledWidgetCount() == 0) + { + return angle::Result::Continue; + } + + RendererVk *rendererVk = contextVk->getRenderer(); + + // If the swapchain image doesn't support storage image, we can't output to it. + VkFormatFeatureFlags featureBits = rendererVk->getImageFormatFeatureBits( + imageToPresent->getFormat().vkImageFormat, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT); + if ((featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0) + { + return angle::Result::Continue; + } + + const VkExtent3D &imageExtent = imageToPresent->getExtents(); + + mRefreshCulledWidgets = mRefreshCulledWidgets || + mPresentImageExtent.width != imageExtent.width || + mPresentImageExtent.height != imageExtent.height; + + if (mRefreshCulledWidgets) + { + mPresentImageExtent.width = imageExtent.width; + mPresentImageExtent.height = imageExtent.height; + + ANGLE_TRY(cullWidgets(contextVk)); + + mRefreshCulledWidgets = false; + } + + vk::ContextScoped textDataBuffer(contextVk); + vk::ContextScoped graphDataBuffer(contextVk); + + VkBufferCreateInfo textBufferCreateInfo = {}; + textBufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + textBufferCreateInfo.size = mState.getTextWidgetsBufferSize(); + textBufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + textBufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkBufferCreateInfo graphBufferCreateInfo = textBufferCreateInfo; + graphBufferCreateInfo.size = mState.getGraphWidgetsBufferSize(); + + ANGLE_TRY(textDataBuffer.get().init(contextVk, textBufferCreateInfo, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + ANGLE_TRY(graphDataBuffer.get().init(contextVk, graphBufferCreateInfo, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + + uint8_t *textData; + uint8_t *graphData; + ANGLE_TRY(textDataBuffer.get().map(contextVk, &textData)); + ANGLE_TRY(graphDataBuffer.get().map(contextVk, &graphData)); + + gl::Extents presentImageExtents(mPresentImageExtent.width, mPresentImageExtent.height, 1); + mState.fillWidgetData(presentImageExtents, textData, graphData); + + ANGLE_TRY(textDataBuffer.get().flush(contextVk, 0, textDataBuffer.get().getSize())); + ANGLE_TRY(graphDataBuffer.get().flush(contextVk, 0, graphDataBuffer.get().getSize())); + textDataBuffer.get().unmap(contextVk->getDevice()); + graphDataBuffer.get().unmap(contextVk->getDevice()); + + UtilsVk::OverlayDrawParameters params; + params.subgroupSize[0] = mSubgroupSize[0]; + params.subgroupSize[1] = mSubgroupSize[1]; + + return contextVk->getUtils().drawOverlay( + contextVk, &textDataBuffer.get(), &graphDataBuffer.get(), &mFontImage, &mFontImageView, + &mCulledWidgets, &mCulledWidgetsView, imageToPresent, imageToPresentView, params); +} + +} // namespace rx diff --git a/src/libANGLE/renderer/vulkan/OverlayVk.h b/src/libANGLE/renderer/vulkan/OverlayVk.h new file mode 100644 index 00000000000..68188dc39ea --- /dev/null +++ b/src/libANGLE/renderer/vulkan/OverlayVk.h @@ -0,0 +1,57 @@ +// +// 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. +// +// OverlayVk.h: +// Defines the OverlayVk class that does the actual rendering of the overlay. +// + +#ifndef LIBANGLE_RENDERER_VULKAN_OVERLAYVK_H_ +#define LIBANGLE_RENDERER_VULKAN_OVERLAYVK_H_ + +#include "common/angleutils.h" +#include "libANGLE/renderer/OverlayImpl.h" +#include "libANGLE/renderer/vulkan/vk_helpers.h" + +namespace rx +{ +class ContextVk; + +class OverlayVk : public OverlayImpl +{ + public: + OverlayVk(const gl::OverlayState &state); + ~OverlayVk() override; + + angle::Result init(const gl::Context *context) override; + void onDestroy(const gl::Context *context) override; + + angle::Result onPresent(ContextVk *contextVk, + vk::ImageHelper *imageToPresent, + const vk::ImageView *imageToPresentView); + + private: + angle::Result createFont(ContextVk *contextVk); + angle::Result cullWidgets(ContextVk *contextVk); + + bool mSupportsSubgroupBallot; + bool mSupportsSubgroupArithmetic; + bool mRefreshCulledWidgets; + + // Cached size of subgroup as accepted by UtilsVk, deduced from hardware subgroup size. + uint32_t mSubgroupSize[2]; + + // Cached size of last presented image. If the size changes, culling is repeated. + VkExtent2D mPresentImageExtent; + + vk::ImageHelper mFontImage; + vk::ImageView mFontImageView; + + vk::ImageHelper mCulledWidgets; + vk::ImageView mCulledWidgetsView; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_VULKAN_OVERLAYVK_H_ diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp index e78957586cc..79174e2c9cc 100644 --- a/src/libANGLE/renderer/vulkan/RendererVk.cpp +++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp @@ -293,6 +293,9 @@ DebugUtilsMessenger(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, bool isError = (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0; std::string msg = log.str(); + RendererVk *rendererVk = static_cast(userData); + rendererVk->onNewValidationMessage(msg); + if (isError) { ERR() << msg; @@ -1652,4 +1655,17 @@ angle::Result RendererVk::cleanupGarbage(vk::Context *context, bool block) return angle::Result::Continue; } +void RendererVk::onNewValidationMessage(const std::string &message) +{ + mLastValidationMessage = message; + ++mValidationMessageCount; +} + +std::string RendererVk::getAndClearLastValidationMessage(uint32_t *countSinceLastClear) +{ + *countSinceLastClear = mValidationMessageCount; + mValidationMessageCount = 0; + + return std::move(mLastValidationMessage); +} } // namespace rx diff --git a/src/libANGLE/renderer/vulkan/RendererVk.h b/src/libANGLE/renderer/vulkan/RendererVk.h index 7e1b7c7eff1..36f7ec29985 100644 --- a/src/libANGLE/renderer/vulkan/RendererVk.h +++ b/src/libANGLE/renderer/vulkan/RendererVk.h @@ -161,6 +161,9 @@ class RendererVk : angle::NonCopyable angle::Result getPipelineCache(vk::PipelineCache **pipelineCache); void onNewGraphicsPipeline() { mPipelineCacheDirty = true; } + void onNewValidationMessage(const std::string &message); + std::string getAndClearLastValidationMessage(uint32_t *countSinceLastClear); + private: angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex); void ensureCapsInitialized() const; @@ -239,6 +242,10 @@ class RendererVk : angle::NonCopyable // DescriptorSetLayouts are also managed in a cache. std::mutex mDescriptorSetLayoutCacheMutex; DescriptorSetLayoutCache mDescriptorSetLayoutCache; + + // Latest validation data for debug overlay. + std::string mLastValidationMessage; + uint32_t mValidationMessageCount; }; } // namespace rx diff --git a/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp b/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp index 2b69e0bab75..9e19ec079c0 100644 --- a/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp +++ b/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp @@ -344,6 +344,27 @@ void SecondaryCommandBuffer::executeCommands(VkCommandBuffer cmdBuffer) } } +void SecondaryCommandBuffer::getMemoryUsageStats(size_t *usedMemoryOut, + size_t *allocatedMemoryOut) const +{ + *allocatedMemoryOut = kBlockSize * mCommands.size(); + + *usedMemoryOut = 0; + for (const CommandHeader *command : mCommands) + { + const CommandHeader *commandEnd = command; + while (commandEnd->id != CommandID::Invalid) + { + commandEnd = NextCommand(commandEnd); + } + + *usedMemoryOut += reinterpret_cast(commandEnd) - + reinterpret_cast(command) + sizeof(CommandHeader::id); + } + + ASSERT(*usedMemoryOut <= *allocatedMemoryOut); +} + std::string SecondaryCommandBuffer::dumpCommands(const char *separator) const { std::string result; diff --git a/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h b/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h index 5cc2010444c..cc56e76c0d3 100644 --- a/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h +++ b/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h @@ -542,6 +542,9 @@ class SecondaryCommandBuffer final : angle::NonCopyable // Parse the cmds in this cmd buffer into given primary cmd buffer for execution void executeCommands(VkCommandBuffer cmdBuffer); + // Calculate memory usage of this command buffer for diagnostics. + void getMemoryUsageStats(size_t *usedMemoryOut, size_t *allocatedMemoryOut) const; + // Traverse the list of commands and build a summary for diagnostics. std::string dumpCommands(const char *separator) const; diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp index c380f194de1..17a866505c0 100644 --- a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp +++ b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp @@ -12,10 +12,12 @@ #include "common/debug.h" #include "libANGLE/Context.h" #include "libANGLE/Display.h" +#include "libANGLE/Overlay.h" #include "libANGLE/Surface.h" #include "libANGLE/renderer/vulkan/ContextVk.h" #include "libANGLE/renderer/vulkan/DisplayVk.h" #include "libANGLE/renderer/vulkan/FramebufferVk.h" +#include "libANGLE/renderer/vulkan/OverlayVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h" #include "libANGLE/trace.h" @@ -719,7 +721,15 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context, VkFormat nativeFormat = format.vkImageFormat; // We need transfer src for reading back from the backbuffer. - constexpr VkImageUsageFlags kImageUsageFlags = kSurfaceVKColorImageUsageFlags; + VkImageUsageFlags imageUsageFlags = kSurfaceVKColorImageUsageFlags; + + // We need storage image for compute writes (debug overlay output). + VkFormatFeatureFlags featureBits = + renderer->getImageFormatFeatureBits(nativeFormat, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT); + if ((featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0) + { + imageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT; + } VkSwapchainCreateInfoKHR swapchainInfo = {}; swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; @@ -732,7 +742,7 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context, swapchainInfo.imageExtent.width = std::max(extents.width, 1); swapchainInfo.imageExtent.height = std::max(extents.height, 1); swapchainInfo.imageArrayLayers = 1; - swapchainInfo.imageUsage = kImageUsageFlags; + swapchainInfo.imageUsage = imageUsageFlags; swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchainInfo.queueFamilyIndexCount = 0; swapchainInfo.pQueueFamilyIndices = nullptr; @@ -1032,7 +1042,6 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk, SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex]; - vk::CommandBuffer *swapCommands = nullptr; if (mColorImageMS.valid()) { // Transition the multisampled image to TRANSFER_SRC for resolve. @@ -1055,14 +1064,17 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk, resolveRegion.dstOffset = {}; resolveRegion.extent = image.image.getExtents(); - ANGLE_TRY(image.image.recordCommands(contextVk, &swapCommands)); - mColorImageMS.resolve(&image.image, resolveRegion, swapCommands); - } - else - { - ANGLE_TRY(image.image.recordCommands(contextVk, &swapCommands)); + vk::CommandBuffer *resolveCommands = nullptr; + ANGLE_TRY(image.image.recordCommands(contextVk, &resolveCommands)); + mColorImageMS.resolve(&image.image, resolveRegion, resolveCommands); } - image.image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::Present, swapCommands); + + ANGLE_TRY(updateAndDrawOverlay(contextVk, &image)); + + vk::CommandBuffer *transitionCommands = nullptr; + ANGLE_TRY(image.image.recordCommands(contextVk, &transitionCommands)); + image.image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::Present, + transitionCommands); // Knowing that the kSwapHistorySize'th submission ago has finished, we can know that the // (kSwapHistorySize+1)'th present ago of this image is definitely finished and so its wait @@ -1408,4 +1420,37 @@ angle::Result WindowSurfaceVk::initializeContents(const gl::Context *context, return angle::Result::Continue; } +angle::Result WindowSurfaceVk::updateAndDrawOverlay(ContextVk *contextVk, + SwapchainImage *image) const +{ + const gl::OverlayType *overlay = contextVk->getOverlay(); + OverlayVk *overlayVk = vk::GetImpl(overlay); + + // If overlay is disabled, nothing to do. + if (overlayVk == nullptr) + { + return angle::Result::Continue; + } + + RendererVk *rendererVk = contextVk->getRenderer(); + + uint32_t validationMessageCount = 0; + std::string lastValidationMessage = + rendererVk->getAndClearLastValidationMessage(&validationMessageCount); + if (validationMessageCount) + { + overlay->getTextWidget(gl::WidgetId::VulkanLastValidationMessage) + ->set(std::move(lastValidationMessage)); + overlay->getCountWidget(gl::WidgetId::VulkanValidationMessageCount) + ->add(validationMessageCount); + } + + // Draw overlay + ANGLE_TRY(overlayVk->onPresent(contextVk, &image->image, &image->imageView)); + + overlay->getRunningGraphWidget(gl::WidgetId::VulkanCommandGraphSize)->next(); + + return angle::Result::Continue; +} + } // namespace rx diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.h b/src/libANGLE/renderer/vulkan/SurfaceVk.h index 0949e3b1f27..51db27f9073 100644 --- a/src/libANGLE/renderer/vulkan/SurfaceVk.h +++ b/src/libANGLE/renderer/vulkan/SurfaceVk.h @@ -244,6 +244,9 @@ class WindowSurfaceVk : public SurfaceVk EGLint n_rects, bool *presentOutOfDate); + struct SwapchainImage; + angle::Result updateAndDrawOverlay(ContextVk *contextVk, SwapchainImage *image) const; + angle::Result swapImpl(const gl::Context *context, EGLint *rects, EGLint n_rects); angle::Result newPresentSemaphore(vk::Context *context, vk::Semaphore *semaphoreOut); diff --git a/src/libANGLE/renderer/vulkan/UtilsVk.cpp b/src/libANGLE/renderer/vulkan/UtilsVk.cpp index 3fa45402a5b..488d5fe06d4 100644 --- a/src/libANGLE/renderer/vulkan/UtilsVk.cpp +++ b/src/libANGLE/renderer/vulkan/UtilsVk.cpp @@ -23,6 +23,8 @@ namespace ImageClear_frag = vk::InternalShader::ImageClear_frag; namespace ImageCopy_frag = vk::InternalShader::ImageCopy_frag; namespace BlitResolve_frag = vk::InternalShader::BlitResolve_frag; namespace BlitResolveStencilNoExport_comp = vk::InternalShader::BlitResolveStencilNoExport_comp; +namespace OverlayCull_comp = vk::InternalShader::OverlayCull_comp; +namespace OverlayDraw_comp = vk::InternalShader::OverlayDraw_comp; namespace { @@ -40,6 +42,13 @@ constexpr uint32_t kBlitResolveSamplerBinding = 2; constexpr uint32_t kBlitResolveStencilNoExportDestBinding = 0; constexpr uint32_t kBlitResolveStencilNoExportSrcBinding = 1; constexpr uint32_t kBlitResolveStencilNoExportSamplerBinding = 2; +constexpr uint32_t kOverlayCullCulledWidgetsBinding = 0; +constexpr uint32_t kOverlayCullWidgetCoordsBinding = 1; +constexpr uint32_t kOverlayDrawOutputBinding = 0; +constexpr uint32_t kOverlayDrawTextWidgetsBinding = 1; +constexpr uint32_t kOverlayDrawGraphWidgetsBinding = 2; +constexpr uint32_t kOverlayDrawCulledWidgetsBinding = 3; +constexpr uint32_t kOverlayDrawFontBinding = 4; uint32_t GetBufferUtilsFlags(size_t dispatchSize, const vk::Format &format) { @@ -343,6 +352,14 @@ void UtilsVk::destroy(VkDevice device) { program.destroy(device); } + for (vk::ShaderProgramHelper &program : mOverlayCullPrograms) + { + program.destroy(device); + } + for (vk::ShaderProgramHelper &program : mOverlayDrawPrograms) + { + program.destroy(device); + } mPointSampler.destroy(device); mLinearSampler.destroy(device); @@ -379,8 +396,11 @@ angle::Result UtilsVk::ensureResourcesInitialized(ContextVk *contextVk, vk::PipelineLayoutDesc pipelineLayoutDesc; pipelineLayoutDesc.updateDescriptorSetLayout(kSetIndex, descriptorSetDesc); - pipelineLayoutDesc.updatePushConstantRange(pushConstantsShaderStage, 0, - static_cast(pushConstantsSize)); + if (pushConstantsSize) + { + pipelineLayoutDesc.updatePushConstantRange(pushConstantsShaderStage, 0, + static_cast(pushConstantsSize)); + } ANGLE_TRY(renderer->getPipelineLayout(contextVk, pipelineLayoutDesc, mDescriptorSetLayouts[function], @@ -483,7 +503,7 @@ angle::Result UtilsVk::ensureBlitResolveResourcesInitialized(ContextVk *contextV ArraySize(setSizes), sizeof(BlitResolveShaderParams))); } - return ensureBlitResolveSamplersInitialized(contextVk); + return ensureSamplersInitialized(contextVk); } angle::Result UtilsVk::ensureBlitResolveStencilNoExportResourcesInitialized(ContextVk *contextVk) @@ -501,10 +521,43 @@ angle::Result UtilsVk::ensureBlitResolveStencilNoExportResourcesInitialized(Cont sizeof(BlitResolveStencilNoExportShaderParams))); } - return ensureBlitResolveSamplersInitialized(contextVk); + return ensureSamplersInitialized(contextVk); } -angle::Result UtilsVk::ensureBlitResolveSamplersInitialized(ContextVk *contextVk) +angle::Result UtilsVk::ensureOverlayCullResourcesInitialized(ContextVk *contextVk) +{ + if (mPipelineLayouts[Function::OverlayCull].valid()) + { + return angle::Result::Continue; + } + + VkDescriptorPoolSize setSizes[2] = { + {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1}, + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1}, + }; + + return ensureResourcesInitialized(contextVk, Function::OverlayCull, setSizes, + ArraySize(setSizes), 0); +} + +angle::Result UtilsVk::ensureOverlayDrawResourcesInitialized(ContextVk *contextVk) +{ + if (!mPipelineLayouts[Function::OverlayDraw].valid()) + { + VkDescriptorPoolSize setSizes[5] = { + {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1}, {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1}, + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1}, {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1}, + {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1}, + }; + + ANGLE_TRY(ensureResourcesInitialized(contextVk, Function::OverlayDraw, setSizes, + ArraySize(setSizes), sizeof(OverlayDrawShaderParams))); + } + + return ensureSamplersInitialized(contextVk); +} + +angle::Result UtilsVk::ensureSamplersInitialized(ContextVk *contextVk) { VkSamplerCreateInfo samplerInfo = {}; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; @@ -603,8 +656,11 @@ angle::Result UtilsVk::setupProgram(ContextVk *contextVk, &descriptorSet, 0, nullptr); } - commandBuffer->pushConstants(pipelineLayout.get(), pushConstantsShaderStage, 0, - static_cast(pushConstantsSize), pushConstants); + if (pushConstants) + { + commandBuffer->pushConstants(pipelineLayout.get(), pushConstantsShaderStage, 0, + static_cast(pushConstantsSize), pushConstants); + } return angle::Result::Continue; } @@ -1446,6 +1502,191 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk, return angle::Result::Continue; } +angle::Result UtilsVk::cullOverlayWidgets(ContextVk *contextVk, + vk::BufferHelper *enabledWidgetsBuffer, + vk::ImageHelper *dest, + const vk::ImageView *destView, + const OverlayCullParameters ¶ms) +{ + ANGLE_TRY(ensureOverlayCullResourcesInitialized(contextVk)); + + ASSERT(params.subgroupSize[0] == 8 && + (params.subgroupSize[1] == 8 || params.subgroupSize[1] == 4)); + uint32_t flags = + params.subgroupSize[1] == 8 ? OverlayCull_comp::kIs8x8 : OverlayCull_comp::kIs8x4; + if (params.supportsSubgroupBallot) + { + flags |= OverlayCull_comp::kSupportsBallot; + } + else if (params.supportsSubgroupBallot) + { + flags |= OverlayCull_comp::kSupportsArithmetic; + } + else + { + flags |= OverlayCull_comp::kSupportsNone; + } + + VkDescriptorSet descriptorSet; + vk::RefCountedDescriptorPoolBinding descriptorPoolBinding; + ANGLE_TRY(allocateDescriptorSet(contextVk, Function::OverlayCull, &descriptorPoolBinding, + &descriptorSet)); + + vk::CommandBuffer *commandBuffer; + ANGLE_TRY(dest->recordCommands(contextVk, &commandBuffer)); + dest->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ComputeShaderWrite, + commandBuffer); + + enabledWidgetsBuffer->onRead(dest, VK_ACCESS_SHADER_READ_BIT); + + VkDescriptorImageInfo imageInfo = {}; + imageInfo.imageView = destView->getHandle(); + imageInfo.imageLayout = dest->getCurrentLayout(); + + VkDescriptorBufferInfo bufferInfo = {}; + bufferInfo.buffer = enabledWidgetsBuffer->getBuffer().getHandle(); + bufferInfo.offset = 0; + bufferInfo.range = VK_WHOLE_SIZE; + + VkWriteDescriptorSet writeInfos[2] = {}; + writeInfos[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeInfos[0].dstSet = descriptorSet; + writeInfos[0].dstBinding = kOverlayCullCulledWidgetsBinding; + writeInfos[0].descriptorCount = 1; + writeInfos[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + writeInfos[0].pImageInfo = &imageInfo; + + writeInfos[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeInfos[1].dstSet = descriptorSet; + writeInfos[1].dstBinding = kOverlayCullWidgetCoordsBinding; + writeInfos[1].descriptorCount = 1; + writeInfos[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeInfos[1].pBufferInfo = &bufferInfo; + + vkUpdateDescriptorSets(contextVk->getDevice(), 2, writeInfos, 0, nullptr); + + vk::RefCounted *shader = nullptr; + ANGLE_TRY(contextVk->getShaderLibrary().getOverlayCull_comp(contextVk, flags, &shader)); + + ANGLE_TRY(setupProgram(contextVk, Function::OverlayCull, shader, nullptr, + &mOverlayCullPrograms[flags], nullptr, descriptorSet, nullptr, 0, + commandBuffer)); + commandBuffer->dispatch(dest->getExtents().width, dest->getExtents().height, 1); + descriptorPoolBinding.reset(); + + dest->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ComputeShaderReadOnly, + commandBuffer); + + return angle::Result::Continue; +} + +angle::Result UtilsVk::drawOverlay(ContextVk *contextVk, + vk::BufferHelper *textWidgetsBuffer, + vk::BufferHelper *graphWidgetsBuffer, + vk::ImageHelper *font, + const vk::ImageView *fontView, + vk::ImageHelper *culledWidgets, + const vk::ImageView *culledWidgetsView, + vk::ImageHelper *dest, + const vk::ImageView *destView, + const OverlayDrawParameters ¶ms) +{ + ANGLE_TRY(ensureOverlayDrawResourcesInitialized(contextVk)); + + OverlayDrawShaderParams shaderParams; + shaderParams.outputSize[0] = dest->getExtents().width; + shaderParams.outputSize[1] = dest->getExtents().height; + + ASSERT(params.subgroupSize[0] == 8 && + (params.subgroupSize[1] == 8 || params.subgroupSize[1] == 4)); + uint32_t flags = + params.subgroupSize[1] == 8 ? OverlayDraw_comp::kIs8x8 : OverlayDraw_comp::kIs8x4; + + VkDescriptorSet descriptorSet; + vk::RefCountedDescriptorPoolBinding descriptorPoolBinding; + ANGLE_TRY(allocateDescriptorSet(contextVk, Function::OverlayDraw, &descriptorPoolBinding, + &descriptorSet)); + + vk::CommandBuffer *commandBuffer; + ANGLE_TRY(dest->recordCommands(contextVk, &commandBuffer)); + dest->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ComputeShaderWrite, + commandBuffer); + + culledWidgets->addReadDependency(dest); + font->addReadDependency(dest); + textWidgetsBuffer->onRead(dest, VK_ACCESS_SHADER_READ_BIT); + graphWidgetsBuffer->onRead(dest, VK_ACCESS_SHADER_READ_BIT); + + VkDescriptorImageInfo imageInfos[3] = {}; + imageInfos[0].imageView = destView->getHandle(); + imageInfos[0].imageLayout = dest->getCurrentLayout(); + + imageInfos[1].imageView = culledWidgetsView->getHandle(); + imageInfos[1].imageLayout = culledWidgets->getCurrentLayout(); + + imageInfos[2].imageView = fontView->getHandle(); + imageInfos[2].imageLayout = font->getCurrentLayout(); + + VkDescriptorBufferInfo bufferInfos[2] = {}; + bufferInfos[0].buffer = textWidgetsBuffer->getBuffer().getHandle(); + bufferInfos[0].offset = 0; + bufferInfos[0].range = VK_WHOLE_SIZE; + + bufferInfos[1].buffer = graphWidgetsBuffer->getBuffer().getHandle(); + bufferInfos[1].offset = 0; + bufferInfos[1].range = VK_WHOLE_SIZE; + + VkWriteDescriptorSet writeInfos[5] = {}; + writeInfos[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeInfos[0].dstSet = descriptorSet; + writeInfos[0].dstBinding = kOverlayDrawOutputBinding; + writeInfos[0].descriptorCount = 1; + writeInfos[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + writeInfos[0].pImageInfo = &imageInfos[0]; + + writeInfos[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeInfos[1].dstSet = descriptorSet; + writeInfos[1].dstBinding = kOverlayDrawCulledWidgetsBinding; + writeInfos[1].descriptorCount = 1; + writeInfos[1].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + writeInfos[1].pImageInfo = &imageInfos[1]; + + writeInfos[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeInfos[2].dstSet = descriptorSet; + writeInfos[2].dstBinding = kOverlayDrawFontBinding; + writeInfos[2].descriptorCount = 1; + writeInfos[2].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + writeInfos[2].pImageInfo = &imageInfos[2]; + + writeInfos[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeInfos[3].dstSet = descriptorSet; + writeInfos[3].dstBinding = kOverlayDrawTextWidgetsBinding; + writeInfos[3].descriptorCount = 1; + writeInfos[3].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeInfos[3].pBufferInfo = &bufferInfos[0]; + + writeInfos[4] = writeInfos[3]; + writeInfos[4].dstBinding = kOverlayDrawGraphWidgetsBinding; + writeInfos[4].pBufferInfo = &bufferInfos[1]; + + vkUpdateDescriptorSets(contextVk->getDevice(), 5, writeInfos, 0, nullptr); + + vk::RefCounted *shader = nullptr; + ANGLE_TRY(contextVk->getShaderLibrary().getOverlayDraw_comp(contextVk, flags, &shader)); + + ANGLE_TRY(setupProgram(contextVk, Function::OverlayDraw, shader, nullptr, + &mOverlayDrawPrograms[flags], nullptr, descriptorSet, &shaderParams, + sizeof(shaderParams), commandBuffer)); + + // Every pixel of culledWidgets corresponds to one workgroup, so we can use that as dispatch + // size. + commandBuffer->dispatch(culledWidgets->getExtents().width, culledWidgets->getExtents().height, + 1); + descriptorPoolBinding.reset(); + + return angle::Result::Continue; +} + angle::Result UtilsVk::allocateDescriptorSet(ContextVk *contextVk, Function function, vk::RefCountedDescriptorPoolBinding *bindingOut, diff --git a/src/libANGLE/renderer/vulkan/UtilsVk.h b/src/libANGLE/renderer/vulkan/UtilsVk.h index 2561bfef5fa..3f07ed1fde3 100644 --- a/src/libANGLE/renderer/vulkan/UtilsVk.h +++ b/src/libANGLE/renderer/vulkan/UtilsVk.h @@ -19,6 +19,7 @@ // on color images. // - Depth/Stencil blit/resolve: Used by FramebufferVk::blit() to implement blit or multisample // resolve on depth/stencil images. +// - Overlay Cull/Draw: Used by OverlayVk to efficiently draw a UI for debugging. // - Mipmap generation: Not yet implemented // @@ -117,6 +118,18 @@ class UtilsVk : angle::NonCopyable bool destFlipY; }; + struct OverlayCullParameters + { + uint32_t subgroupSize[2]; + bool supportsSubgroupBallot; + bool supportsSubgroupArithmetic; + }; + + struct OverlayDrawParameters + { + uint32_t subgroupSize[2]; + }; + angle::Result clearBuffer(ContextVk *contextVk, vk::BufferHelper *dest, const ClearParameters ¶ms); @@ -158,6 +171,24 @@ class UtilsVk : angle::NonCopyable const vk::ImageView *srcView, const CopyImageParameters ¶ms); + // Overlay utilities. + angle::Result cullOverlayWidgets(ContextVk *contextVk, + vk::BufferHelper *enabledWidgetsBuffer, + vk::ImageHelper *dest, + const vk::ImageView *destView, + const OverlayCullParameters ¶ms); + + angle::Result drawOverlay(ContextVk *contextVk, + vk::BufferHelper *textWidgetsBuffer, + vk::BufferHelper *graphWidgetsBuffer, + vk::ImageHelper *font, + const vk::ImageView *fontView, + vk::ImageHelper *culledWidgets, + const vk::ImageView *culledWidgetsView, + vk::ImageHelper *dest, + const vk::ImageView *destView, + const OverlayDrawParameters ¶ms); + private: ANGLE_ENABLE_STRUCT_PADDING_WARNINGS @@ -255,6 +286,12 @@ class UtilsVk : angle::NonCopyable uint32_t flipY = 0; }; + struct OverlayDrawShaderParams + { + // Structure matching PushConstants in OverlayDraw.comp + uint32_t outputSize[2] = {}; + }; + ANGLE_DISABLE_STRUCT_PADDING_WARNINGS // Functions implemented by the class: @@ -271,9 +308,11 @@ class UtilsVk : angle::NonCopyable ConvertIndexBuffer = 4, ConvertVertexBuffer = 5, BlitResolveStencilNoExport = 6, + OverlayCull = 7, + OverlayDraw = 8, - InvalidEnum = 7, - EnumCount = 7, + InvalidEnum = 9, + EnumCount = 9, }; // Common function that creates the pipeline for the specified function, binds it and prepares @@ -312,8 +351,10 @@ class UtilsVk : angle::NonCopyable angle::Result ensureImageCopyResourcesInitialized(ContextVk *contextVk); angle::Result ensureBlitResolveResourcesInitialized(ContextVk *contextVk); angle::Result ensureBlitResolveStencilNoExportResourcesInitialized(ContextVk *contextVk); + angle::Result ensureOverlayCullResourcesInitialized(ContextVk *contextVk); + angle::Result ensureOverlayDrawResourcesInitialized(ContextVk *contextVk); - angle::Result ensureBlitResolveSamplersInitialized(ContextVk *context); + angle::Result ensureSamplersInitialized(ContextVk *context); angle::Result startRenderPass(ContextVk *contextVk, vk::ImageHelper *image, @@ -351,6 +392,8 @@ class UtilsVk : angle::NonCopyable vk::ShaderProgramHelper mBlitResolvePrograms[vk::InternalShader::BlitResolve_frag::kArrayLen]; vk::ShaderProgramHelper mBlitResolveStencilNoExportPrograms [vk::InternalShader::BlitResolveStencilNoExport_comp::kArrayLen]; + vk::ShaderProgramHelper mOverlayCullPrograms[vk::InternalShader::OverlayCull_comp::kArrayLen]; + vk::ShaderProgramHelper mOverlayDrawPrograms[vk::InternalShader::OverlayDraw_comp::kArrayLen]; vk::Sampler mPointSampler; vk::Sampler mLinearSampler; diff --git a/src/libANGLE/renderer/vulkan/gen_vk_internal_shaders.py b/src/libANGLE/renderer/vulkan/gen_vk_internal_shaders.py index 18866af0a1c..bd971f3c1c0 100644 --- a/src/libANGLE/renderer/vulkan/gen_vk_internal_shaders.py +++ b/src/libANGLE/renderer/vulkan/gen_vk_internal_shaders.py @@ -386,6 +386,17 @@ def finish(self): raise Exception(exception) +# If the option is just a string, that's the name. Otherwise, it could be +# [ name, arg1, ..., argN ]. In that case, name is option[0] and option[1:] are extra arguments +# that need to be passed to glslang_validator for this variation. +def get_variation_name(option): + return option if isinstance(option, unicode) else option[0] + + +def get_variation_args(option): + return [] if isinstance(option, unicode) else option[1:] + + def compile_variation(glslang_path, compile_queue, shader_file, shader_basename, flags, enums, flags_active, enum_indices, flags_bits, enum_bits, output_shaders): @@ -398,9 +409,12 @@ def compile_variation(glslang_path, compile_queue, shader_file, shader_basename, # takes up as few bits as needed to count that many enum values. variation_bits = 0 variation_string = '' + variation_extra_args = [] for f in range(len(flags)): if flags_active & (1 << f): - flag_name = flags[f] + flag = flags[f] + flag_name = get_variation_name(flag) + variation_extra_args += get_variation_args(flag) glslang_args.append('-D' + flag_name + '=1') variation_bits |= 1 << f @@ -409,7 +423,9 @@ def compile_variation(glslang_path, compile_queue, shader_file, shader_basename, current_bit_start = flags_bits for e in range(len(enums)): - enum_name = enums[e][1][enum_indices[e]] + enum = enums[e][1][enum_indices[e]] + enum_name = get_variation_name(enum) + variation_extra_args += get_variation_args(enum) glslang_args.append('-D' + enum_name + '=1') variation_bits |= enum_indices[e] << current_bit_start @@ -424,6 +440,8 @@ def compile_variation(glslang_path, compile_queue, shader_file, shader_basename, glslang_preprocessor_output_args = glslang_args + ['-E'] glslang_preprocessor_output_args.append(shader_file) # Input GLSL shader + glslang_args += variation_extra_args + glslang_args += ['-V'] # Output mode is Vulkan glslang_args += ['--variable-name', get_var_name(output_name)] # C-style variable name glslang_args += ['-o', output_path] # Output file @@ -463,7 +481,9 @@ def get_variation_definition(shader_and_variation): definition = 'namespace %s\n{\n' % namespace_name if len(flags) > 0: definition += 'enum flags\n{\n' - definition += ''.join(['k%s = 0x%08X,\n' % (flags[f], 1 << f) for f in range(len(flags))]) + definition += ''.join([ + 'k%s = 0x%08X,\n' % (get_variation_name(flags[f]), 1 << f) for f in range(len(flags)) + ]) definition += '};\n' current_bit_start = flags_bits @@ -473,7 +493,8 @@ def get_variation_definition(shader_and_variation): enum_name = enum[0] definition += 'enum %s\n{\n' % enum_name definition += ''.join([ - 'k%s = 0x%08X,\n' % (enum[1][v], v << current_bit_start) for v in range(len(enum[1])) + 'k%s = 0x%08X,\n' % (get_variation_name(enum[1][v]), v << current_bit_start) + for v in range(len(enum[1])) ]) definition += '};\n' current_bit_start += enum_bits[e] diff --git a/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000000.inc b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000000.inc new file mode 100644 index 00000000000..0369a180867 --- /dev/null +++ b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000000.inc @@ -0,0 +1,145 @@ + // 7.12.3226 + #pragma once +const uint32_t kOverlayCull_comp_00000000[] = { + 0x07230203,0x00010300,0x00080007,0x00000070,0x00000000,0x00020011,0x00000001,0x00020011, + 0x0000003d,0x00020011,0x00000040,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e, + 0x00000000,0x0003000e,0x00000000,0x00000001,0x0007000f,0x00000005,0x00000004,0x6e69616d, + 0x00000000,0x00000012,0x00000046,0x00060010,0x00000004,0x00000011,0x00000020,0x00000001, + 0x00000001,0x00030003,0x00000002,0x000001c2,0x000b0004,0x455f4c47,0x735f5458,0x6c706d61, + 0x656c7265,0x745f7373,0x75747865,0x665f6572,0x74636e75,0x736e6f69,0x00000000,0x00090004, + 0x4b5f4c47,0x735f5248,0x65646168,0x75735f72,0x6f726762,0x625f7075,0x6f6c6c61,0x00000074, + 0x00090004,0x4b5f4c47,0x735f5248,0x65646168,0x75735f72,0x6f726762,0x625f7075,0x63697361, + 0x00000000,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00080005,0x0000000c,0x6c6c7563, + 0x67646957,0x28737465,0x763b3175,0x763b3275,0x003b3275,0x00040005,0x00000009,0x7366666f, + 0x00007465,0x00060005,0x0000000a,0x636f6c62,0x6f6f436b,0x6f4c6472,0x00000077,0x00060005, + 0x0000000b,0x636f6c62,0x6f6f436b,0x69486472,0x00006867,0x00040005,0x0000000f,0x61636f6c, + 0x0064496c,0x00080005,0x00000012,0x4c5f6c67,0x6c61636f,0x6f766e49,0x69746163,0x44496e6f, + 0x00000000,0x00060005,0x00000019,0x67646977,0x6f437465,0x7364726f,0x00000000,0x00070005, + 0x0000001c,0x67646957,0x6f437465,0x6964726f,0x6574616e,0x00000073,0x00060006,0x0000001c, + 0x00000000,0x726f6f63,0x616e6964,0x00736574,0x00030005,0x0000001e,0x00000000,0x00050005, + 0x00000028,0x65746e69,0x63657372,0x00007374,0x00050005,0x00000045,0x4374756f,0x64726f6f, + 0x00000000,0x00060005,0x00000046,0x575f6c67,0x476b726f,0x70756f72,0x00004449,0x00060005, + 0x00000049,0x636f6c62,0x6f6f436b,0x6f4c6472,0x00000077,0x00060005,0x0000004f,0x636f6c62, + 0x6f6f436b,0x69486472,0x00006867,0x00060005,0x00000052,0x6c6c7563,0x69576465,0x74656764, + 0x00000073,0x00070005,0x00000066,0x6c6c7563,0x69576465,0x74656764,0x74754f73,0x00000000, + 0x00040047,0x00000012,0x0000000b,0x0000001b,0x00040047,0x0000001b,0x00000006,0x00000010, + 0x00050048,0x0000001c,0x00000000,0x00000023,0x00000000,0x00030047,0x0000001c,0x00000002, + 0x00040047,0x0000001e,0x00000022,0x00000000,0x00040047,0x0000001e,0x00000021,0x00000001, + 0x00040047,0x00000046,0x0000000b,0x0000001a,0x00040047,0x00000066,0x00000022,0x00000000, + 0x00040047,0x00000066,0x00000021,0x00000000,0x00030047,0x00000066,0x00000019,0x00040047, + 0x0000006f,0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002, + 0x00040015,0x00000006,0x00000020,0x00000000,0x00040017,0x00000007,0x00000006,0x00000002, + 0x00060021,0x00000008,0x00000007,0x00000006,0x00000007,0x00000007,0x00040020,0x0000000e, + 0x00000007,0x00000006,0x00040017,0x00000010,0x00000006,0x00000003,0x00040020,0x00000011, + 0x00000001,0x00000010,0x0004003b,0x00000011,0x00000012,0x00000001,0x0004002b,0x00000006, + 0x00000013,0x00000000,0x00040020,0x00000014,0x00000001,0x00000006,0x00040017,0x00000017, + 0x00000006,0x00000004,0x00040020,0x00000018,0x00000007,0x00000017,0x0004002b,0x00000006, + 0x0000001a,0x00000040,0x0004001c,0x0000001b,0x00000017,0x0000001a,0x0003001e,0x0000001c, + 0x0000001b,0x00040020,0x0000001d,0x00000002,0x0000001c,0x0004003b,0x0000001d,0x0000001e, + 0x00000002,0x00040015,0x0000001f,0x00000020,0x00000001,0x0004002b,0x0000001f,0x00000020, + 0x00000000,0x00040020,0x00000023,0x00000002,0x00000017,0x00020014,0x00000026,0x00040020, + 0x00000027,0x00000007,0x00000026,0x0004002b,0x00000006,0x0000002b,0x00000002,0x00040017, + 0x00000033,0x00000026,0x00000002,0x0004002b,0x00000006,0x0000003f,0x00000003,0x00040020, + 0x00000044,0x00000007,0x00000007,0x0004003b,0x00000011,0x00000046,0x00000001,0x0004002b, + 0x00000006,0x0000004b,0x00000008,0x0004002b,0x00000006,0x0000004c,0x00000004,0x0005002c, + 0x00000007,0x0000004d,0x0000004b,0x0000004c,0x0004002b,0x00000006,0x00000058,0x00000020, + 0x0004002b,0x00000006,0x0000005d,0x00000001,0x00090019,0x00000064,0x00000006,0x00000001, + 0x00000000,0x00000000,0x00000000,0x00000002,0x0000001e,0x00040020,0x00000065,0x00000000, + 0x00000064,0x0004003b,0x00000065,0x00000066,0x00000000,0x00040017,0x00000069,0x0000001f, + 0x00000002,0x0006002c,0x00000010,0x0000006f,0x00000058,0x0000005d,0x0000005d,0x00050036, + 0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000044, + 0x00000045,0x00000007,0x0004003b,0x00000044,0x00000049,0x00000007,0x0004003b,0x00000044, + 0x0000004f,0x00000007,0x0004003b,0x00000044,0x00000052,0x00000007,0x0004003d,0x00000010, + 0x00000047,0x00000046,0x0007004f,0x00000007,0x00000048,0x00000047,0x00000047,0x00000000, + 0x00000001,0x0003003e,0x00000045,0x00000048,0x0004003d,0x00000007,0x0000004a,0x00000045, + 0x00050084,0x00000007,0x0000004e,0x0000004a,0x0000004d,0x0003003e,0x00000049,0x0000004e, + 0x0004003d,0x00000007,0x00000050,0x00000049,0x00050080,0x00000007,0x00000051,0x00000050, + 0x0000004d,0x0003003e,0x0000004f,0x00000051,0x0004003d,0x00000007,0x00000053,0x00000049, + 0x0004003d,0x00000007,0x00000054,0x0000004f,0x00070039,0x00000007,0x00000055,0x0000000c, + 0x00000013,0x00000053,0x00000054,0x00050051,0x00000006,0x00000056,0x00000055,0x00000000, + 0x00050041,0x0000000e,0x00000057,0x00000052,0x00000013,0x0003003e,0x00000057,0x00000056, + 0x0004003d,0x00000007,0x00000059,0x00000049,0x0004003d,0x00000007,0x0000005a,0x0000004f, + 0x00070039,0x00000007,0x0000005b,0x0000000c,0x00000058,0x00000059,0x0000005a,0x00050051, + 0x00000006,0x0000005c,0x0000005b,0x00000000,0x00050041,0x0000000e,0x0000005e,0x00000052, + 0x0000005d,0x0003003e,0x0000005e,0x0000005c,0x00050041,0x00000014,0x0000005f,0x00000012, + 0x00000013,0x0004003d,0x00000006,0x00000060,0x0000005f,0x000500aa,0x00000026,0x00000061, + 0x00000060,0x00000013,0x000300f7,0x00000063,0x00000000,0x000400fa,0x00000061,0x00000062, + 0x00000063,0x000200f8,0x00000062,0x0004003d,0x00000064,0x00000067,0x00000066,0x0004003d, + 0x00000007,0x00000068,0x00000045,0x0004007c,0x00000069,0x0000006a,0x00000068,0x0004003d, + 0x00000007,0x0000006b,0x00000052,0x00050051,0x00000006,0x0000006c,0x0000006b,0x00000000, + 0x00050051,0x00000006,0x0000006d,0x0000006b,0x00000001,0x00070050,0x00000017,0x0000006e, + 0x0000006c,0x0000006d,0x00000013,0x00000013,0x00040063,0x00000067,0x0000006a,0x0000006e, + 0x000200f9,0x00000063,0x000200f8,0x00000063,0x000100fd,0x00010038,0x00050036,0x00000007, + 0x0000000c,0x00000000,0x00000008,0x00030037,0x00000006,0x00000009,0x00030037,0x00000007, + 0x0000000a,0x00030037,0x00000007,0x0000000b,0x000200f8,0x0000000d,0x0004003b,0x0000000e, + 0x0000000f,0x00000007,0x0004003b,0x00000018,0x00000019,0x00000007,0x0004003b,0x00000027, + 0x00000028,0x00000007,0x00050041,0x00000014,0x00000015,0x00000012,0x00000013,0x0004003d, + 0x00000006,0x00000016,0x00000015,0x0003003e,0x0000000f,0x00000016,0x0004003d,0x00000006, + 0x00000021,0x0000000f,0x00050080,0x00000006,0x00000022,0x00000009,0x00000021,0x00060041, + 0x00000023,0x00000024,0x0000001e,0x00000020,0x00000022,0x0004003d,0x00000017,0x00000025, + 0x00000024,0x0003003e,0x00000019,0x00000025,0x00050041,0x0000000e,0x00000029,0x00000019, + 0x00000013,0x0004003d,0x00000006,0x0000002a,0x00000029,0x00050041,0x0000000e,0x0000002c, + 0x00000019,0x0000002b,0x0004003d,0x00000006,0x0000002d,0x0000002c,0x000500b0,0x00000026, + 0x0000002e,0x0000002a,0x0000002d,0x000300f7,0x00000030,0x00000000,0x000400fa,0x0000002e, + 0x0000002f,0x00000030,0x000200f8,0x0000002f,0x0004003d,0x00000017,0x00000031,0x00000019, + 0x0007004f,0x00000007,0x00000032,0x00000031,0x00000031,0x00000000,0x00000001,0x000500b0, + 0x00000033,0x00000034,0x00000032,0x0000000b,0x0004009b,0x00000026,0x00000035,0x00000034, + 0x000200f9,0x00000030,0x000200f8,0x00000030,0x000700f5,0x00000026,0x00000036,0x0000002e, + 0x0000000d,0x00000035,0x0000002f,0x000300f7,0x00000038,0x00000000,0x000400fa,0x00000036, + 0x00000037,0x00000038,0x000200f8,0x00000037,0x0004003d,0x00000017,0x00000039,0x00000019, + 0x0007004f,0x00000007,0x0000003a,0x00000039,0x00000039,0x00000002,0x00000003,0x000500ae, + 0x00000033,0x0000003b,0x0000003a,0x0000000a,0x0004009b,0x00000026,0x0000003c,0x0000003b, + 0x000200f9,0x00000038,0x000200f8,0x00000038,0x000700f5,0x00000026,0x0000003d,0x00000036, + 0x00000030,0x0000003c,0x00000037,0x0003003e,0x00000028,0x0000003d,0x0004003d,0x00000026, + 0x0000003e,0x00000028,0x00050153,0x00000017,0x00000040,0x0000003f,0x0000003e,0x0007004f, + 0x00000007,0x00000041,0x00000040,0x00000040,0x00000000,0x00000001,0x000200fe,0x00000041, + 0x00010038 +}; + +// Generated from: +// +// #version 450 core +// +// #extension GL_EXT_samplerless_texture_functions : require +// +// #extension GL_KHR_shader_subgroup_ballot : require +// +// layout(local_size_x = 32, local_size_y = 1, local_size_z = 1)in; +// +// layout(set = 0, binding = 0, rgba32ui)uniform writeonly uimage2D culledWidgetsOut; +// +// layout(set = 0, binding = 1)uniform WidgetCoordinates +// { +// uvec4 coordinates[32 + 32]; +// }; +// +// uvec2 cullWidgets(const uint offset, const uvec2 blockCoordLow, const uvec2 blockCoordHigh) +// { +// const uint localId = gl_LocalInvocationID . x; +// const uvec4 widgetCoords = coordinates[offset + localId]; +// +// const bool intersects = widgetCoords . x < widgetCoords . z && +// all(lessThan(widgetCoords . xy, blockCoordHigh))&& +// all(greaterThanEqual(widgetCoords . zw, blockCoordLow)); +// +// return subgroupBallot(intersects). xy; +// +// } +// +// void main() +// { +// +// const uvec2 outCoord = gl_WorkGroupID . xy; +// const uvec2 blockCoordLow = outCoord * uvec2(8, 4); +// const uvec2 blockCoordHigh = blockCoordLow + uvec2(8, 4); +// +// uvec2 culledWidgets; +// +// culledWidgets . x = cullWidgets(0, blockCoordLow, blockCoordHigh). x; +// culledWidgets . y = cullWidgets(32, blockCoordLow, blockCoordHigh). x; +// +// if(gl_LocalInvocationID . x == 0) +// { +// imageStore(culledWidgetsOut, ivec2(outCoord), uvec4(culledWidgets, 0, 0)); +// } +// } diff --git a/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000001.inc b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000001.inc new file mode 100644 index 00000000000..cde3872b4a6 --- /dev/null +++ b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000001.inc @@ -0,0 +1,138 @@ + // 7.12.3226 + #pragma once +const uint32_t kOverlayCull_comp_00000001[] = { + 0x07230203,0x00010300,0x00080007,0x00000067,0x00000000,0x00020011,0x00000001,0x00020011, + 0x0000003d,0x00020011,0x00000040,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e, + 0x00000000,0x0003000e,0x00000000,0x00000001,0x0007000f,0x00000005,0x00000004,0x6e69616d, + 0x00000000,0x00000012,0x00000046,0x00060010,0x00000004,0x00000011,0x00000040,0x00000001, + 0x00000001,0x00030003,0x00000002,0x000001c2,0x000b0004,0x455f4c47,0x735f5458,0x6c706d61, + 0x656c7265,0x745f7373,0x75747865,0x665f6572,0x74636e75,0x736e6f69,0x00000000,0x00090004, + 0x4b5f4c47,0x735f5248,0x65646168,0x75735f72,0x6f726762,0x625f7075,0x6f6c6c61,0x00000074, + 0x00090004,0x4b5f4c47,0x735f5248,0x65646168,0x75735f72,0x6f726762,0x625f7075,0x63697361, + 0x00000000,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00080005,0x0000000c,0x6c6c7563, + 0x67646957,0x28737465,0x763b3175,0x763b3275,0x003b3275,0x00040005,0x00000009,0x7366666f, + 0x00007465,0x00060005,0x0000000a,0x636f6c62,0x6f6f436b,0x6f4c6472,0x00000077,0x00060005, + 0x0000000b,0x636f6c62,0x6f6f436b,0x69486472,0x00006867,0x00040005,0x0000000f,0x61636f6c, + 0x0064496c,0x00080005,0x00000012,0x4c5f6c67,0x6c61636f,0x6f766e49,0x69746163,0x44496e6f, + 0x00000000,0x00060005,0x00000019,0x67646977,0x6f437465,0x7364726f,0x00000000,0x00070005, + 0x0000001c,0x67646957,0x6f437465,0x6964726f,0x6574616e,0x00000073,0x00060006,0x0000001c, + 0x00000000,0x726f6f63,0x616e6964,0x00736574,0x00030005,0x0000001e,0x00000000,0x00050005, + 0x00000028,0x65746e69,0x63657372,0x00007374,0x00050005,0x00000045,0x4374756f,0x64726f6f, + 0x00000000,0x00060005,0x00000046,0x575f6c67,0x476b726f,0x70756f72,0x00004449,0x00060005, + 0x00000049,0x636f6c62,0x6f6f436b,0x6f4c6472,0x00000077,0x00060005,0x0000004e,0x636f6c62, + 0x6f6f436b,0x69486472,0x00006867,0x00060005,0x00000051,0x6c6c7563,0x69576465,0x74656764, + 0x00000073,0x00070005,0x0000005c,0x6c6c7563,0x69576465,0x74656764,0x74754f73,0x00000000, + 0x00040047,0x00000012,0x0000000b,0x0000001b,0x00040047,0x0000001b,0x00000006,0x00000010, + 0x00050048,0x0000001c,0x00000000,0x00000023,0x00000000,0x00030047,0x0000001c,0x00000002, + 0x00040047,0x0000001e,0x00000022,0x00000000,0x00040047,0x0000001e,0x00000021,0x00000001, + 0x00040047,0x00000046,0x0000000b,0x0000001a,0x00040047,0x0000005c,0x00000022,0x00000000, + 0x00040047,0x0000005c,0x00000021,0x00000000,0x00030047,0x0000005c,0x00000019,0x00040047, + 0x00000066,0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002, + 0x00040015,0x00000006,0x00000020,0x00000000,0x00040017,0x00000007,0x00000006,0x00000002, + 0x00060021,0x00000008,0x00000007,0x00000006,0x00000007,0x00000007,0x00040020,0x0000000e, + 0x00000007,0x00000006,0x00040017,0x00000010,0x00000006,0x00000003,0x00040020,0x00000011, + 0x00000001,0x00000010,0x0004003b,0x00000011,0x00000012,0x00000001,0x0004002b,0x00000006, + 0x00000013,0x00000000,0x00040020,0x00000014,0x00000001,0x00000006,0x00040017,0x00000017, + 0x00000006,0x00000004,0x00040020,0x00000018,0x00000007,0x00000017,0x0004002b,0x00000006, + 0x0000001a,0x00000040,0x0004001c,0x0000001b,0x00000017,0x0000001a,0x0003001e,0x0000001c, + 0x0000001b,0x00040020,0x0000001d,0x00000002,0x0000001c,0x0004003b,0x0000001d,0x0000001e, + 0x00000002,0x00040015,0x0000001f,0x00000020,0x00000001,0x0004002b,0x0000001f,0x00000020, + 0x00000000,0x00040020,0x00000023,0x00000002,0x00000017,0x00020014,0x00000026,0x00040020, + 0x00000027,0x00000007,0x00000026,0x0004002b,0x00000006,0x0000002b,0x00000002,0x00040017, + 0x00000033,0x00000026,0x00000002,0x0004002b,0x00000006,0x0000003f,0x00000003,0x00040020, + 0x00000044,0x00000007,0x00000007,0x0004003b,0x00000011,0x00000046,0x00000001,0x0004002b, + 0x00000006,0x0000004b,0x00000008,0x0005002c,0x00000007,0x0000004c,0x0000004b,0x0000004b, + 0x00090019,0x0000005a,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,0x00000002, + 0x0000001e,0x00040020,0x0000005b,0x00000000,0x0000005a,0x0004003b,0x0000005b,0x0000005c, + 0x00000000,0x00040017,0x0000005f,0x0000001f,0x00000002,0x0004002b,0x00000006,0x00000065, + 0x00000001,0x0006002c,0x00000010,0x00000066,0x0000001a,0x00000065,0x00000065,0x00050036, + 0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000044, + 0x00000045,0x00000007,0x0004003b,0x00000044,0x00000049,0x00000007,0x0004003b,0x00000044, + 0x0000004e,0x00000007,0x0004003b,0x00000044,0x00000051,0x00000007,0x0004003d,0x00000010, + 0x00000047,0x00000046,0x0007004f,0x00000007,0x00000048,0x00000047,0x00000047,0x00000000, + 0x00000001,0x0003003e,0x00000045,0x00000048,0x0004003d,0x00000007,0x0000004a,0x00000045, + 0x00050084,0x00000007,0x0000004d,0x0000004a,0x0000004c,0x0003003e,0x00000049,0x0000004d, + 0x0004003d,0x00000007,0x0000004f,0x00000049,0x00050080,0x00000007,0x00000050,0x0000004f, + 0x0000004c,0x0003003e,0x0000004e,0x00000050,0x0004003d,0x00000007,0x00000052,0x00000049, + 0x0004003d,0x00000007,0x00000053,0x0000004e,0x00070039,0x00000007,0x00000054,0x0000000c, + 0x00000013,0x00000052,0x00000053,0x0003003e,0x00000051,0x00000054,0x00050041,0x00000014, + 0x00000055,0x00000012,0x00000013,0x0004003d,0x00000006,0x00000056,0x00000055,0x000500aa, + 0x00000026,0x00000057,0x00000056,0x00000013,0x000300f7,0x00000059,0x00000000,0x000400fa, + 0x00000057,0x00000058,0x00000059,0x000200f8,0x00000058,0x0004003d,0x0000005a,0x0000005d, + 0x0000005c,0x0004003d,0x00000007,0x0000005e,0x00000045,0x0004007c,0x0000005f,0x00000060, + 0x0000005e,0x0004003d,0x00000007,0x00000061,0x00000051,0x00050051,0x00000006,0x00000062, + 0x00000061,0x00000000,0x00050051,0x00000006,0x00000063,0x00000061,0x00000001,0x00070050, + 0x00000017,0x00000064,0x00000062,0x00000063,0x00000013,0x00000013,0x00040063,0x0000005d, + 0x00000060,0x00000064,0x000200f9,0x00000059,0x000200f8,0x00000059,0x000100fd,0x00010038, + 0x00050036,0x00000007,0x0000000c,0x00000000,0x00000008,0x00030037,0x00000006,0x00000009, + 0x00030037,0x00000007,0x0000000a,0x00030037,0x00000007,0x0000000b,0x000200f8,0x0000000d, + 0x0004003b,0x0000000e,0x0000000f,0x00000007,0x0004003b,0x00000018,0x00000019,0x00000007, + 0x0004003b,0x00000027,0x00000028,0x00000007,0x00050041,0x00000014,0x00000015,0x00000012, + 0x00000013,0x0004003d,0x00000006,0x00000016,0x00000015,0x0003003e,0x0000000f,0x00000016, + 0x0004003d,0x00000006,0x00000021,0x0000000f,0x00050080,0x00000006,0x00000022,0x00000009, + 0x00000021,0x00060041,0x00000023,0x00000024,0x0000001e,0x00000020,0x00000022,0x0004003d, + 0x00000017,0x00000025,0x00000024,0x0003003e,0x00000019,0x00000025,0x00050041,0x0000000e, + 0x00000029,0x00000019,0x00000013,0x0004003d,0x00000006,0x0000002a,0x00000029,0x00050041, + 0x0000000e,0x0000002c,0x00000019,0x0000002b,0x0004003d,0x00000006,0x0000002d,0x0000002c, + 0x000500b0,0x00000026,0x0000002e,0x0000002a,0x0000002d,0x000300f7,0x00000030,0x00000000, + 0x000400fa,0x0000002e,0x0000002f,0x00000030,0x000200f8,0x0000002f,0x0004003d,0x00000017, + 0x00000031,0x00000019,0x0007004f,0x00000007,0x00000032,0x00000031,0x00000031,0x00000000, + 0x00000001,0x000500b0,0x00000033,0x00000034,0x00000032,0x0000000b,0x0004009b,0x00000026, + 0x00000035,0x00000034,0x000200f9,0x00000030,0x000200f8,0x00000030,0x000700f5,0x00000026, + 0x00000036,0x0000002e,0x0000000d,0x00000035,0x0000002f,0x000300f7,0x00000038,0x00000000, + 0x000400fa,0x00000036,0x00000037,0x00000038,0x000200f8,0x00000037,0x0004003d,0x00000017, + 0x00000039,0x00000019,0x0007004f,0x00000007,0x0000003a,0x00000039,0x00000039,0x00000002, + 0x00000003,0x000500ae,0x00000033,0x0000003b,0x0000003a,0x0000000a,0x0004009b,0x00000026, + 0x0000003c,0x0000003b,0x000200f9,0x00000038,0x000200f8,0x00000038,0x000700f5,0x00000026, + 0x0000003d,0x00000036,0x00000030,0x0000003c,0x00000037,0x0003003e,0x00000028,0x0000003d, + 0x0004003d,0x00000026,0x0000003e,0x00000028,0x00050153,0x00000017,0x00000040,0x0000003f, + 0x0000003e,0x0007004f,0x00000007,0x00000041,0x00000040,0x00000040,0x00000000,0x00000001, + 0x000200fe,0x00000041,0x00010038 +}; + +// Generated from: +// +// #version 450 core +// +// #extension GL_EXT_samplerless_texture_functions : require +// +// #extension GL_KHR_shader_subgroup_ballot : require +// +// layout(local_size_x = 64, local_size_y = 1, local_size_z = 1)in; +// +// layout(set = 0, binding = 0, rgba32ui)uniform writeonly uimage2D culledWidgetsOut; +// +// layout(set = 0, binding = 1)uniform WidgetCoordinates +// { +// uvec4 coordinates[32 + 32]; +// }; +// +// uvec2 cullWidgets(const uint offset, const uvec2 blockCoordLow, const uvec2 blockCoordHigh) +// { +// const uint localId = gl_LocalInvocationID . x; +// const uvec4 widgetCoords = coordinates[offset + localId]; +// +// const bool intersects = widgetCoords . x < widgetCoords . z && +// all(lessThan(widgetCoords . xy, blockCoordHigh))&& +// all(greaterThanEqual(widgetCoords . zw, blockCoordLow)); +// +// return subgroupBallot(intersects). xy; +// +// } +// +// void main() +// { +// +// const uvec2 outCoord = gl_WorkGroupID . xy; +// const uvec2 blockCoordLow = outCoord * uvec2(8, 8); +// const uvec2 blockCoordHigh = blockCoordLow + uvec2(8, 8); +// +// uvec2 culledWidgets; +// +// culledWidgets = cullWidgets(0, blockCoordLow, blockCoordHigh); +// +// if(gl_LocalInvocationID . x == 0) +// { +// imageStore(culledWidgetsOut, ivec2(outCoord), uvec4(culledWidgets, 0, 0)); +// } +// } diff --git a/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000002.inc b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000002.inc new file mode 100644 index 00000000000..ee22eacb042 --- /dev/null +++ b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000002.inc @@ -0,0 +1,146 @@ + // 7.12.3226 + #pragma once +const uint32_t kOverlayCull_comp_00000002[] = { + 0x07230203,0x00010300,0x00080007,0x00000073,0x00000000,0x00020011,0x00000001,0x00020011, + 0x0000003d,0x00020011,0x0000003f,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e, + 0x00000000,0x0003000e,0x00000000,0x00000001,0x0007000f,0x00000005,0x00000004,0x6e69616d, + 0x00000000,0x00000012,0x0000004a,0x00060010,0x00000004,0x00000011,0x00000020,0x00000001, + 0x00000001,0x00030003,0x00000002,0x000001c2,0x000b0004,0x455f4c47,0x735f5458,0x6c706d61, + 0x656c7265,0x745f7373,0x75747865,0x665f6572,0x74636e75,0x736e6f69,0x00000000,0x000a0004, + 0x4b5f4c47,0x735f5248,0x65646168,0x75735f72,0x6f726762,0x615f7075,0x68746972,0x6974656d, + 0x00000063,0x00090004,0x4b5f4c47,0x735f5248,0x65646168,0x75735f72,0x6f726762,0x625f7075, + 0x63697361,0x00000000,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00080005,0x0000000c, + 0x6c6c7563,0x67646957,0x28737465,0x763b3175,0x763b3275,0x003b3275,0x00040005,0x00000009, + 0x7366666f,0x00007465,0x00060005,0x0000000a,0x636f6c62,0x6f6f436b,0x6f4c6472,0x00000077, + 0x00060005,0x0000000b,0x636f6c62,0x6f6f436b,0x69486472,0x00006867,0x00040005,0x0000000f, + 0x61636f6c,0x0064496c,0x00080005,0x00000012,0x4c5f6c67,0x6c61636f,0x6f766e49,0x69746163, + 0x44496e6f,0x00000000,0x00060005,0x00000019,0x67646977,0x6f437465,0x7364726f,0x00000000, + 0x00070005,0x0000001c,0x67646957,0x6f437465,0x6964726f,0x6574616e,0x00000073,0x00060006, + 0x0000001c,0x00000000,0x726f6f63,0x616e6964,0x00736574,0x00030005,0x0000001e,0x00000000, + 0x00050005,0x00000028,0x65746e69,0x63657372,0x00007374,0x00050005,0x00000049,0x4374756f, + 0x64726f6f,0x00000000,0x00060005,0x0000004a,0x575f6c67,0x476b726f,0x70756f72,0x00004449, + 0x00060005,0x0000004d,0x636f6c62,0x6f6f436b,0x6f4c6472,0x00000077,0x00060005,0x00000053, + 0x636f6c62,0x6f6f436b,0x69486472,0x00006867,0x00060005,0x00000056,0x6c6c7563,0x69576465, + 0x74656764,0x00000073,0x00070005,0x00000069,0x6c6c7563,0x69576465,0x74656764,0x74754f73, + 0x00000000,0x00040047,0x00000012,0x0000000b,0x0000001b,0x00040047,0x0000001b,0x00000006, + 0x00000010,0x00050048,0x0000001c,0x00000000,0x00000023,0x00000000,0x00030047,0x0000001c, + 0x00000002,0x00040047,0x0000001e,0x00000022,0x00000000,0x00040047,0x0000001e,0x00000021, + 0x00000001,0x00040047,0x0000004a,0x0000000b,0x0000001a,0x00040047,0x00000069,0x00000022, + 0x00000000,0x00040047,0x00000069,0x00000021,0x00000000,0x00030047,0x00000069,0x00000019, + 0x00040047,0x00000072,0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003, + 0x00000002,0x00040015,0x00000006,0x00000020,0x00000000,0x00040017,0x00000007,0x00000006, + 0x00000002,0x00060021,0x00000008,0x00000007,0x00000006,0x00000007,0x00000007,0x00040020, + 0x0000000e,0x00000007,0x00000006,0x00040017,0x00000010,0x00000006,0x00000003,0x00040020, + 0x00000011,0x00000001,0x00000010,0x0004003b,0x00000011,0x00000012,0x00000001,0x0004002b, + 0x00000006,0x00000013,0x00000000,0x00040020,0x00000014,0x00000001,0x00000006,0x00040017, + 0x00000017,0x00000006,0x00000004,0x00040020,0x00000018,0x00000007,0x00000017,0x0004002b, + 0x00000006,0x0000001a,0x00000040,0x0004001c,0x0000001b,0x00000017,0x0000001a,0x0003001e, + 0x0000001c,0x0000001b,0x00040020,0x0000001d,0x00000002,0x0000001c,0x0004003b,0x0000001d, + 0x0000001e,0x00000002,0x00040015,0x0000001f,0x00000020,0x00000001,0x0004002b,0x0000001f, + 0x00000020,0x00000000,0x00040020,0x00000023,0x00000002,0x00000017,0x00020014,0x00000026, + 0x00040020,0x00000027,0x00000007,0x00000026,0x0004002b,0x00000006,0x0000002b,0x00000002, + 0x00040017,0x00000033,0x00000026,0x00000002,0x0004002b,0x00000006,0x0000003f,0x00000001, + 0x0004002b,0x00000006,0x00000043,0x00000003,0x00040020,0x00000048,0x00000007,0x00000007, + 0x0004003b,0x00000011,0x0000004a,0x00000001,0x0004002b,0x00000006,0x0000004f,0x00000008, + 0x0004002b,0x00000006,0x00000050,0x00000004,0x0005002c,0x00000007,0x00000051,0x0000004f, + 0x00000050,0x0004002b,0x00000006,0x0000005c,0x00000020,0x00090019,0x00000067,0x00000006, + 0x00000001,0x00000000,0x00000000,0x00000000,0x00000002,0x0000001e,0x00040020,0x00000068, + 0x00000000,0x00000067,0x0004003b,0x00000068,0x00000069,0x00000000,0x00040017,0x0000006c, + 0x0000001f,0x00000002,0x0006002c,0x00000010,0x00000072,0x0000005c,0x0000003f,0x0000003f, + 0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b, + 0x00000048,0x00000049,0x00000007,0x0004003b,0x00000048,0x0000004d,0x00000007,0x0004003b, + 0x00000048,0x00000053,0x00000007,0x0004003b,0x00000048,0x00000056,0x00000007,0x0004003d, + 0x00000010,0x0000004b,0x0000004a,0x0007004f,0x00000007,0x0000004c,0x0000004b,0x0000004b, + 0x00000000,0x00000001,0x0003003e,0x00000049,0x0000004c,0x0004003d,0x00000007,0x0000004e, + 0x00000049,0x00050084,0x00000007,0x00000052,0x0000004e,0x00000051,0x0003003e,0x0000004d, + 0x00000052,0x0004003d,0x00000007,0x00000054,0x0000004d,0x00050080,0x00000007,0x00000055, + 0x00000054,0x00000051,0x0003003e,0x00000053,0x00000055,0x0004003d,0x00000007,0x00000057, + 0x0000004d,0x0004003d,0x00000007,0x00000058,0x00000053,0x00070039,0x00000007,0x00000059, + 0x0000000c,0x00000013,0x00000057,0x00000058,0x00050051,0x00000006,0x0000005a,0x00000059, + 0x00000000,0x00050041,0x0000000e,0x0000005b,0x00000056,0x00000013,0x0003003e,0x0000005b, + 0x0000005a,0x0004003d,0x00000007,0x0000005d,0x0000004d,0x0004003d,0x00000007,0x0000005e, + 0x00000053,0x00070039,0x00000007,0x0000005f,0x0000000c,0x0000005c,0x0000005d,0x0000005e, + 0x00050051,0x00000006,0x00000060,0x0000005f,0x00000000,0x00050041,0x0000000e,0x00000061, + 0x00000056,0x0000003f,0x0003003e,0x00000061,0x00000060,0x00050041,0x00000014,0x00000062, + 0x00000012,0x00000013,0x0004003d,0x00000006,0x00000063,0x00000062,0x000500aa,0x00000026, + 0x00000064,0x00000063,0x00000013,0x000300f7,0x00000066,0x00000000,0x000400fa,0x00000064, + 0x00000065,0x00000066,0x000200f8,0x00000065,0x0004003d,0x00000067,0x0000006a,0x00000069, + 0x0004003d,0x00000007,0x0000006b,0x00000049,0x0004007c,0x0000006c,0x0000006d,0x0000006b, + 0x0004003d,0x00000007,0x0000006e,0x00000056,0x00050051,0x00000006,0x0000006f,0x0000006e, + 0x00000000,0x00050051,0x00000006,0x00000070,0x0000006e,0x00000001,0x00070050,0x00000017, + 0x00000071,0x0000006f,0x00000070,0x00000013,0x00000013,0x00040063,0x0000006a,0x0000006d, + 0x00000071,0x000200f9,0x00000066,0x000200f8,0x00000066,0x000100fd,0x00010038,0x00050036, + 0x00000007,0x0000000c,0x00000000,0x00000008,0x00030037,0x00000006,0x00000009,0x00030037, + 0x00000007,0x0000000a,0x00030037,0x00000007,0x0000000b,0x000200f8,0x0000000d,0x0004003b, + 0x0000000e,0x0000000f,0x00000007,0x0004003b,0x00000018,0x00000019,0x00000007,0x0004003b, + 0x00000027,0x00000028,0x00000007,0x00050041,0x00000014,0x00000015,0x00000012,0x00000013, + 0x0004003d,0x00000006,0x00000016,0x00000015,0x0003003e,0x0000000f,0x00000016,0x0004003d, + 0x00000006,0x00000021,0x0000000f,0x00050080,0x00000006,0x00000022,0x00000009,0x00000021, + 0x00060041,0x00000023,0x00000024,0x0000001e,0x00000020,0x00000022,0x0004003d,0x00000017, + 0x00000025,0x00000024,0x0003003e,0x00000019,0x00000025,0x00050041,0x0000000e,0x00000029, + 0x00000019,0x00000013,0x0004003d,0x00000006,0x0000002a,0x00000029,0x00050041,0x0000000e, + 0x0000002c,0x00000019,0x0000002b,0x0004003d,0x00000006,0x0000002d,0x0000002c,0x000500b0, + 0x00000026,0x0000002e,0x0000002a,0x0000002d,0x000300f7,0x00000030,0x00000000,0x000400fa, + 0x0000002e,0x0000002f,0x00000030,0x000200f8,0x0000002f,0x0004003d,0x00000017,0x00000031, + 0x00000019,0x0007004f,0x00000007,0x00000032,0x00000031,0x00000031,0x00000000,0x00000001, + 0x000500b0,0x00000033,0x00000034,0x00000032,0x0000000b,0x0004009b,0x00000026,0x00000035, + 0x00000034,0x000200f9,0x00000030,0x000200f8,0x00000030,0x000700f5,0x00000026,0x00000036, + 0x0000002e,0x0000000d,0x00000035,0x0000002f,0x000300f7,0x00000038,0x00000000,0x000400fa, + 0x00000036,0x00000037,0x00000038,0x000200f8,0x00000037,0x0004003d,0x00000017,0x00000039, + 0x00000019,0x0007004f,0x00000007,0x0000003a,0x00000039,0x00000039,0x00000002,0x00000003, + 0x000500ae,0x00000033,0x0000003b,0x0000003a,0x0000000a,0x0004009b,0x00000026,0x0000003c, + 0x0000003b,0x000200f9,0x00000038,0x000200f8,0x00000038,0x000700f5,0x00000026,0x0000003d, + 0x00000036,0x00000030,0x0000003c,0x00000037,0x0003003e,0x00000028,0x0000003d,0x0004003d, + 0x00000026,0x0000003e,0x00000028,0x000600a9,0x00000006,0x00000040,0x0000003e,0x0000003f, + 0x00000013,0x0004003d,0x00000006,0x00000041,0x0000000f,0x000500c4,0x00000006,0x00000042, + 0x00000040,0x00000041,0x00060168,0x00000006,0x00000044,0x00000043,0x00000000,0x00000042, + 0x00050050,0x00000007,0x00000045,0x00000044,0x00000013,0x000200fe,0x00000045,0x00010038 +}; + +// Generated from: +// +// #version 450 core +// +// #extension GL_EXT_samplerless_texture_functions : require +// +// #extension GL_KHR_shader_subgroup_arithmetic : require +// +// layout(local_size_x = 32, local_size_y = 1, local_size_z = 1)in; +// +// layout(set = 0, binding = 0, rgba32ui)uniform writeonly uimage2D culledWidgetsOut; +// +// layout(set = 0, binding = 1)uniform WidgetCoordinates +// { +// uvec4 coordinates[32 + 32]; +// }; +// +// uvec2 cullWidgets(const uint offset, const uvec2 blockCoordLow, const uvec2 blockCoordHigh) +// { +// const uint localId = gl_LocalInvocationID . x; +// const uvec4 widgetCoords = coordinates[offset + localId]; +// +// const bool intersects = widgetCoords . x < widgetCoords . z && +// all(lessThan(widgetCoords . xy, blockCoordHigh))&& +// all(greaterThanEqual(widgetCoords . zw, blockCoordLow)); +// +// return uvec2(subgroupOr(uint(intersects)<< localId), 0); +// +// } +// +// void main() +// { +// +// const uvec2 outCoord = gl_WorkGroupID . xy; +// const uvec2 blockCoordLow = outCoord * uvec2(8, 4); +// const uvec2 blockCoordHigh = blockCoordLow + uvec2(8, 4); +// +// uvec2 culledWidgets; +// +// culledWidgets . x = cullWidgets(0, blockCoordLow, blockCoordHigh). x; +// culledWidgets . y = cullWidgets(32, blockCoordLow, blockCoordHigh). x; +// +// if(gl_LocalInvocationID . x == 0) +// { +// imageStore(culledWidgetsOut, ivec2(outCoord), uvec4(culledWidgets, 0, 0)); +// } +// } diff --git a/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000003.inc b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000003.inc new file mode 100644 index 00000000000..e0124bbb138 --- /dev/null +++ b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000003.inc @@ -0,0 +1,162 @@ + // 7.12.3226 + #pragma once +const uint32_t kOverlayCull_comp_00000003[] = { + 0x07230203,0x00010300,0x00080007,0x00000083,0x00000000,0x00020011,0x00000001,0x00020011, + 0x0000003d,0x00020011,0x0000003f,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e, + 0x00000000,0x0003000e,0x00000000,0x00000001,0x0007000f,0x00000005,0x00000004,0x6e69616d, + 0x00000000,0x00000012,0x00000063,0x00060010,0x00000004,0x00000011,0x00000040,0x00000001, + 0x00000001,0x00030003,0x00000002,0x000001c2,0x000b0004,0x455f4c47,0x735f5458,0x6c706d61, + 0x656c7265,0x745f7373,0x75747865,0x665f6572,0x74636e75,0x736e6f69,0x00000000,0x000a0004, + 0x4b5f4c47,0x735f5248,0x65646168,0x75735f72,0x6f726762,0x615f7075,0x68746972,0x6974656d, + 0x00000063,0x00090004,0x4b5f4c47,0x735f5248,0x65646168,0x75735f72,0x6f726762,0x625f7075, + 0x63697361,0x00000000,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00080005,0x0000000c, + 0x6c6c7563,0x67646957,0x28737465,0x763b3175,0x763b3275,0x003b3275,0x00040005,0x00000009, + 0x7366666f,0x00007465,0x00060005,0x0000000a,0x636f6c62,0x6f6f436b,0x6f4c6472,0x00000077, + 0x00060005,0x0000000b,0x636f6c62,0x6f6f436b,0x69486472,0x00006867,0x00040005,0x0000000f, + 0x61636f6c,0x0064496c,0x00080005,0x00000012,0x4c5f6c67,0x6c61636f,0x6f766e49,0x69746163, + 0x44496e6f,0x00000000,0x00060005,0x00000019,0x67646977,0x6f437465,0x7364726f,0x00000000, + 0x00070005,0x0000001c,0x67646957,0x6f437465,0x6964726f,0x6574616e,0x00000073,0x00060006, + 0x0000001c,0x00000000,0x726f6f63,0x616e6964,0x00736574,0x00030005,0x0000001e,0x00000000, + 0x00050005,0x00000028,0x65746e69,0x63657372,0x00007374,0x00060005,0x0000003e,0x74786574, + 0x67646957,0x69427465,0x00000074,0x00060005,0x0000004c,0x70617267,0x64695768,0x42746567, + 0x00007469,0x00050005,0x00000062,0x4374756f,0x64726f6f,0x00000000,0x00060005,0x00000063, + 0x575f6c67,0x476b726f,0x70756f72,0x00004449,0x00060005,0x00000066,0x636f6c62,0x6f6f436b, + 0x6f4c6472,0x00000077,0x00060005,0x0000006b,0x636f6c62,0x6f6f436b,0x69486472,0x00006867, + 0x00060005,0x0000006e,0x6c6c7563,0x69576465,0x74656764,0x00000073,0x00070005,0x00000079, + 0x6c6c7563,0x69576465,0x74656764,0x74754f73,0x00000000,0x00040047,0x00000012,0x0000000b, + 0x0000001b,0x00040047,0x0000001b,0x00000006,0x00000010,0x00050048,0x0000001c,0x00000000, + 0x00000023,0x00000000,0x00030047,0x0000001c,0x00000002,0x00040047,0x0000001e,0x00000022, + 0x00000000,0x00040047,0x0000001e,0x00000021,0x00000001,0x00040047,0x00000063,0x0000000b, + 0x0000001a,0x00040047,0x00000079,0x00000022,0x00000000,0x00040047,0x00000079,0x00000021, + 0x00000000,0x00030047,0x00000079,0x00000019,0x00040047,0x00000082,0x0000000b,0x00000019, + 0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00040015,0x00000006,0x00000020, + 0x00000000,0x00040017,0x00000007,0x00000006,0x00000002,0x00060021,0x00000008,0x00000007, + 0x00000006,0x00000007,0x00000007,0x00040020,0x0000000e,0x00000007,0x00000006,0x00040017, + 0x00000010,0x00000006,0x00000003,0x00040020,0x00000011,0x00000001,0x00000010,0x0004003b, + 0x00000011,0x00000012,0x00000001,0x0004002b,0x00000006,0x00000013,0x00000000,0x00040020, + 0x00000014,0x00000001,0x00000006,0x00040017,0x00000017,0x00000006,0x00000004,0x00040020, + 0x00000018,0x00000007,0x00000017,0x0004002b,0x00000006,0x0000001a,0x00000040,0x0004001c, + 0x0000001b,0x00000017,0x0000001a,0x0003001e,0x0000001c,0x0000001b,0x00040020,0x0000001d, + 0x00000002,0x0000001c,0x0004003b,0x0000001d,0x0000001e,0x00000002,0x00040015,0x0000001f, + 0x00000020,0x00000001,0x0004002b,0x0000001f,0x00000020,0x00000000,0x00040020,0x00000023, + 0x00000002,0x00000017,0x00020014,0x00000026,0x00040020,0x00000027,0x00000007,0x00000026, + 0x0004002b,0x00000006,0x0000002b,0x00000002,0x00040017,0x00000033,0x00000026,0x00000002, + 0x0004002b,0x00000006,0x00000040,0x00000020,0x0004002b,0x00000006,0x00000046,0x00000001, + 0x0004002b,0x00000006,0x0000005a,0x00000003,0x00040020,0x00000061,0x00000007,0x00000007, + 0x0004003b,0x00000011,0x00000063,0x00000001,0x0004002b,0x00000006,0x00000068,0x00000008, + 0x0005002c,0x00000007,0x00000069,0x00000068,0x00000068,0x00090019,0x00000077,0x00000006, + 0x00000001,0x00000000,0x00000000,0x00000000,0x00000002,0x0000001e,0x00040020,0x00000078, + 0x00000000,0x00000077,0x0004003b,0x00000078,0x00000079,0x00000000,0x00040017,0x0000007c, + 0x0000001f,0x00000002,0x0006002c,0x00000010,0x00000082,0x0000001a,0x00000046,0x00000046, + 0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b, + 0x00000061,0x00000062,0x00000007,0x0004003b,0x00000061,0x00000066,0x00000007,0x0004003b, + 0x00000061,0x0000006b,0x00000007,0x0004003b,0x00000061,0x0000006e,0x00000007,0x0004003d, + 0x00000010,0x00000064,0x00000063,0x0007004f,0x00000007,0x00000065,0x00000064,0x00000064, + 0x00000000,0x00000001,0x0003003e,0x00000062,0x00000065,0x0004003d,0x00000007,0x00000067, + 0x00000062,0x00050084,0x00000007,0x0000006a,0x00000067,0x00000069,0x0003003e,0x00000066, + 0x0000006a,0x0004003d,0x00000007,0x0000006c,0x00000066,0x00050080,0x00000007,0x0000006d, + 0x0000006c,0x00000069,0x0003003e,0x0000006b,0x0000006d,0x0004003d,0x00000007,0x0000006f, + 0x00000066,0x0004003d,0x00000007,0x00000070,0x0000006b,0x00070039,0x00000007,0x00000071, + 0x0000000c,0x00000013,0x0000006f,0x00000070,0x0003003e,0x0000006e,0x00000071,0x00050041, + 0x00000014,0x00000072,0x00000012,0x00000013,0x0004003d,0x00000006,0x00000073,0x00000072, + 0x000500aa,0x00000026,0x00000074,0x00000073,0x00000013,0x000300f7,0x00000076,0x00000000, + 0x000400fa,0x00000074,0x00000075,0x00000076,0x000200f8,0x00000075,0x0004003d,0x00000077, + 0x0000007a,0x00000079,0x0004003d,0x00000007,0x0000007b,0x00000062,0x0004007c,0x0000007c, + 0x0000007d,0x0000007b,0x0004003d,0x00000007,0x0000007e,0x0000006e,0x00050051,0x00000006, + 0x0000007f,0x0000007e,0x00000000,0x00050051,0x00000006,0x00000080,0x0000007e,0x00000001, + 0x00070050,0x00000017,0x00000081,0x0000007f,0x00000080,0x00000013,0x00000013,0x00040063, + 0x0000007a,0x0000007d,0x00000081,0x000200f9,0x00000076,0x000200f8,0x00000076,0x000100fd, + 0x00010038,0x00050036,0x00000007,0x0000000c,0x00000000,0x00000008,0x00030037,0x00000006, + 0x00000009,0x00030037,0x00000007,0x0000000a,0x00030037,0x00000007,0x0000000b,0x000200f8, + 0x0000000d,0x0004003b,0x0000000e,0x0000000f,0x00000007,0x0004003b,0x00000018,0x00000019, + 0x00000007,0x0004003b,0x00000027,0x00000028,0x00000007,0x0004003b,0x0000000e,0x0000003e, + 0x00000007,0x0004003b,0x0000000e,0x00000042,0x00000007,0x0004003b,0x0000000e,0x0000004c, + 0x00000007,0x0004003b,0x0000000e,0x0000004f,0x00000007,0x00050041,0x00000014,0x00000015, + 0x00000012,0x00000013,0x0004003d,0x00000006,0x00000016,0x00000015,0x0003003e,0x0000000f, + 0x00000016,0x0004003d,0x00000006,0x00000021,0x0000000f,0x00050080,0x00000006,0x00000022, + 0x00000009,0x00000021,0x00060041,0x00000023,0x00000024,0x0000001e,0x00000020,0x00000022, + 0x0004003d,0x00000017,0x00000025,0x00000024,0x0003003e,0x00000019,0x00000025,0x00050041, + 0x0000000e,0x00000029,0x00000019,0x00000013,0x0004003d,0x00000006,0x0000002a,0x00000029, + 0x00050041,0x0000000e,0x0000002c,0x00000019,0x0000002b,0x0004003d,0x00000006,0x0000002d, + 0x0000002c,0x000500b0,0x00000026,0x0000002e,0x0000002a,0x0000002d,0x000300f7,0x00000030, + 0x00000000,0x000400fa,0x0000002e,0x0000002f,0x00000030,0x000200f8,0x0000002f,0x0004003d, + 0x00000017,0x00000031,0x00000019,0x0007004f,0x00000007,0x00000032,0x00000031,0x00000031, + 0x00000000,0x00000001,0x000500b0,0x00000033,0x00000034,0x00000032,0x0000000b,0x0004009b, + 0x00000026,0x00000035,0x00000034,0x000200f9,0x00000030,0x000200f8,0x00000030,0x000700f5, + 0x00000026,0x00000036,0x0000002e,0x0000000d,0x00000035,0x0000002f,0x000300f7,0x00000038, + 0x00000000,0x000400fa,0x00000036,0x00000037,0x00000038,0x000200f8,0x00000037,0x0004003d, + 0x00000017,0x00000039,0x00000019,0x0007004f,0x00000007,0x0000003a,0x00000039,0x00000039, + 0x00000002,0x00000003,0x000500ae,0x00000033,0x0000003b,0x0000003a,0x0000000a,0x0004009b, + 0x00000026,0x0000003c,0x0000003b,0x000200f9,0x00000038,0x000200f8,0x00000038,0x000700f5, + 0x00000026,0x0000003d,0x00000036,0x00000030,0x0000003c,0x00000037,0x0003003e,0x00000028, + 0x0000003d,0x0004003d,0x00000006,0x0000003f,0x0000000f,0x000500b0,0x00000026,0x00000041, + 0x0000003f,0x00000040,0x000300f7,0x00000044,0x00000000,0x000400fa,0x00000041,0x00000043, + 0x0000004a,0x000200f8,0x00000043,0x0004003d,0x00000026,0x00000045,0x00000028,0x000600a9, + 0x00000006,0x00000047,0x00000045,0x00000046,0x00000013,0x0004003d,0x00000006,0x00000048, + 0x0000000f,0x000500c4,0x00000006,0x00000049,0x00000047,0x00000048,0x0003003e,0x00000042, + 0x00000049,0x000200f9,0x00000044,0x000200f8,0x0000004a,0x0003003e,0x00000042,0x00000013, + 0x000200f9,0x00000044,0x000200f8,0x00000044,0x0004003d,0x00000006,0x0000004b,0x00000042, + 0x0003003e,0x0000003e,0x0000004b,0x0004003d,0x00000006,0x0000004d,0x0000000f,0x000500ae, + 0x00000026,0x0000004e,0x0000004d,0x00000040,0x000300f7,0x00000051,0x00000000,0x000400fa, + 0x0000004e,0x00000050,0x00000057,0x000200f8,0x00000050,0x0004003d,0x00000026,0x00000052, + 0x00000028,0x000600a9,0x00000006,0x00000053,0x00000052,0x00000046,0x00000013,0x0004003d, + 0x00000006,0x00000054,0x0000000f,0x00050082,0x00000006,0x00000055,0x00000054,0x00000040, + 0x000500c4,0x00000006,0x00000056,0x00000053,0x00000055,0x0003003e,0x0000004f,0x00000056, + 0x000200f9,0x00000051,0x000200f8,0x00000057,0x0003003e,0x0000004f,0x00000013,0x000200f9, + 0x00000051,0x000200f8,0x00000051,0x0004003d,0x00000006,0x00000058,0x0000004f,0x0003003e, + 0x0000004c,0x00000058,0x0004003d,0x00000006,0x00000059,0x0000003e,0x00060168,0x00000006, + 0x0000005b,0x0000005a,0x00000000,0x00000059,0x0004003d,0x00000006,0x0000005c,0x0000004c, + 0x00060168,0x00000006,0x0000005d,0x0000005a,0x00000000,0x0000005c,0x00050050,0x00000007, + 0x0000005e,0x0000005b,0x0000005d,0x000200fe,0x0000005e,0x00010038 +}; + +// Generated from: +// +// #version 450 core +// +// #extension GL_EXT_samplerless_texture_functions : require +// +// #extension GL_KHR_shader_subgroup_arithmetic : require +// +// layout(local_size_x = 64, local_size_y = 1, local_size_z = 1)in; +// +// layout(set = 0, binding = 0, rgba32ui)uniform writeonly uimage2D culledWidgetsOut; +// +// layout(set = 0, binding = 1)uniform WidgetCoordinates +// { +// uvec4 coordinates[32 + 32]; +// }; +// +// uvec2 cullWidgets(const uint offset, const uvec2 blockCoordLow, const uvec2 blockCoordHigh) +// { +// const uint localId = gl_LocalInvocationID . x; +// const uvec4 widgetCoords = coordinates[offset + localId]; +// +// const bool intersects = widgetCoords . x < widgetCoords . z && +// all(lessThan(widgetCoords . xy, blockCoordHigh))&& +// all(greaterThanEqual(widgetCoords . zw, blockCoordLow)); +// +// const uint textWidgetBit = +// localId < 32 ? uint(intersects)<< localId : 0; +// const uint graphWidgetBit = +// localId >= 32 ? uint(intersects)<<(localId - 32): 0; +// return uvec2(subgroupOr(textWidgetBit), subgroupOr(graphWidgetBit)); +// +// } +// +// void main() +// { +// +// const uvec2 outCoord = gl_WorkGroupID . xy; +// const uvec2 blockCoordLow = outCoord * uvec2(8, 8); +// const uvec2 blockCoordHigh = blockCoordLow + uvec2(8, 8); +// +// uvec2 culledWidgets; +// +// culledWidgets = cullWidgets(0, blockCoordLow, blockCoordHigh); +// +// if(gl_LocalInvocationID . x == 0) +// { +// imageStore(culledWidgetsOut, ivec2(outCoord), uvec4(culledWidgets, 0, 0)); +// } +// } diff --git a/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000004.inc b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000004.inc new file mode 100644 index 00000000000..56b82d1b32e --- /dev/null +++ b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000004.inc @@ -0,0 +1,226 @@ + // 7.12.3226 + #pragma once +const uint32_t kOverlayCull_comp_00000004[] = { + 0x07230203,0x00010000,0x00080007,0x000000b9,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x00000053,0x00000093,0x00060010, + 0x00000004,0x00000011,0x00000020,0x00000001,0x00000001,0x00030003,0x00000002,0x000001c2, + 0x000b0004,0x455f4c47,0x735f5458,0x6c706d61,0x656c7265,0x745f7373,0x75747865,0x665f6572, + 0x74636e75,0x736e6f69,0x00000000,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00080005, + 0x00000009,0x75636361,0x616c756d,0x69576574,0x74656764,0x31752873,0x0000003b,0x00040005, + 0x00000008,0x61636f6c,0x0064496c,0x00080005,0x00000010,0x6c6c7563,0x67646957,0x28737465, + 0x763b3175,0x763b3275,0x003b3275,0x00040005,0x0000000d,0x7366666f,0x00007465,0x00060005, + 0x0000000e,0x636f6c62,0x6f6f436b,0x6f4c6472,0x00000077,0x00060005,0x0000000f,0x636f6c62, + 0x6f6f436b,0x69486472,0x00006867,0x00070005,0x0000001a,0x65746e69,0x63657372,0x676e6974, + 0x67646957,0x00737465,0x00040005,0x00000050,0x61636f6c,0x0064496c,0x00080005,0x00000053, + 0x4c5f6c67,0x6c61636f,0x6f766e49,0x69746163,0x44496e6f,0x00000000,0x00060005,0x0000005a, + 0x67646977,0x6f437465,0x7364726f,0x00000000,0x00070005,0x0000005d,0x67646957,0x6f437465, + 0x6964726f,0x6574616e,0x00000073,0x00060006,0x0000005d,0x00000000,0x726f6f63,0x616e6964, + 0x00736574,0x00030005,0x0000005f,0x00000000,0x00050005,0x00000068,0x65746e69,0x63657372, + 0x00007374,0x00040005,0x0000007e,0x6c6c6162,0x0000746f,0x00050005,0x00000092,0x4374756f, + 0x64726f6f,0x00000000,0x00060005,0x00000093,0x575f6c67,0x476b726f,0x70756f72,0x00004449, + 0x00060005,0x00000096,0x636f6c62,0x6f6f436b,0x6f4c6472,0x00000077,0x00060005,0x0000009a, + 0x636f6c62,0x6f6f436b,0x69486472,0x00006867,0x00060005,0x0000009d,0x6c6c7563,0x69576465, + 0x74656764,0x00000073,0x00070005,0x000000af,0x6c6c7563,0x69576465,0x74656764,0x74754f73, + 0x00000000,0x00040047,0x00000053,0x0000000b,0x0000001b,0x00040047,0x0000005c,0x00000006, + 0x00000010,0x00050048,0x0000005d,0x00000000,0x00000023,0x00000000,0x00030047,0x0000005d, + 0x00000002,0x00040047,0x0000005f,0x00000022,0x00000000,0x00040047,0x0000005f,0x00000021, + 0x00000001,0x00040047,0x00000093,0x0000000b,0x0000001a,0x00040047,0x000000af,0x00000022, + 0x00000000,0x00040047,0x000000af,0x00000021,0x00000000,0x00030047,0x000000af,0x00000019, + 0x00040047,0x000000b8,0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003, + 0x00000002,0x00040015,0x00000006,0x00000020,0x00000000,0x00040021,0x00000007,0x00000002, + 0x00000006,0x00040017,0x0000000b,0x00000006,0x00000002,0x00060021,0x0000000c,0x0000000b, + 0x00000006,0x0000000b,0x0000000b,0x0004002b,0x00000006,0x00000012,0x00000010,0x00020014, + 0x00000013,0x0004002b,0x00000006,0x00000017,0x00000020,0x0004001c,0x00000018,0x00000006, + 0x00000017,0x00040020,0x00000019,0x00000004,0x00000018,0x0004003b,0x00000019,0x0000001a, + 0x00000004,0x00040020,0x0000001c,0x00000004,0x00000006,0x0004002b,0x00000006,0x00000023, + 0x00000008,0x0004002b,0x00000006,0x0000002e,0x00000004,0x0004002b,0x00000006,0x00000039, + 0x00000002,0x0004002b,0x00000006,0x00000044,0x00000001,0x00040020,0x0000004f,0x00000007, + 0x00000006,0x00040017,0x00000051,0x00000006,0x00000003,0x00040020,0x00000052,0x00000001, + 0x00000051,0x0004003b,0x00000052,0x00000053,0x00000001,0x0004002b,0x00000006,0x00000054, + 0x00000000,0x00040020,0x00000055,0x00000001,0x00000006,0x00040017,0x00000058,0x00000006, + 0x00000004,0x00040020,0x00000059,0x00000007,0x00000058,0x0004002b,0x00000006,0x0000005b, + 0x00000040,0x0004001c,0x0000005c,0x00000058,0x0000005b,0x0003001e,0x0000005d,0x0000005c, + 0x00040020,0x0000005e,0x00000002,0x0000005d,0x0004003b,0x0000005e,0x0000005f,0x00000002, + 0x00040015,0x00000060,0x00000020,0x00000001,0x0004002b,0x00000060,0x00000061,0x00000000, + 0x00040020,0x00000064,0x00000002,0x00000058,0x00040020,0x00000067,0x00000007,0x00000013, + 0x00040017,0x00000072,0x00000013,0x00000002,0x00040020,0x0000007d,0x00000007,0x0000000b, + 0x0005002c,0x0000000b,0x0000007f,0x00000054,0x00000054,0x0004003b,0x00000052,0x00000093, + 0x00000001,0x0005002c,0x0000000b,0x00000098,0x00000023,0x0000002e,0x00090019,0x000000ad, + 0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,0x00000002,0x0000001e,0x00040020, + 0x000000ae,0x00000000,0x000000ad,0x0004003b,0x000000ae,0x000000af,0x00000000,0x00040017, + 0x000000b2,0x00000060,0x00000002,0x0006002c,0x00000051,0x000000b8,0x00000017,0x00000044, + 0x00000044,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005, + 0x0004003b,0x0000007d,0x00000092,0x00000007,0x0004003b,0x0000007d,0x00000096,0x00000007, + 0x0004003b,0x0000007d,0x0000009a,0x00000007,0x0004003b,0x0000007d,0x0000009d,0x00000007, + 0x0004003d,0x00000051,0x00000094,0x00000093,0x0007004f,0x0000000b,0x00000095,0x00000094, + 0x00000094,0x00000000,0x00000001,0x0003003e,0x00000092,0x00000095,0x0004003d,0x0000000b, + 0x00000097,0x00000092,0x00050084,0x0000000b,0x00000099,0x00000097,0x00000098,0x0003003e, + 0x00000096,0x00000099,0x0004003d,0x0000000b,0x0000009b,0x00000096,0x00050080,0x0000000b, + 0x0000009c,0x0000009b,0x00000098,0x0003003e,0x0000009a,0x0000009c,0x0004003d,0x0000000b, + 0x0000009e,0x00000096,0x0004003d,0x0000000b,0x0000009f,0x0000009a,0x00070039,0x0000000b, + 0x000000a0,0x00000010,0x00000054,0x0000009e,0x0000009f,0x00050051,0x00000006,0x000000a1, + 0x000000a0,0x00000000,0x00050041,0x0000004f,0x000000a2,0x0000009d,0x00000054,0x0003003e, + 0x000000a2,0x000000a1,0x0004003d,0x0000000b,0x000000a3,0x00000096,0x0004003d,0x0000000b, + 0x000000a4,0x0000009a,0x00070039,0x0000000b,0x000000a5,0x00000010,0x00000017,0x000000a3, + 0x000000a4,0x00050051,0x00000006,0x000000a6,0x000000a5,0x00000000,0x00050041,0x0000004f, + 0x000000a7,0x0000009d,0x00000044,0x0003003e,0x000000a7,0x000000a6,0x00050041,0x00000055, + 0x000000a8,0x00000053,0x00000054,0x0004003d,0x00000006,0x000000a9,0x000000a8,0x000500aa, + 0x00000013,0x000000aa,0x000000a9,0x00000054,0x000300f7,0x000000ac,0x00000000,0x000400fa, + 0x000000aa,0x000000ab,0x000000ac,0x000200f8,0x000000ab,0x0004003d,0x000000ad,0x000000b0, + 0x000000af,0x0004003d,0x0000000b,0x000000b1,0x00000092,0x0004007c,0x000000b2,0x000000b3, + 0x000000b1,0x0004003d,0x0000000b,0x000000b4,0x0000009d,0x00050051,0x00000006,0x000000b5, + 0x000000b4,0x00000000,0x00050051,0x00000006,0x000000b6,0x000000b4,0x00000001,0x00070050, + 0x00000058,0x000000b7,0x000000b5,0x000000b6,0x00000054,0x00000054,0x00040063,0x000000b0, + 0x000000b3,0x000000b7,0x000200f9,0x000000ac,0x000200f8,0x000000ac,0x000100fd,0x00010038, + 0x00050036,0x00000002,0x00000009,0x00000000,0x00000007,0x00030037,0x00000006,0x00000008, + 0x000200f8,0x0000000a,0x000500b0,0x00000013,0x00000014,0x00000008,0x00000012,0x000300f7, + 0x00000016,0x00000000,0x000400fa,0x00000014,0x00000015,0x00000016,0x000200f8,0x00000015, + 0x00050080,0x00000006,0x0000001b,0x00000008,0x00000012,0x00050041,0x0000001c,0x0000001d, + 0x0000001a,0x0000001b,0x0004003d,0x00000006,0x0000001e,0x0000001d,0x00050041,0x0000001c, + 0x0000001f,0x0000001a,0x00000008,0x0004003d,0x00000006,0x00000020,0x0000001f,0x000500c5, + 0x00000006,0x00000021,0x00000020,0x0000001e,0x00050041,0x0000001c,0x00000022,0x0000001a, + 0x00000008,0x0003003e,0x00000022,0x00000021,0x000500b0,0x00000013,0x00000024,0x00000008, + 0x00000023,0x000300f7,0x00000026,0x00000000,0x000400fa,0x00000024,0x00000025,0x00000026, + 0x000200f8,0x00000025,0x00050080,0x00000006,0x00000027,0x00000008,0x00000023,0x00050041, + 0x0000001c,0x00000028,0x0000001a,0x00000027,0x0004003d,0x00000006,0x00000029,0x00000028, + 0x00050041,0x0000001c,0x0000002a,0x0000001a,0x00000008,0x0004003d,0x00000006,0x0000002b, + 0x0000002a,0x000500c5,0x00000006,0x0000002c,0x0000002b,0x00000029,0x00050041,0x0000001c, + 0x0000002d,0x0000001a,0x00000008,0x0003003e,0x0000002d,0x0000002c,0x000500b0,0x00000013, + 0x0000002f,0x00000008,0x0000002e,0x000300f7,0x00000031,0x00000000,0x000400fa,0x0000002f, + 0x00000030,0x00000031,0x000200f8,0x00000030,0x00050080,0x00000006,0x00000032,0x00000008, + 0x0000002e,0x00050041,0x0000001c,0x00000033,0x0000001a,0x00000032,0x0004003d,0x00000006, + 0x00000034,0x00000033,0x00050041,0x0000001c,0x00000035,0x0000001a,0x00000008,0x0004003d, + 0x00000006,0x00000036,0x00000035,0x000500c5,0x00000006,0x00000037,0x00000036,0x00000034, + 0x00050041,0x0000001c,0x00000038,0x0000001a,0x00000008,0x0003003e,0x00000038,0x00000037, + 0x000500b0,0x00000013,0x0000003a,0x00000008,0x00000039,0x000300f7,0x0000003c,0x00000000, + 0x000400fa,0x0000003a,0x0000003b,0x0000003c,0x000200f8,0x0000003b,0x00050080,0x00000006, + 0x0000003d,0x00000008,0x00000039,0x00050041,0x0000001c,0x0000003e,0x0000001a,0x0000003d, + 0x0004003d,0x00000006,0x0000003f,0x0000003e,0x00050041,0x0000001c,0x00000040,0x0000001a, + 0x00000008,0x0004003d,0x00000006,0x00000041,0x00000040,0x000500c5,0x00000006,0x00000042, + 0x00000041,0x0000003f,0x00050041,0x0000001c,0x00000043,0x0000001a,0x00000008,0x0003003e, + 0x00000043,0x00000042,0x000500b0,0x00000013,0x00000045,0x00000008,0x00000044,0x000300f7, + 0x00000047,0x00000000,0x000400fa,0x00000045,0x00000046,0x00000047,0x000200f8,0x00000046, + 0x00050080,0x00000006,0x00000048,0x00000008,0x00000044,0x00050041,0x0000001c,0x00000049, + 0x0000001a,0x00000048,0x0004003d,0x00000006,0x0000004a,0x00000049,0x00050041,0x0000001c, + 0x0000004b,0x0000001a,0x00000008,0x0004003d,0x00000006,0x0000004c,0x0000004b,0x000500c5, + 0x00000006,0x0000004d,0x0000004c,0x0000004a,0x00050041,0x0000001c,0x0000004e,0x0000001a, + 0x00000008,0x0003003e,0x0000004e,0x0000004d,0x000200f9,0x00000047,0x000200f8,0x00000047, + 0x000200f9,0x0000003c,0x000200f8,0x0000003c,0x000200f9,0x00000031,0x000200f8,0x00000031, + 0x000200f9,0x00000026,0x000200f8,0x00000026,0x000200f9,0x00000016,0x000200f8,0x00000016, + 0x000100fd,0x00010038,0x00050036,0x0000000b,0x00000010,0x00000000,0x0000000c,0x00030037, + 0x00000006,0x0000000d,0x00030037,0x0000000b,0x0000000e,0x00030037,0x0000000b,0x0000000f, + 0x000200f8,0x00000011,0x0004003b,0x0000004f,0x00000050,0x00000007,0x0004003b,0x00000059, + 0x0000005a,0x00000007,0x0004003b,0x00000067,0x00000068,0x00000007,0x0004003b,0x0000007d, + 0x0000007e,0x00000007,0x00050041,0x00000055,0x00000056,0x00000053,0x00000054,0x0004003d, + 0x00000006,0x00000057,0x00000056,0x0003003e,0x00000050,0x00000057,0x0004003d,0x00000006, + 0x00000062,0x00000050,0x00050080,0x00000006,0x00000063,0x0000000d,0x00000062,0x00060041, + 0x00000064,0x00000065,0x0000005f,0x00000061,0x00000063,0x0004003d,0x00000058,0x00000066, + 0x00000065,0x0003003e,0x0000005a,0x00000066,0x00050041,0x0000004f,0x00000069,0x0000005a, + 0x00000054,0x0004003d,0x00000006,0x0000006a,0x00000069,0x00050041,0x0000004f,0x0000006b, + 0x0000005a,0x00000039,0x0004003d,0x00000006,0x0000006c,0x0000006b,0x000500b0,0x00000013, + 0x0000006d,0x0000006a,0x0000006c,0x000300f7,0x0000006f,0x00000000,0x000400fa,0x0000006d, + 0x0000006e,0x0000006f,0x000200f8,0x0000006e,0x0004003d,0x00000058,0x00000070,0x0000005a, + 0x0007004f,0x0000000b,0x00000071,0x00000070,0x00000070,0x00000000,0x00000001,0x000500b0, + 0x00000072,0x00000073,0x00000071,0x0000000f,0x0004009b,0x00000013,0x00000074,0x00000073, + 0x000200f9,0x0000006f,0x000200f8,0x0000006f,0x000700f5,0x00000013,0x00000075,0x0000006d, + 0x00000011,0x00000074,0x0000006e,0x000300f7,0x00000077,0x00000000,0x000400fa,0x00000075, + 0x00000076,0x00000077,0x000200f8,0x00000076,0x0004003d,0x00000058,0x00000078,0x0000005a, + 0x0007004f,0x0000000b,0x00000079,0x00000078,0x00000078,0x00000002,0x00000003,0x000500ae, + 0x00000072,0x0000007a,0x00000079,0x0000000e,0x0004009b,0x00000013,0x0000007b,0x0000007a, + 0x000200f9,0x00000077,0x000200f8,0x00000077,0x000700f5,0x00000013,0x0000007c,0x00000075, + 0x0000006f,0x0000007b,0x00000076,0x0003003e,0x00000068,0x0000007c,0x0003003e,0x0000007e, + 0x0000007f,0x0004003d,0x00000006,0x00000080,0x00000050,0x0004003d,0x00000013,0x00000081, + 0x00000068,0x000600a9,0x00000006,0x00000082,0x00000081,0x00000044,0x00000054,0x0004003d, + 0x00000006,0x00000083,0x00000050,0x000500c4,0x00000006,0x00000084,0x00000082,0x00000083, + 0x00050041,0x0000001c,0x00000085,0x0000001a,0x00000080,0x0003003e,0x00000085,0x00000084, + 0x0004003d,0x00000006,0x00000086,0x00000050,0x00050039,0x00000002,0x00000087,0x00000009, + 0x00000086,0x0004003d,0x00000006,0x00000088,0x00000050,0x000500aa,0x00000013,0x00000089, + 0x00000088,0x00000054,0x000300f7,0x0000008b,0x00000000,0x000400fa,0x00000089,0x0000008a, + 0x0000008b,0x000200f8,0x0000008a,0x00050041,0x0000001c,0x0000008c,0x0000001a,0x00000061, + 0x0004003d,0x00000006,0x0000008d,0x0000008c,0x00050041,0x0000004f,0x0000008e,0x0000007e, + 0x00000054,0x0003003e,0x0000008e,0x0000008d,0x000200f9,0x0000008b,0x000200f8,0x0000008b, + 0x0004003d,0x0000000b,0x0000008f,0x0000007e,0x000200fe,0x0000008f,0x00010038 +}; + +// Generated from: +// +// #version 450 core +// +// #extension GL_EXT_samplerless_texture_functions : require +// +// layout(local_size_x = 32, local_size_y = 1, local_size_z = 1)in; +// +// layout(set = 0, binding = 0, rgba32ui)uniform writeonly uimage2D culledWidgetsOut; +// +// layout(set = 0, binding = 1)uniform WidgetCoordinates +// { +// uvec4 coordinates[32 + 32]; +// }; +// +// shared uint intersectingWidgets[32]; +// +// void accumulateWidgets(const uint localId) +// { +// +// if(localId < 16) +// { +// intersectingWidgets[localId]|= intersectingWidgets[localId + 16]; +// if(localId < 8) +// { +// intersectingWidgets[localId]|= intersectingWidgets[localId + 8]; +// if(localId < 4) +// { +// intersectingWidgets[localId]|= intersectingWidgets[localId + 4]; +// if(localId < 2) +// { +// intersectingWidgets[localId]|= intersectingWidgets[localId + 2]; +// if(localId < 1) +// { +// intersectingWidgets[localId]|= intersectingWidgets[localId + 1]; +// } +// } +// } +// } +// } +// } +// +// uvec2 cullWidgets(const uint offset, const uvec2 blockCoordLow, const uvec2 blockCoordHigh) +// { +// const uint localId = gl_LocalInvocationID . x; +// const uvec4 widgetCoords = coordinates[offset + localId]; +// +// const bool intersects = widgetCoords . x < widgetCoords . z && +// all(lessThan(widgetCoords . xy, blockCoordHigh))&& +// all(greaterThanEqual(widgetCoords . zw, blockCoordLow)); +// +// uvec2 ballot = uvec2(0, 0); +// +// intersectingWidgets[localId]= uint(intersects)<< localId; +// accumulateWidgets(localId); +// if(localId == 0) +// { +// ballot . x = intersectingWidgets[0]; +// } +// +// return ballot; +// +// } +// +// void main() +// { +// +// const uvec2 outCoord = gl_WorkGroupID . xy; +// const uvec2 blockCoordLow = outCoord * uvec2(8, 4); +// const uvec2 blockCoordHigh = blockCoordLow + uvec2(8, 4); +// +// uvec2 culledWidgets; +// +// culledWidgets . x = cullWidgets(0, blockCoordLow, blockCoordHigh). x; +// culledWidgets . y = cullWidgets(32, blockCoordLow, blockCoordHigh). x; +// +// if(gl_LocalInvocationID . x == 0) +// { +// imageStore(culledWidgetsOut, ivec2(outCoord), uvec4(culledWidgets, 0, 0)); +// } +// } diff --git a/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000005.inc b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000005.inc new file mode 100644 index 00000000000..67047d9eba2 --- /dev/null +++ b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000005.inc @@ -0,0 +1,249 @@ + // 7.12.3226 + #pragma once +const uint32_t kOverlayCull_comp_00000005[] = { + 0x07230203,0x00010000,0x00080007,0x000000c9,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x00000053,0x000000aa,0x00060010, + 0x00000004,0x00000011,0x00000040,0x00000001,0x00000001,0x00030003,0x00000002,0x000001c2, + 0x000b0004,0x455f4c47,0x735f5458,0x6c706d61,0x656c7265,0x745f7373,0x75747865,0x665f6572, + 0x74636e75,0x736e6f69,0x00000000,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00080005, + 0x00000009,0x75636361,0x616c756d,0x69576574,0x74656764,0x31752873,0x0000003b,0x00040005, + 0x00000008,0x61636f6c,0x0064496c,0x00080005,0x00000010,0x6c6c7563,0x67646957,0x28737465, + 0x763b3175,0x763b3275,0x003b3275,0x00040005,0x0000000d,0x7366666f,0x00007465,0x00060005, + 0x0000000e,0x636f6c62,0x6f6f436b,0x6f4c6472,0x00000077,0x00060005,0x0000000f,0x636f6c62, + 0x6f6f436b,0x69486472,0x00006867,0x00070005,0x0000001a,0x65746e69,0x63657372,0x676e6974, + 0x67646957,0x00737465,0x00040005,0x00000050,0x61636f6c,0x0064496c,0x00080005,0x00000053, + 0x4c5f6c67,0x6c61636f,0x6f766e49,0x69746163,0x44496e6f,0x00000000,0x00060005,0x0000005a, + 0x67646977,0x6f437465,0x7364726f,0x00000000,0x00070005,0x0000005d,0x67646957,0x6f437465, + 0x6964726f,0x6574616e,0x00000073,0x00060006,0x0000005d,0x00000000,0x726f6f63,0x616e6964, + 0x00736574,0x00030005,0x0000005f,0x00000000,0x00050005,0x00000068,0x65746e69,0x63657372, + 0x00007374,0x00040005,0x0000007e,0x6c6c6162,0x0000746f,0x00060005,0x00000094,0x70617267, + 0x636f4c68,0x64496c61,0x00000000,0x00050005,0x000000a9,0x4374756f,0x64726f6f,0x00000000, + 0x00060005,0x000000aa,0x575f6c67,0x476b726f,0x70756f72,0x00004449,0x00060005,0x000000ad, + 0x636f6c62,0x6f6f436b,0x6f4c6472,0x00000077,0x00060005,0x000000b1,0x636f6c62,0x6f6f436b, + 0x69486472,0x00006867,0x00060005,0x000000b4,0x6c6c7563,0x69576465,0x74656764,0x00000073, + 0x00070005,0x000000bf,0x6c6c7563,0x69576465,0x74656764,0x74754f73,0x00000000,0x00040047, + 0x00000053,0x0000000b,0x0000001b,0x00040047,0x0000005c,0x00000006,0x00000010,0x00050048, + 0x0000005d,0x00000000,0x00000023,0x00000000,0x00030047,0x0000005d,0x00000002,0x00040047, + 0x0000005f,0x00000022,0x00000000,0x00040047,0x0000005f,0x00000021,0x00000001,0x00040047, + 0x000000aa,0x0000000b,0x0000001a,0x00040047,0x000000bf,0x00000022,0x00000000,0x00040047, + 0x000000bf,0x00000021,0x00000000,0x00030047,0x000000bf,0x00000019,0x00040047,0x000000c8, + 0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00040015, + 0x00000006,0x00000020,0x00000000,0x00040021,0x00000007,0x00000002,0x00000006,0x00040017, + 0x0000000b,0x00000006,0x00000002,0x00060021,0x0000000c,0x0000000b,0x00000006,0x0000000b, + 0x0000000b,0x0004002b,0x00000006,0x00000012,0x00000010,0x00020014,0x00000013,0x0004002b, + 0x00000006,0x00000017,0x00000020,0x0004001c,0x00000018,0x00000006,0x00000017,0x00040020, + 0x00000019,0x00000004,0x00000018,0x0004003b,0x00000019,0x0000001a,0x00000004,0x00040020, + 0x0000001c,0x00000004,0x00000006,0x0004002b,0x00000006,0x00000023,0x00000008,0x0004002b, + 0x00000006,0x0000002e,0x00000004,0x0004002b,0x00000006,0x00000039,0x00000002,0x0004002b, + 0x00000006,0x00000044,0x00000001,0x00040020,0x0000004f,0x00000007,0x00000006,0x00040017, + 0x00000051,0x00000006,0x00000003,0x00040020,0x00000052,0x00000001,0x00000051,0x0004003b, + 0x00000052,0x00000053,0x00000001,0x0004002b,0x00000006,0x00000054,0x00000000,0x00040020, + 0x00000055,0x00000001,0x00000006,0x00040017,0x00000058,0x00000006,0x00000004,0x00040020, + 0x00000059,0x00000007,0x00000058,0x0004002b,0x00000006,0x0000005b,0x00000040,0x0004001c, + 0x0000005c,0x00000058,0x0000005b,0x0003001e,0x0000005d,0x0000005c,0x00040020,0x0000005e, + 0x00000002,0x0000005d,0x0004003b,0x0000005e,0x0000005f,0x00000002,0x00040015,0x00000060, + 0x00000020,0x00000001,0x0004002b,0x00000060,0x00000061,0x00000000,0x00040020,0x00000064, + 0x00000002,0x00000058,0x00040020,0x00000067,0x00000007,0x00000013,0x00040017,0x00000072, + 0x00000013,0x00000002,0x00040020,0x0000007d,0x00000007,0x0000000b,0x0005002c,0x0000000b, + 0x0000007f,0x00000054,0x00000054,0x0004003b,0x00000052,0x000000aa,0x00000001,0x0005002c, + 0x0000000b,0x000000af,0x00000023,0x00000023,0x00090019,0x000000bd,0x00000006,0x00000001, + 0x00000000,0x00000000,0x00000000,0x00000002,0x0000001e,0x00040020,0x000000be,0x00000000, + 0x000000bd,0x0004003b,0x000000be,0x000000bf,0x00000000,0x00040017,0x000000c2,0x00000060, + 0x00000002,0x0006002c,0x00000051,0x000000c8,0x0000005b,0x00000044,0x00000044,0x00050036, + 0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x0000007d, + 0x000000a9,0x00000007,0x0004003b,0x0000007d,0x000000ad,0x00000007,0x0004003b,0x0000007d, + 0x000000b1,0x00000007,0x0004003b,0x0000007d,0x000000b4,0x00000007,0x0004003d,0x00000051, + 0x000000ab,0x000000aa,0x0007004f,0x0000000b,0x000000ac,0x000000ab,0x000000ab,0x00000000, + 0x00000001,0x0003003e,0x000000a9,0x000000ac,0x0004003d,0x0000000b,0x000000ae,0x000000a9, + 0x00050084,0x0000000b,0x000000b0,0x000000ae,0x000000af,0x0003003e,0x000000ad,0x000000b0, + 0x0004003d,0x0000000b,0x000000b2,0x000000ad,0x00050080,0x0000000b,0x000000b3,0x000000b2, + 0x000000af,0x0003003e,0x000000b1,0x000000b3,0x0004003d,0x0000000b,0x000000b5,0x000000ad, + 0x0004003d,0x0000000b,0x000000b6,0x000000b1,0x00070039,0x0000000b,0x000000b7,0x00000010, + 0x00000054,0x000000b5,0x000000b6,0x0003003e,0x000000b4,0x000000b7,0x00050041,0x00000055, + 0x000000b8,0x00000053,0x00000054,0x0004003d,0x00000006,0x000000b9,0x000000b8,0x000500aa, + 0x00000013,0x000000ba,0x000000b9,0x00000054,0x000300f7,0x000000bc,0x00000000,0x000400fa, + 0x000000ba,0x000000bb,0x000000bc,0x000200f8,0x000000bb,0x0004003d,0x000000bd,0x000000c0, + 0x000000bf,0x0004003d,0x0000000b,0x000000c1,0x000000a9,0x0004007c,0x000000c2,0x000000c3, + 0x000000c1,0x0004003d,0x0000000b,0x000000c4,0x000000b4,0x00050051,0x00000006,0x000000c5, + 0x000000c4,0x00000000,0x00050051,0x00000006,0x000000c6,0x000000c4,0x00000001,0x00070050, + 0x00000058,0x000000c7,0x000000c5,0x000000c6,0x00000054,0x00000054,0x00040063,0x000000c0, + 0x000000c3,0x000000c7,0x000200f9,0x000000bc,0x000200f8,0x000000bc,0x000100fd,0x00010038, + 0x00050036,0x00000002,0x00000009,0x00000000,0x00000007,0x00030037,0x00000006,0x00000008, + 0x000200f8,0x0000000a,0x000500b0,0x00000013,0x00000014,0x00000008,0x00000012,0x000300f7, + 0x00000016,0x00000000,0x000400fa,0x00000014,0x00000015,0x00000016,0x000200f8,0x00000015, + 0x00050080,0x00000006,0x0000001b,0x00000008,0x00000012,0x00050041,0x0000001c,0x0000001d, + 0x0000001a,0x0000001b,0x0004003d,0x00000006,0x0000001e,0x0000001d,0x00050041,0x0000001c, + 0x0000001f,0x0000001a,0x00000008,0x0004003d,0x00000006,0x00000020,0x0000001f,0x000500c5, + 0x00000006,0x00000021,0x00000020,0x0000001e,0x00050041,0x0000001c,0x00000022,0x0000001a, + 0x00000008,0x0003003e,0x00000022,0x00000021,0x000500b0,0x00000013,0x00000024,0x00000008, + 0x00000023,0x000300f7,0x00000026,0x00000000,0x000400fa,0x00000024,0x00000025,0x00000026, + 0x000200f8,0x00000025,0x00050080,0x00000006,0x00000027,0x00000008,0x00000023,0x00050041, + 0x0000001c,0x00000028,0x0000001a,0x00000027,0x0004003d,0x00000006,0x00000029,0x00000028, + 0x00050041,0x0000001c,0x0000002a,0x0000001a,0x00000008,0x0004003d,0x00000006,0x0000002b, + 0x0000002a,0x000500c5,0x00000006,0x0000002c,0x0000002b,0x00000029,0x00050041,0x0000001c, + 0x0000002d,0x0000001a,0x00000008,0x0003003e,0x0000002d,0x0000002c,0x000500b0,0x00000013, + 0x0000002f,0x00000008,0x0000002e,0x000300f7,0x00000031,0x00000000,0x000400fa,0x0000002f, + 0x00000030,0x00000031,0x000200f8,0x00000030,0x00050080,0x00000006,0x00000032,0x00000008, + 0x0000002e,0x00050041,0x0000001c,0x00000033,0x0000001a,0x00000032,0x0004003d,0x00000006, + 0x00000034,0x00000033,0x00050041,0x0000001c,0x00000035,0x0000001a,0x00000008,0x0004003d, + 0x00000006,0x00000036,0x00000035,0x000500c5,0x00000006,0x00000037,0x00000036,0x00000034, + 0x00050041,0x0000001c,0x00000038,0x0000001a,0x00000008,0x0003003e,0x00000038,0x00000037, + 0x000500b0,0x00000013,0x0000003a,0x00000008,0x00000039,0x000300f7,0x0000003c,0x00000000, + 0x000400fa,0x0000003a,0x0000003b,0x0000003c,0x000200f8,0x0000003b,0x00050080,0x00000006, + 0x0000003d,0x00000008,0x00000039,0x00050041,0x0000001c,0x0000003e,0x0000001a,0x0000003d, + 0x0004003d,0x00000006,0x0000003f,0x0000003e,0x00050041,0x0000001c,0x00000040,0x0000001a, + 0x00000008,0x0004003d,0x00000006,0x00000041,0x00000040,0x000500c5,0x00000006,0x00000042, + 0x00000041,0x0000003f,0x00050041,0x0000001c,0x00000043,0x0000001a,0x00000008,0x0003003e, + 0x00000043,0x00000042,0x000500b0,0x00000013,0x00000045,0x00000008,0x00000044,0x000300f7, + 0x00000047,0x00000000,0x000400fa,0x00000045,0x00000046,0x00000047,0x000200f8,0x00000046, + 0x00050080,0x00000006,0x00000048,0x00000008,0x00000044,0x00050041,0x0000001c,0x00000049, + 0x0000001a,0x00000048,0x0004003d,0x00000006,0x0000004a,0x00000049,0x00050041,0x0000001c, + 0x0000004b,0x0000001a,0x00000008,0x0004003d,0x00000006,0x0000004c,0x0000004b,0x000500c5, + 0x00000006,0x0000004d,0x0000004c,0x0000004a,0x00050041,0x0000001c,0x0000004e,0x0000001a, + 0x00000008,0x0003003e,0x0000004e,0x0000004d,0x000200f9,0x00000047,0x000200f8,0x00000047, + 0x000200f9,0x0000003c,0x000200f8,0x0000003c,0x000200f9,0x00000031,0x000200f8,0x00000031, + 0x000200f9,0x00000026,0x000200f8,0x00000026,0x000200f9,0x00000016,0x000200f8,0x00000016, + 0x000100fd,0x00010038,0x00050036,0x0000000b,0x00000010,0x00000000,0x0000000c,0x00030037, + 0x00000006,0x0000000d,0x00030037,0x0000000b,0x0000000e,0x00030037,0x0000000b,0x0000000f, + 0x000200f8,0x00000011,0x0004003b,0x0000004f,0x00000050,0x00000007,0x0004003b,0x00000059, + 0x0000005a,0x00000007,0x0004003b,0x00000067,0x00000068,0x00000007,0x0004003b,0x0000007d, + 0x0000007e,0x00000007,0x0004003b,0x0000004f,0x00000094,0x00000007,0x00050041,0x00000055, + 0x00000056,0x00000053,0x00000054,0x0004003d,0x00000006,0x00000057,0x00000056,0x0003003e, + 0x00000050,0x00000057,0x0004003d,0x00000006,0x00000062,0x00000050,0x00050080,0x00000006, + 0x00000063,0x0000000d,0x00000062,0x00060041,0x00000064,0x00000065,0x0000005f,0x00000061, + 0x00000063,0x0004003d,0x00000058,0x00000066,0x00000065,0x0003003e,0x0000005a,0x00000066, + 0x00050041,0x0000004f,0x00000069,0x0000005a,0x00000054,0x0004003d,0x00000006,0x0000006a, + 0x00000069,0x00050041,0x0000004f,0x0000006b,0x0000005a,0x00000039,0x0004003d,0x00000006, + 0x0000006c,0x0000006b,0x000500b0,0x00000013,0x0000006d,0x0000006a,0x0000006c,0x000300f7, + 0x0000006f,0x00000000,0x000400fa,0x0000006d,0x0000006e,0x0000006f,0x000200f8,0x0000006e, + 0x0004003d,0x00000058,0x00000070,0x0000005a,0x0007004f,0x0000000b,0x00000071,0x00000070, + 0x00000070,0x00000000,0x00000001,0x000500b0,0x00000072,0x00000073,0x00000071,0x0000000f, + 0x0004009b,0x00000013,0x00000074,0x00000073,0x000200f9,0x0000006f,0x000200f8,0x0000006f, + 0x000700f5,0x00000013,0x00000075,0x0000006d,0x00000011,0x00000074,0x0000006e,0x000300f7, + 0x00000077,0x00000000,0x000400fa,0x00000075,0x00000076,0x00000077,0x000200f8,0x00000076, + 0x0004003d,0x00000058,0x00000078,0x0000005a,0x0007004f,0x0000000b,0x00000079,0x00000078, + 0x00000078,0x00000002,0x00000003,0x000500ae,0x00000072,0x0000007a,0x00000079,0x0000000e, + 0x0004009b,0x00000013,0x0000007b,0x0000007a,0x000200f9,0x00000077,0x000200f8,0x00000077, + 0x000700f5,0x00000013,0x0000007c,0x00000075,0x0000006f,0x0000007b,0x00000076,0x0003003e, + 0x00000068,0x0000007c,0x0003003e,0x0000007e,0x0000007f,0x0004003d,0x00000006,0x00000080, + 0x00000050,0x000500b0,0x00000013,0x00000081,0x00000080,0x00000017,0x000300f7,0x00000083, + 0x00000000,0x000400fa,0x00000081,0x00000082,0x00000093,0x000200f8,0x00000082,0x0004003d, + 0x00000006,0x00000084,0x00000050,0x0004003d,0x00000013,0x00000085,0x00000068,0x000600a9, + 0x00000006,0x00000086,0x00000085,0x00000044,0x00000054,0x0004003d,0x00000006,0x00000087, + 0x00000050,0x000500c4,0x00000006,0x00000088,0x00000086,0x00000087,0x00050041,0x0000001c, + 0x00000089,0x0000001a,0x00000084,0x0003003e,0x00000089,0x00000088,0x0004003d,0x00000006, + 0x0000008a,0x00000050,0x00050039,0x00000002,0x0000008b,0x00000009,0x0000008a,0x0004003d, + 0x00000006,0x0000008c,0x00000050,0x000500aa,0x00000013,0x0000008d,0x0000008c,0x00000054, + 0x000300f7,0x0000008f,0x00000000,0x000400fa,0x0000008d,0x0000008e,0x0000008f,0x000200f8, + 0x0000008e,0x00050041,0x0000001c,0x00000090,0x0000001a,0x00000061,0x0004003d,0x00000006, + 0x00000091,0x00000090,0x00050041,0x0000004f,0x00000092,0x0000007e,0x00000054,0x0003003e, + 0x00000092,0x00000091,0x000200f9,0x0000008f,0x000200f8,0x0000008f,0x000200f9,0x00000083, + 0x000200f8,0x00000093,0x0004003d,0x00000006,0x00000095,0x00000050,0x00050082,0x00000006, + 0x00000096,0x00000095,0x00000017,0x0003003e,0x00000094,0x00000096,0x0004003d,0x00000006, + 0x00000097,0x00000094,0x0004003d,0x00000013,0x00000098,0x00000068,0x000600a9,0x00000006, + 0x00000099,0x00000098,0x00000044,0x00000054,0x0004003d,0x00000006,0x0000009a,0x00000094, + 0x000500c4,0x00000006,0x0000009b,0x00000099,0x0000009a,0x00050041,0x0000001c,0x0000009c, + 0x0000001a,0x00000097,0x0003003e,0x0000009c,0x0000009b,0x0004003d,0x00000006,0x0000009d, + 0x00000094,0x00050039,0x00000002,0x0000009e,0x00000009,0x0000009d,0x000200f9,0x00000083, + 0x000200f8,0x00000083,0x0004003d,0x00000006,0x0000009f,0x00000050,0x000500aa,0x00000013, + 0x000000a0,0x0000009f,0x00000054,0x000300f7,0x000000a2,0x00000000,0x000400fa,0x000000a0, + 0x000000a1,0x000000a2,0x000200f8,0x000000a1,0x00050041,0x0000001c,0x000000a3,0x0000001a, + 0x00000061,0x0004003d,0x00000006,0x000000a4,0x000000a3,0x00050041,0x0000004f,0x000000a5, + 0x0000007e,0x00000044,0x0003003e,0x000000a5,0x000000a4,0x000200f9,0x000000a2,0x000200f8, + 0x000000a2,0x0004003d,0x0000000b,0x000000a6,0x0000007e,0x000200fe,0x000000a6,0x00010038 +}; + +// Generated from: +// +// #version 450 core +// +// #extension GL_EXT_samplerless_texture_functions : require +// +// layout(local_size_x = 64, local_size_y = 1, local_size_z = 1)in; +// +// layout(set = 0, binding = 0, rgba32ui)uniform writeonly uimage2D culledWidgetsOut; +// +// layout(set = 0, binding = 1)uniform WidgetCoordinates +// { +// uvec4 coordinates[32 + 32]; +// }; +// +// shared uint intersectingWidgets[32]; +// +// void accumulateWidgets(const uint localId) +// { +// +// if(localId < 16) +// { +// intersectingWidgets[localId]|= intersectingWidgets[localId + 16]; +// if(localId < 8) +// { +// intersectingWidgets[localId]|= intersectingWidgets[localId + 8]; +// if(localId < 4) +// { +// intersectingWidgets[localId]|= intersectingWidgets[localId + 4]; +// if(localId < 2) +// { +// intersectingWidgets[localId]|= intersectingWidgets[localId + 2]; +// if(localId < 1) +// { +// intersectingWidgets[localId]|= intersectingWidgets[localId + 1]; +// } +// } +// } +// } +// } +// } +// +// uvec2 cullWidgets(const uint offset, const uvec2 blockCoordLow, const uvec2 blockCoordHigh) +// { +// const uint localId = gl_LocalInvocationID . x; +// const uvec4 widgetCoords = coordinates[offset + localId]; +// +// const bool intersects = widgetCoords . x < widgetCoords . z && +// all(lessThan(widgetCoords . xy, blockCoordHigh))&& +// all(greaterThanEqual(widgetCoords . zw, blockCoordLow)); +// +// uvec2 ballot = uvec2(0, 0); +// +// if(localId < 32) +// { +// intersectingWidgets[localId]= uint(intersects)<< localId; +// accumulateWidgets(localId); +// if(localId == 0) +// { +// ballot . x = intersectingWidgets[0]; +// } +// } +// else +// { +// const uint graphLocalId = localId - 32; +// intersectingWidgets[graphLocalId]= uint(intersects)<< graphLocalId; +// accumulateWidgets(graphLocalId); +// } +// if(localId == 0) +// { +// ballot . y = intersectingWidgets[0]; +// } +// +// return ballot; +// +// } +// +// void main() +// { +// +// const uvec2 outCoord = gl_WorkGroupID . xy; +// const uvec2 blockCoordLow = outCoord * uvec2(8, 8); +// const uvec2 blockCoordHigh = blockCoordLow + uvec2(8, 8); +// +// uvec2 culledWidgets; +// +// culledWidgets = cullWidgets(0, blockCoordLow, blockCoordHigh); +// +// if(gl_LocalInvocationID . x == 0) +// { +// imageStore(culledWidgetsOut, ivec2(outCoord), uvec4(culledWidgets, 0, 0)); +// } +// } diff --git a/src/libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000000.inc b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000000.inc new file mode 100644 index 00000000000..591a822a1a1 --- /dev/null +++ b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000000.inc @@ -0,0 +1,526 @@ + // 7.12.3226 + #pragma once +const uint32_t kOverlayDraw_comp_00000000[] = { + 0x07230203,0x00010000,0x00080007,0x000001ba,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x0000009f,0x000000b7,0x00060010, + 0x00000004,0x00000011,0x00000008,0x00000004,0x00000001,0x00030003,0x00000002,0x000001c2, + 0x000b0004,0x455f4c47,0x735f5458,0x6c706d61,0x656c7265,0x745f7373,0x75747865,0x665f6572, + 0x74636e75,0x736e6f69,0x00000000,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00070005, + 0x0000000d,0x65746e69,0x63657372,0x76287374,0x763b3275,0x003b3475,0x00050005,0x0000000b, + 0x67616d69,0x6f6f4365,0x00736472,0x00060005,0x0000000c,0x67646977,0x6f437465,0x7364726f, + 0x00000000,0x00070005,0x00000013,0x43746567,0x28726168,0x763b3175,0x753b3275,0x00003b31, + 0x00050005,0x00000010,0x74786574,0x67646957,0x00007465,0x00060005,0x00000011,0x726f6f63, + 0x576e4964,0x65676469,0x00000074,0x00060005,0x00000012,0x746e6f66,0x70796c47,0x64695768, + 0x00006874,0x00090005,0x0000001b,0x706d6173,0x6f46656c,0x7528746e,0x75763b31,0x75763b32, + 0x31753b32,0x0000003b,0x00050005,0x00000017,0x74786574,0x72616843,0x00000000,0x00060005, + 0x00000018,0x726f6f63,0x576e4964,0x65676469,0x00000074,0x00060005,0x00000019,0x746e6f66, + 0x70796c47,0x7a695368,0x00000065,0x00050005,0x0000001a,0x746e6f66,0x6579614c,0x00000072, + 0x00070005,0x00000020,0x56746567,0x65756c61,0x3b317528,0x3b327576,0x003b3175,0x00050005, + 0x0000001d,0x70617267,0x64695768,0x00746567,0x00060005,0x0000001e,0x726f6f63,0x576e4964, + 0x65676469,0x00000074,0x00050005,0x0000001f,0x756c6176,0x64695765,0x00006874,0x00060005, + 0x00000026,0x6e656c62,0x66762864,0x66763b34,0x00003b34,0x00060005,0x00000024,0x6e656c62, + 0x53646564,0x7261466f,0x00000000,0x00040005,0x00000025,0x6f6c6f63,0x00000072,0x00050005, + 0x00000035,0x72616863,0x65646e49,0x00000078,0x00050005,0x00000039,0x6b636170,0x65646e49, + 0x00000078,0x00050005,0x0000003d,0x6b636170,0x68436465,0x00737261,0x00060005,0x00000040, + 0x74786554,0x67646957,0x61447465,0x00006174,0x00060006,0x00000040,0x00000000,0x726f6f63, + 0x616e6964,0x00736574,0x00050006,0x00000040,0x00000001,0x6f6c6f63,0x00000072,0x00060006, + 0x00000040,0x00000002,0x746e6f66,0x657a6953,0x00000000,0x00050006,0x00000040,0x00000003, + 0x74786574,0x00000000,0x00050005,0x00000043,0x74786554,0x67646957,0x00737465,0x00070006, + 0x00000043,0x00000000,0x74786574,0x67646957,0x44737465,0x00617461,0x00030005,0x00000045, + 0x00000000,0x00040005,0x00000050,0x66696873,0x00000074,0x00060005,0x0000005d,0x726f6f63, + 0x476e4964,0x6870796c,0x00000000,0x00050005,0x0000005f,0x70796c67,0x66664f68,0x00746573, + 0x00040005,0x00000066,0x746e6f66,0x00000000,0x00050005,0x00000076,0x756c6176,0x646e4965, + 0x00007865,0x00060005,0x0000007a,0x70617247,0x64695768,0x44746567,0x00617461,0x00060006, + 0x0000007a,0x00000000,0x726f6f63,0x616e6964,0x00736574,0x00050006,0x0000007a,0x00000001, + 0x6f6c6f63,0x00000072,0x00060006,0x0000007a,0x00000002,0x756c6176,0x64695765,0x00006874, + 0x00050006,0x0000007a,0x00000003,0x756c6176,0x00007365,0x00060005,0x0000007c,0x70617247, + 0x64695768,0x73746567,0x00000000,0x00080006,0x0000007c,0x00000000,0x70617267,0x64695768, + 0x73746567,0x61746144,0x00000000,0x00030005,0x0000007e,0x00000000,0x00050005,0x0000009c, + 0x67616d69,0x6f6f4365,0x00736472,0x00080005,0x0000009f,0x475f6c67,0x61626f6c,0x766e496c, + 0x7461636f,0x496e6f69,0x00000044,0x00060005,0x000000a3,0x68737550,0x736e6f43,0x746e6174, + 0x00000073,0x00060006,0x000000a3,0x00000000,0x7074756f,0x69537475,0x0000657a,0x00040005, + 0x000000a5,0x61726170,0x0000736d,0x00060005,0x000000af,0x6e656c62,0x57646564,0x65676469, + 0x00007374,0x00060005,0x000000b2,0x67627573,0x70756f72,0x67646957,0x00737465,0x00060005, + 0x000000b5,0x6c6c7563,0x69576465,0x74656764,0x00000073,0x00060005,0x000000b7,0x575f6c67, + 0x476b726f,0x70756f72,0x00004449,0x00050005,0x000000bd,0x74786574,0x67646957,0x00737465, + 0x00060005,0x000000c0,0x70617267,0x64695768,0x73746567,0x00000000,0x00050005,0x000000cb, + 0x70617267,0x64695768,0x00746567,0x00060005,0x000000d6,0x67646977,0x6f437465,0x7364726f, + 0x00000000,0x00060005,0x00000109,0x726f6f63,0x576e4964,0x65676469,0x00000074,0x00050005, + 0x0000010e,0x756c6176,0x64695765,0x00006874,0x00040005,0x00000113,0x756c6176,0x00000065, + 0x00040005,0x00000118,0x6f6c6f63,0x00000072,0x00060005,0x00000119,0x67646977,0x65487465, + 0x74686769,0x00000000,0x00070005,0x00000120,0x69646e69,0x65746163,0x7265764f,0x776f6c66, + 0x00000000,0x00050005,0x0000014f,0x74786574,0x67646957,0x00007465,0x00060005,0x00000158, + 0x67646977,0x6f437465,0x7364726f,0x00000000,0x00060005,0x00000163,0x726f6f63,0x576e4964, + 0x65676469,0x00000074,0x00060005,0x00000168,0x746e6f66,0x657a6953,0x6b636150,0x00006465, + 0x00060005,0x0000016c,0x746e6f66,0x70796c47,0x7a695368,0x00000065,0x00050005,0x0000016f, + 0x746e6f66,0x6579614c,0x00000072,0x00050005,0x00000172,0x74786574,0x72616843,0x00000000, + 0x00050005,0x0000017e,0x706d6173,0x6156656c,0x0065756c,0x00040005,0x00000184,0x6f6c6f63, + 0x00000072,0x00060005,0x00000197,0x6e656c62,0x43646564,0x726f6c6f,0x00000000,0x00040005, + 0x0000019f,0x6f6c6f63,0x00000072,0x00050005,0x000001a2,0x6e656c62,0x74754f64,0x00747570, + 0x00040047,0x0000003f,0x00000006,0x00000010,0x00050048,0x00000040,0x00000000,0x00000023, + 0x00000000,0x00050048,0x00000040,0x00000001,0x00000023,0x00000010,0x00050048,0x00000040, + 0x00000002,0x00000023,0x00000020,0x00050048,0x00000040,0x00000003,0x00000023,0x00000030, + 0x00040047,0x00000042,0x00000006,0x00000130,0x00050048,0x00000043,0x00000000,0x00000023, + 0x00000000,0x00030047,0x00000043,0x00000002,0x00040047,0x00000045,0x00000022,0x00000000, + 0x00040047,0x00000045,0x00000021,0x00000001,0x00040047,0x00000066,0x00000022,0x00000000, + 0x00040047,0x00000066,0x00000021,0x00000004,0x00040047,0x00000079,0x00000006,0x00000010, + 0x00050048,0x0000007a,0x00000000,0x00000023,0x00000000,0x00050048,0x0000007a,0x00000001, + 0x00000023,0x00000010,0x00050048,0x0000007a,0x00000002,0x00000023,0x00000020,0x00050048, + 0x0000007a,0x00000003,0x00000023,0x00000030,0x00040047,0x0000007b,0x00000006,0x00000130, + 0x00050048,0x0000007c,0x00000000,0x00000023,0x00000000,0x00030047,0x0000007c,0x00000002, + 0x00040047,0x0000007e,0x00000022,0x00000000,0x00040047,0x0000007e,0x00000021,0x00000002, + 0x00040047,0x0000009f,0x0000000b,0x0000001c,0x00050048,0x000000a3,0x00000000,0x00000023, + 0x00000000,0x00030047,0x000000a3,0x00000002,0x00040047,0x000000b5,0x00000022,0x00000000, + 0x00040047,0x000000b5,0x00000021,0x00000003,0x00040047,0x000000b7,0x0000000b,0x0000001a, + 0x00040047,0x000001a2,0x00000022,0x00000000,0x00040047,0x000001a2,0x00000021,0x00000000, + 0x00040047,0x000001b9,0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003, + 0x00000002,0x00040015,0x00000006,0x00000020,0x00000000,0x00040017,0x00000007,0x00000006, + 0x00000002,0x00040017,0x00000008,0x00000006,0x00000004,0x00020014,0x00000009,0x00050021, + 0x0000000a,0x00000009,0x00000007,0x00000008,0x00060021,0x0000000f,0x00000006,0x00000006, + 0x00000007,0x00000006,0x00030016,0x00000015,0x00000020,0x00070021,0x00000016,0x00000015, + 0x00000006,0x00000007,0x00000007,0x00000006,0x00040017,0x00000022,0x00000015,0x00000004, + 0x00050021,0x00000023,0x00000022,0x00000022,0x00000022,0x00040017,0x00000029,0x00000009, + 0x00000002,0x00040020,0x00000034,0x00000007,0x00000006,0x0004002b,0x00000006,0x00000036, + 0x00000000,0x0004002b,0x00000006,0x0000003b,0x00000004,0x0004002b,0x00000006,0x0000003e, + 0x00000010,0x0004001c,0x0000003f,0x00000008,0x0000003e,0x0006001e,0x00000040,0x00000008, + 0x00000022,0x00000008,0x0000003f,0x0004002b,0x00000006,0x00000041,0x00000020,0x0004001c, + 0x00000042,0x00000040,0x00000041,0x0003001e,0x00000043,0x00000042,0x00040020,0x00000044, + 0x00000002,0x00000043,0x0004003b,0x00000044,0x00000045,0x00000002,0x00040015,0x00000046, + 0x00000020,0x00000001,0x0004002b,0x00000046,0x00000047,0x00000000,0x0004002b,0x00000046, + 0x00000048,0x00000003,0x00040020,0x0000004d,0x00000002,0x00000006,0x0004002b,0x00000006, + 0x00000053,0x00000008,0x0004002b,0x00000006,0x00000058,0x000000ff,0x00040020,0x0000005c, + 0x00000007,0x00000007,0x00090019,0x00000064,0x00000015,0x00000001,0x00000000,0x00000001, + 0x00000000,0x00000001,0x00000000,0x00040020,0x00000065,0x00000000,0x00000064,0x0004003b, + 0x00000065,0x00000066,0x00000000,0x00040017,0x0000006b,0x00000046,0x00000002,0x00040017, + 0x0000006e,0x00000046,0x00000003,0x0004001c,0x00000079,0x00000008,0x0000003e,0x0006001e, + 0x0000007a,0x00000008,0x00000022,0x00000008,0x00000079,0x0004001c,0x0000007b,0x0000007a, + 0x00000041,0x0003001e,0x0000007c,0x0000007b,0x00040020,0x0000007d,0x00000002,0x0000007c, + 0x0004003b,0x0000007d,0x0000007e,0x00000002,0x00040017,0x00000087,0x00000015,0x00000003, + 0x0004002b,0x00000015,0x00000089,0x3f800000,0x0004002b,0x00000006,0x0000008a,0x00000003, + 0x00040017,0x0000009d,0x00000006,0x00000003,0x00040020,0x0000009e,0x00000001,0x0000009d, + 0x0004003b,0x0000009e,0x0000009f,0x00000001,0x0003001e,0x000000a3,0x00000007,0x00040020, + 0x000000a4,0x00000009,0x000000a3,0x0004003b,0x000000a4,0x000000a5,0x00000009,0x00040020, + 0x000000a6,0x00000009,0x00000007,0x00040020,0x000000ae,0x00000007,0x00000022,0x0004002b, + 0x00000015,0x000000b0,0x00000000,0x0007002c,0x00000022,0x000000b1,0x000000b0,0x000000b0, + 0x000000b0,0x00000089,0x00090019,0x000000b3,0x00000006,0x00000001,0x00000000,0x00000000, + 0x00000000,0x00000001,0x00000000,0x00040020,0x000000b4,0x00000000,0x000000b3,0x0004003b, + 0x000000b4,0x000000b5,0x00000000,0x0004003b,0x0000009e,0x000000b7,0x00000001,0x0004002b, + 0x00000006,0x000000c1,0x00000001,0x0004002b,0x00000046,0x000000cf,0x00000001,0x00040020, + 0x000000d5,0x00000007,0x00000008,0x00040020,0x000000d8,0x00000002,0x00000008,0x0004002b, + 0x00000006,0x000000f6,0x00000002,0x0007002c,0x00000022,0x00000107,0x000000b0,0x000000b0, + 0x000000b0,0x000000b0,0x0004002b,0x00000046,0x00000110,0x00000002,0x00040020,0x0000011f, + 0x00000007,0x00000009,0x00040020,0x00000142,0x00000002,0x00000022,0x0004002b,0x00000006, + 0x00000179,0x00000060,0x00040020,0x0000017d,0x00000007,0x00000015,0x0004002b,0x00000015, + 0x00000185,0x3ecccccd,0x0007002c,0x00000022,0x00000186,0x000000b0,0x000000b0,0x000000b0, + 0x00000185,0x00040020,0x00000196,0x00000007,0x00000087,0x00090019,0x000001a0,0x00000015, + 0x00000001,0x00000000,0x00000000,0x00000000,0x00000002,0x00000001,0x00040020,0x000001a1, + 0x00000000,0x000001a0,0x0004003b,0x000001a1,0x000001a2,0x00000000,0x0006002c,0x0000009d, + 0x000001b9,0x00000053,0x0000003b,0x000000c1,0x00050036,0x00000002,0x00000004,0x00000000, + 0x00000003,0x000200f8,0x00000005,0x0004003b,0x0000005c,0x0000009c,0x00000007,0x0004003b, + 0x000000ae,0x000000af,0x00000007,0x0004003b,0x0000005c,0x000000b2,0x00000007,0x0004003b, + 0x00000034,0x000000bd,0x00000007,0x0004003b,0x00000034,0x000000c0,0x00000007,0x0004003b, + 0x00000034,0x000000cb,0x00000007,0x0004003b,0x000000d5,0x000000d6,0x00000007,0x0004003b, + 0x0000005c,0x00000109,0x00000007,0x0004003b,0x00000034,0x0000010e,0x00000007,0x0004003b, + 0x00000034,0x00000113,0x00000007,0x0004003b,0x000000ae,0x00000118,0x00000007,0x0004003b, + 0x00000034,0x00000119,0x00000007,0x0004003b,0x0000011f,0x00000120,0x00000007,0x0004003b, + 0x00000034,0x0000014f,0x00000007,0x0004003b,0x000000d5,0x00000158,0x00000007,0x0004003b, + 0x0000005c,0x00000163,0x00000007,0x0004003b,0x000000d5,0x00000168,0x00000007,0x0004003b, + 0x0000005c,0x0000016c,0x00000007,0x0004003b,0x00000034,0x0000016f,0x00000007,0x0004003b, + 0x00000034,0x00000172,0x00000007,0x0004003b,0x0000017d,0x0000017e,0x00000007,0x0004003b, + 0x000000ae,0x00000184,0x00000007,0x0004003b,0x00000196,0x00000197,0x00000007,0x0004003b, + 0x000000ae,0x0000019f,0x00000007,0x0004003d,0x0000009d,0x000000a0,0x0000009f,0x0007004f, + 0x00000007,0x000000a1,0x000000a0,0x000000a0,0x00000000,0x00000001,0x0003003e,0x0000009c, + 0x000000a1,0x0004003d,0x00000007,0x000000a2,0x0000009c,0x00050041,0x000000a6,0x000000a7, + 0x000000a5,0x00000047,0x0004003d,0x00000007,0x000000a8,0x000000a7,0x000500ae,0x00000029, + 0x000000a9,0x000000a2,0x000000a8,0x0004009a,0x00000009,0x000000aa,0x000000a9,0x000300f7, + 0x000000ac,0x00000000,0x000400fa,0x000000aa,0x000000ab,0x000000ac,0x000200f8,0x000000ab, + 0x000100fd,0x000200f8,0x000000ac,0x0003003e,0x000000af,0x000000b1,0x0004003d,0x000000b3, + 0x000000b6,0x000000b5,0x0004003d,0x0000009d,0x000000b8,0x000000b7,0x0007004f,0x00000007, + 0x000000b9,0x000000b8,0x000000b8,0x00000000,0x00000001,0x0004007c,0x0000006b,0x000000ba, + 0x000000b9,0x0007005f,0x00000008,0x000000bb,0x000000b6,0x000000ba,0x00000002,0x00000047, + 0x0007004f,0x00000007,0x000000bc,0x000000bb,0x000000bb,0x00000000,0x00000001,0x0003003e, + 0x000000b2,0x000000bc,0x00050041,0x00000034,0x000000be,0x000000b2,0x00000036,0x0004003d, + 0x00000006,0x000000bf,0x000000be,0x0003003e,0x000000bd,0x000000bf,0x00050041,0x00000034, + 0x000000c2,0x000000b2,0x000000c1,0x0004003d,0x00000006,0x000000c3,0x000000c2,0x0003003e, + 0x000000c0,0x000000c3,0x000200f9,0x000000c4,0x000200f8,0x000000c4,0x000400f6,0x000000c6, + 0x000000c7,0x00000000,0x000200f9,0x000000c8,0x000200f8,0x000000c8,0x0004003d,0x00000006, + 0x000000c9,0x000000c0,0x000500ab,0x00000009,0x000000ca,0x000000c9,0x00000036,0x000400fa, + 0x000000ca,0x000000c5,0x000000c6,0x000200f8,0x000000c5,0x0004003d,0x00000006,0x000000cc, + 0x000000c0,0x0006000c,0x00000046,0x000000cd,0x00000001,0x00000049,0x000000cc,0x0004007c, + 0x00000006,0x000000ce,0x000000cd,0x0003003e,0x000000cb,0x000000ce,0x0004003d,0x00000006, + 0x000000d0,0x000000cb,0x000500c4,0x00000046,0x000000d1,0x000000cf,0x000000d0,0x0004007c, + 0x00000006,0x000000d2,0x000000d1,0x0004003d,0x00000006,0x000000d3,0x000000c0,0x000500c6, + 0x00000006,0x000000d4,0x000000d3,0x000000d2,0x0003003e,0x000000c0,0x000000d4,0x0004003d, + 0x00000006,0x000000d7,0x000000cb,0x00070041,0x000000d8,0x000000d9,0x0000007e,0x00000047, + 0x000000d7,0x00000047,0x0004003d,0x00000008,0x000000da,0x000000d9,0x0003003e,0x000000d6, + 0x000000da,0x0004003d,0x00000007,0x000000db,0x0000009c,0x0004003d,0x00000008,0x000000dc, + 0x000000d6,0x00060039,0x00000009,0x000000dd,0x0000000d,0x000000db,0x000000dc,0x000400a8, + 0x00000009,0x000000de,0x000000dd,0x000300f7,0x000000e0,0x00000000,0x000400fa,0x000000de, + 0x000000df,0x000000e0,0x000200f8,0x000000df,0x000200f9,0x000000c7,0x000200f8,0x000000e0, + 0x00050041,0x00000034,0x000000e2,0x0000009c,0x00000036,0x0004003d,0x00000006,0x000000e3, + 0x000000e2,0x00050041,0x00000034,0x000000e4,0x000000d6,0x00000036,0x0004003d,0x00000006, + 0x000000e5,0x000000e4,0x000500aa,0x00000009,0x000000e6,0x000000e3,0x000000e5,0x000400a8, + 0x00000009,0x000000e7,0x000000e6,0x000300f7,0x000000e9,0x00000000,0x000400fa,0x000000e7, + 0x000000e8,0x000000e9,0x000200f8,0x000000e8,0x00050041,0x00000034,0x000000ea,0x0000009c, + 0x000000c1,0x0004003d,0x00000006,0x000000eb,0x000000ea,0x00050041,0x00000034,0x000000ec, + 0x000000d6,0x000000c1,0x0004003d,0x00000006,0x000000ed,0x000000ec,0x000500aa,0x00000009, + 0x000000ee,0x000000eb,0x000000ed,0x000200f9,0x000000e9,0x000200f8,0x000000e9,0x000700f5, + 0x00000009,0x000000ef,0x000000e6,0x000000e0,0x000000ee,0x000000e8,0x000400a8,0x00000009, + 0x000000f0,0x000000ef,0x000300f7,0x000000f2,0x00000000,0x000400fa,0x000000f0,0x000000f1, + 0x000000f2,0x000200f8,0x000000f1,0x00050041,0x00000034,0x000000f3,0x0000009c,0x00000036, + 0x0004003d,0x00000006,0x000000f4,0x000000f3,0x00050080,0x00000006,0x000000f5,0x000000f4, + 0x000000c1,0x00050041,0x00000034,0x000000f7,0x000000d6,0x000000f6,0x0004003d,0x00000006, + 0x000000f8,0x000000f7,0x000500aa,0x00000009,0x000000f9,0x000000f5,0x000000f8,0x000200f9, + 0x000000f2,0x000200f8,0x000000f2,0x000700f5,0x00000009,0x000000fa,0x000000ef,0x000000e9, + 0x000000f9,0x000000f1,0x000400a8,0x00000009,0x000000fb,0x000000fa,0x000300f7,0x000000fd, + 0x00000000,0x000400fa,0x000000fb,0x000000fc,0x000000fd,0x000200f8,0x000000fc,0x00050041, + 0x00000034,0x000000fe,0x0000009c,0x000000c1,0x0004003d,0x00000006,0x000000ff,0x000000fe, + 0x00050080,0x00000006,0x00000100,0x000000ff,0x000000c1,0x00050041,0x00000034,0x00000101, + 0x000000d6,0x0000008a,0x0004003d,0x00000006,0x00000102,0x00000101,0x000500aa,0x00000009, + 0x00000103,0x00000100,0x00000102,0x000200f9,0x000000fd,0x000200f8,0x000000fd,0x000700f5, + 0x00000009,0x00000104,0x000000fa,0x000000f2,0x00000103,0x000000fc,0x000300f7,0x00000106, + 0x00000000,0x000400fa,0x00000104,0x00000105,0x00000106,0x000200f8,0x00000105,0x0003003e, + 0x000000af,0x00000107,0x000200f9,0x000000c7,0x000200f8,0x00000106,0x0004003d,0x00000007, + 0x0000010a,0x0000009c,0x0004003d,0x00000008,0x0000010b,0x000000d6,0x0007004f,0x00000007, + 0x0000010c,0x0000010b,0x0000010b,0x00000000,0x00000001,0x00050082,0x00000007,0x0000010d, + 0x0000010a,0x0000010c,0x0003003e,0x00000109,0x0000010d,0x0004003d,0x00000006,0x0000010f, + 0x000000cb,0x00080041,0x0000004d,0x00000111,0x0000007e,0x00000047,0x0000010f,0x00000110, + 0x00000036,0x0004003d,0x00000006,0x00000112,0x00000111,0x0003003e,0x0000010e,0x00000112, + 0x0004003d,0x00000006,0x00000114,0x000000cb,0x0004003d,0x00000007,0x00000115,0x00000109, + 0x0004003d,0x00000006,0x00000116,0x0000010e,0x00070039,0x00000006,0x00000117,0x00000020, + 0x00000114,0x00000115,0x00000116,0x0003003e,0x00000113,0x00000117,0x0003003e,0x00000118, + 0x00000107,0x00050041,0x00000034,0x0000011a,0x000000d6,0x0000008a,0x0004003d,0x00000006, + 0x0000011b,0x0000011a,0x00050041,0x00000034,0x0000011c,0x000000d6,0x000000c1,0x0004003d, + 0x00000006,0x0000011d,0x0000011c,0x00050082,0x00000006,0x0000011e,0x0000011b,0x0000011d, + 0x0003003e,0x00000119,0x0000011e,0x0004003d,0x00000006,0x00000121,0x00000113,0x0004003d, + 0x00000006,0x00000122,0x00000119,0x000500ac,0x00000009,0x00000123,0x00000121,0x00000122, + 0x000300f7,0x00000125,0x00000000,0x000400fa,0x00000123,0x00000124,0x00000125,0x000200f8, + 0x00000124,0x00050041,0x00000034,0x00000126,0x00000109,0x000000c1,0x0004003d,0x00000006, + 0x00000127,0x00000126,0x00050080,0x00000006,0x00000128,0x00000127,0x0000003b,0x0004003d, + 0x00000006,0x00000129,0x00000119,0x000500ae,0x00000009,0x0000012a,0x00000128,0x00000129, + 0x000200f9,0x00000125,0x000200f8,0x00000125,0x000700f5,0x00000009,0x0000012b,0x00000123, + 0x00000106,0x0000012a,0x00000124,0x000300f7,0x0000012d,0x00000000,0x000400fa,0x0000012b, + 0x0000012c,0x0000012d,0x000200f8,0x0000012c,0x00050041,0x00000034,0x0000012e,0x00000109, + 0x00000036,0x0004003d,0x00000006,0x0000012f,0x0000012e,0x00050041,0x00000034,0x00000130, + 0x00000109,0x000000c1,0x0004003d,0x00000006,0x00000131,0x00000130,0x000500c6,0x00000006, + 0x00000132,0x0000012f,0x00000131,0x000500c7,0x00000006,0x00000133,0x00000132,0x000000c1, + 0x000500aa,0x00000009,0x00000134,0x00000133,0x00000036,0x000200f9,0x0000012d,0x000200f8, + 0x0000012d,0x000700f5,0x00000009,0x00000135,0x0000012b,0x00000125,0x00000134,0x0000012c, + 0x0003003e,0x00000120,0x00000135,0x0004003d,0x00000006,0x00000136,0x00000119,0x00050041, + 0x00000034,0x00000137,0x00000109,0x000000c1,0x0004003d,0x00000006,0x00000138,0x00000137, + 0x00050082,0x00000006,0x00000139,0x00000136,0x00000138,0x0004003d,0x00000006,0x0000013a, + 0x00000113,0x000500b0,0x00000009,0x0000013b,0x00000139,0x0000013a,0x0004003d,0x00000009, + 0x0000013c,0x00000120,0x000400a8,0x00000009,0x0000013d,0x0000013c,0x000500a7,0x00000009, + 0x0000013e,0x0000013b,0x0000013d,0x000300f7,0x00000140,0x00000000,0x000400fa,0x0000013e, + 0x0000013f,0x00000140,0x000200f8,0x0000013f,0x0004003d,0x00000006,0x00000141,0x000000cb, + 0x00070041,0x00000142,0x00000143,0x0000007e,0x00000047,0x00000141,0x000000cf,0x0004003d, + 0x00000022,0x00000144,0x00000143,0x0003003e,0x00000118,0x00000144,0x0004003d,0x00000022, + 0x00000145,0x000000af,0x0004003d,0x00000022,0x00000146,0x00000118,0x00060039,0x00000022, + 0x00000147,0x00000026,0x00000145,0x00000146,0x0003003e,0x000000af,0x00000147,0x000200f9, + 0x00000140,0x000200f8,0x00000140,0x000200f9,0x000000c7,0x000200f8,0x000000c7,0x000200f9, + 0x000000c4,0x000200f8,0x000000c6,0x000200f9,0x00000148,0x000200f8,0x00000148,0x000400f6, + 0x0000014a,0x0000014b,0x00000000,0x000200f9,0x0000014c,0x000200f8,0x0000014c,0x0004003d, + 0x00000006,0x0000014d,0x000000bd,0x000500ab,0x00000009,0x0000014e,0x0000014d,0x00000036, + 0x000400fa,0x0000014e,0x00000149,0x0000014a,0x000200f8,0x00000149,0x0004003d,0x00000006, + 0x00000150,0x000000bd,0x0006000c,0x00000046,0x00000151,0x00000001,0x00000049,0x00000150, + 0x0004007c,0x00000006,0x00000152,0x00000151,0x0003003e,0x0000014f,0x00000152,0x0004003d, + 0x00000006,0x00000153,0x0000014f,0x000500c4,0x00000046,0x00000154,0x000000cf,0x00000153, + 0x0004007c,0x00000006,0x00000155,0x00000154,0x0004003d,0x00000006,0x00000156,0x000000bd, + 0x000500c6,0x00000006,0x00000157,0x00000156,0x00000155,0x0003003e,0x000000bd,0x00000157, + 0x0004003d,0x00000006,0x00000159,0x0000014f,0x00070041,0x000000d8,0x0000015a,0x00000045, + 0x00000047,0x00000159,0x00000047,0x0004003d,0x00000008,0x0000015b,0x0000015a,0x0003003e, + 0x00000158,0x0000015b,0x0004003d,0x00000007,0x0000015c,0x0000009c,0x0004003d,0x00000008, + 0x0000015d,0x00000158,0x00060039,0x00000009,0x0000015e,0x0000000d,0x0000015c,0x0000015d, + 0x000400a8,0x00000009,0x0000015f,0x0000015e,0x000300f7,0x00000161,0x00000000,0x000400fa, + 0x0000015f,0x00000160,0x00000161,0x000200f8,0x00000160,0x000200f9,0x0000014b,0x000200f8, + 0x00000161,0x0004003d,0x00000007,0x00000164,0x0000009c,0x0004003d,0x00000008,0x00000165, + 0x00000158,0x0007004f,0x00000007,0x00000166,0x00000165,0x00000165,0x00000000,0x00000001, + 0x00050082,0x00000007,0x00000167,0x00000164,0x00000166,0x0003003e,0x00000163,0x00000167, + 0x0004003d,0x00000006,0x00000169,0x0000014f,0x00070041,0x000000d8,0x0000016a,0x00000045, + 0x00000047,0x00000169,0x00000110,0x0004003d,0x00000008,0x0000016b,0x0000016a,0x0003003e, + 0x00000168,0x0000016b,0x0004003d,0x00000008,0x0000016d,0x00000168,0x0007004f,0x00000007, + 0x0000016e,0x0000016d,0x0000016d,0x00000000,0x00000001,0x0003003e,0x0000016c,0x0000016e, + 0x00050041,0x00000034,0x00000170,0x00000168,0x000000f6,0x0004003d,0x00000006,0x00000171, + 0x00000170,0x0003003e,0x0000016f,0x00000171,0x0004003d,0x00000006,0x00000173,0x0000014f, + 0x0004003d,0x00000007,0x00000174,0x00000163,0x00050041,0x00000034,0x00000175,0x0000016c, + 0x00000036,0x0004003d,0x00000006,0x00000176,0x00000175,0x00070039,0x00000006,0x00000177, + 0x00000013,0x00000173,0x00000174,0x00000176,0x0003003e,0x00000172,0x00000177,0x0004003d, + 0x00000006,0x00000178,0x00000172,0x000500b0,0x00000009,0x0000017a,0x00000178,0x00000179, + 0x000300f7,0x0000017c,0x00000000,0x000400fa,0x0000017a,0x0000017b,0x0000017c,0x000200f8, + 0x0000017b,0x0004003d,0x00000006,0x0000017f,0x00000172,0x0004003d,0x00000007,0x00000180, + 0x00000163,0x0004003d,0x00000007,0x00000181,0x0000016c,0x0004003d,0x00000006,0x00000182, + 0x0000016f,0x00080039,0x00000015,0x00000183,0x0000001b,0x0000017f,0x00000180,0x00000181, + 0x00000182,0x0003003e,0x0000017e,0x00000183,0x0003003e,0x00000184,0x00000186,0x0004003d, + 0x00000022,0x00000187,0x00000184,0x0004003d,0x00000006,0x00000188,0x0000014f,0x00070041, + 0x00000142,0x00000189,0x00000045,0x00000047,0x00000188,0x000000cf,0x0004003d,0x00000022, + 0x0000018a,0x00000189,0x0004003d,0x00000015,0x0000018b,0x0000017e,0x00070050,0x00000022, + 0x0000018c,0x0000018b,0x0000018b,0x0000018b,0x0000018b,0x0008000c,0x00000022,0x0000018d, + 0x00000001,0x0000002e,0x00000187,0x0000018a,0x0000018c,0x0003003e,0x00000184,0x0000018d, + 0x0004003d,0x00000022,0x0000018e,0x000000af,0x0004003d,0x00000022,0x0000018f,0x00000184, + 0x00060039,0x00000022,0x00000190,0x00000026,0x0000018e,0x0000018f,0x0003003e,0x000000af, + 0x00000190,0x000200f9,0x0000017c,0x000200f8,0x0000017c,0x000200f9,0x0000014b,0x000200f8, + 0x0000014b,0x000200f9,0x00000148,0x000200f8,0x0000014a,0x00050041,0x0000017d,0x00000191, + 0x000000af,0x0000008a,0x0004003d,0x00000015,0x00000192,0x00000191,0x000500b8,0x00000009, + 0x00000193,0x00000192,0x00000089,0x000300f7,0x00000195,0x00000000,0x000400fa,0x00000193, + 0x00000194,0x00000195,0x000200f8,0x00000194,0x0004003d,0x00000022,0x00000198,0x000000af, + 0x0008004f,0x00000087,0x00000199,0x00000198,0x00000198,0x00000000,0x00000001,0x00000002, + 0x0003003e,0x00000197,0x00000199,0x00050041,0x0000017d,0x0000019a,0x000000af,0x0000008a, + 0x0004003d,0x00000015,0x0000019b,0x0000019a,0x000500ba,0x00000009,0x0000019c,0x0000019b, + 0x000000b0,0x000300f7,0x0000019e,0x00000000,0x000400fa,0x0000019c,0x0000019d,0x0000019e, + 0x000200f8,0x0000019d,0x0004003d,0x000001a0,0x000001a3,0x000001a2,0x0004003d,0x00000007, + 0x000001a4,0x0000009c,0x0004007c,0x0000006b,0x000001a5,0x000001a4,0x00050062,0x00000022, + 0x000001a6,0x000001a3,0x000001a5,0x0003003e,0x0000019f,0x000001a6,0x0004003d,0x00000022, + 0x000001a7,0x0000019f,0x0008004f,0x00000087,0x000001a8,0x000001a7,0x000001a7,0x00000000, + 0x00000001,0x00000002,0x00050041,0x0000017d,0x000001a9,0x0000019f,0x0000008a,0x0004003d, + 0x00000015,0x000001aa,0x000001a9,0x0005008e,0x00000087,0x000001ab,0x000001a8,0x000001aa, + 0x00050041,0x0000017d,0x000001ac,0x000000af,0x0000008a,0x0004003d,0x00000015,0x000001ad, + 0x000001ac,0x0005008e,0x00000087,0x000001ae,0x000001ab,0x000001ad,0x0004003d,0x00000087, + 0x000001af,0x00000197,0x00050081,0x00000087,0x000001b0,0x000001af,0x000001ae,0x0003003e, + 0x00000197,0x000001b0,0x000200f9,0x0000019e,0x000200f8,0x0000019e,0x0004003d,0x000001a0, + 0x000001b1,0x000001a2,0x0004003d,0x00000007,0x000001b2,0x0000009c,0x0004007c,0x0000006b, + 0x000001b3,0x000001b2,0x0004003d,0x00000087,0x000001b4,0x00000197,0x00050051,0x00000015, + 0x000001b5,0x000001b4,0x00000000,0x00050051,0x00000015,0x000001b6,0x000001b4,0x00000001, + 0x00050051,0x00000015,0x000001b7,0x000001b4,0x00000002,0x00070050,0x00000022,0x000001b8, + 0x000001b5,0x000001b6,0x000001b7,0x00000089,0x00040063,0x000001b1,0x000001b3,0x000001b8, + 0x000200f9,0x00000195,0x000200f8,0x00000195,0x000100fd,0x00010038,0x00050036,0x00000009, + 0x0000000d,0x00000000,0x0000000a,0x00030037,0x00000007,0x0000000b,0x00030037,0x00000008, + 0x0000000c,0x000200f8,0x0000000e,0x0007004f,0x00000007,0x00000028,0x0000000c,0x0000000c, + 0x00000000,0x00000001,0x000500ae,0x00000029,0x0000002a,0x0000000b,0x00000028,0x0004009b, + 0x00000009,0x0000002b,0x0000002a,0x000300f7,0x0000002d,0x00000000,0x000400fa,0x0000002b, + 0x0000002c,0x0000002d,0x000200f8,0x0000002c,0x0007004f,0x00000007,0x0000002e,0x0000000c, + 0x0000000c,0x00000002,0x00000003,0x000500b0,0x00000029,0x0000002f,0x0000000b,0x0000002e, + 0x0004009b,0x00000009,0x00000030,0x0000002f,0x000200f9,0x0000002d,0x000200f8,0x0000002d, + 0x000700f5,0x00000009,0x00000031,0x0000002b,0x0000000e,0x00000030,0x0000002c,0x000200fe, + 0x00000031,0x00010038,0x00050036,0x00000006,0x00000013,0x00000000,0x0000000f,0x00030037, + 0x00000006,0x00000010,0x00030037,0x00000007,0x00000011,0x00030037,0x00000006,0x00000012, + 0x000200f8,0x00000014,0x0004003b,0x00000034,0x00000035,0x00000007,0x0004003b,0x00000034, + 0x00000039,0x00000007,0x0004003b,0x00000034,0x0000003d,0x00000007,0x0004003b,0x00000034, + 0x00000050,0x00000007,0x00050051,0x00000006,0x00000037,0x00000011,0x00000000,0x00050086, + 0x00000006,0x00000038,0x00000037,0x00000012,0x0003003e,0x00000035,0x00000038,0x0004003d, + 0x00000006,0x0000003a,0x00000035,0x00050086,0x00000006,0x0000003c,0x0000003a,0x0000003b, + 0x0003003e,0x00000039,0x0000003c,0x0004003d,0x00000006,0x00000049,0x00000039,0x00050086, + 0x00000006,0x0000004a,0x00000049,0x0000003b,0x0004003d,0x00000006,0x0000004b,0x00000039, + 0x00050089,0x00000006,0x0000004c,0x0000004b,0x0000003b,0x00090041,0x0000004d,0x0000004e, + 0x00000045,0x00000047,0x00000010,0x00000048,0x0000004a,0x0000004c,0x0004003d,0x00000006, + 0x0000004f,0x0000004e,0x0003003e,0x0000003d,0x0000004f,0x0004003d,0x00000006,0x00000051, + 0x00000035,0x00050089,0x00000006,0x00000052,0x00000051,0x0000003b,0x00050084,0x00000006, + 0x00000054,0x00000052,0x00000053,0x0003003e,0x00000050,0x00000054,0x0004003d,0x00000006, + 0x00000055,0x0000003d,0x0004003d,0x00000006,0x00000056,0x00000050,0x000500c2,0x00000006, + 0x00000057,0x00000055,0x00000056,0x000500c7,0x00000006,0x00000059,0x00000057,0x00000058, + 0x000200fe,0x00000059,0x00010038,0x00050036,0x00000015,0x0000001b,0x00000000,0x00000016, + 0x00030037,0x00000006,0x00000017,0x00030037,0x00000007,0x00000018,0x00030037,0x00000007, + 0x00000019,0x00030037,0x00000006,0x0000001a,0x000200f8,0x0000001c,0x0004003b,0x0000005c, + 0x0000005d,0x00000007,0x0004003b,0x0000005c,0x0000005f,0x00000007,0x00050089,0x00000007, + 0x0000005e,0x00000018,0x00000019,0x0003003e,0x0000005d,0x0000005e,0x00050089,0x00000006, + 0x00000060,0x00000017,0x00000041,0x00050086,0x00000006,0x00000061,0x00000017,0x00000041, + 0x00050050,0x00000007,0x00000062,0x00000060,0x00000061,0x00050084,0x00000007,0x00000063, + 0x00000019,0x00000062,0x0003003e,0x0000005f,0x00000063,0x0004003d,0x00000064,0x00000067, + 0x00000066,0x0004003d,0x00000007,0x00000068,0x0000005f,0x0004003d,0x00000007,0x00000069, + 0x0000005d,0x00050080,0x00000007,0x0000006a,0x00000068,0x00000069,0x0004007c,0x0000006b, + 0x0000006c,0x0000006a,0x0004007c,0x00000046,0x0000006d,0x0000001a,0x00050051,0x00000046, + 0x0000006f,0x0000006c,0x00000000,0x00050051,0x00000046,0x00000070,0x0000006c,0x00000001, + 0x00060050,0x0000006e,0x00000071,0x0000006f,0x00000070,0x0000006d,0x0007005f,0x00000022, + 0x00000072,0x00000067,0x00000071,0x00000002,0x00000047,0x00050051,0x00000015,0x00000073, + 0x00000072,0x00000000,0x000200fe,0x00000073,0x00010038,0x00050036,0x00000006,0x00000020, + 0x00000000,0x0000000f,0x00030037,0x00000006,0x0000001d,0x00030037,0x00000007,0x0000001e, + 0x00030037,0x00000006,0x0000001f,0x000200f8,0x00000021,0x0004003b,0x00000034,0x00000076, + 0x00000007,0x00050051,0x00000006,0x00000077,0x0000001e,0x00000000,0x00050086,0x00000006, + 0x00000078,0x00000077,0x0000001f,0x0003003e,0x00000076,0x00000078,0x0004003d,0x00000006, + 0x0000007f,0x00000076,0x00050086,0x00000006,0x00000080,0x0000007f,0x0000003b,0x0004003d, + 0x00000006,0x00000081,0x00000076,0x00050089,0x00000006,0x00000082,0x00000081,0x0000003b, + 0x00090041,0x0000004d,0x00000083,0x0000007e,0x00000047,0x0000001d,0x00000048,0x00000080, + 0x00000082,0x0004003d,0x00000006,0x00000084,0x00000083,0x000200fe,0x00000084,0x00010038, + 0x00050036,0x00000022,0x00000026,0x00000000,0x00000023,0x00030037,0x00000022,0x00000024, + 0x00030037,0x00000022,0x00000025,0x000200f8,0x00000027,0x0008004f,0x00000087,0x00000088, + 0x00000024,0x00000024,0x00000000,0x00000001,0x00000002,0x00050051,0x00000015,0x0000008b, + 0x00000025,0x00000003,0x00050083,0x00000015,0x0000008c,0x00000089,0x0000008b,0x0005008e, + 0x00000087,0x0000008d,0x00000088,0x0000008c,0x0008004f,0x00000087,0x0000008e,0x00000025, + 0x00000025,0x00000000,0x00000001,0x00000002,0x00050051,0x00000015,0x0000008f,0x00000025, + 0x00000003,0x0005008e,0x00000087,0x00000090,0x0000008e,0x0000008f,0x00050081,0x00000087, + 0x00000091,0x0000008d,0x00000090,0x00050051,0x00000015,0x00000092,0x00000024,0x00000003, + 0x00050051,0x00000015,0x00000093,0x00000025,0x00000003,0x00050083,0x00000015,0x00000094, + 0x00000089,0x00000093,0x00050085,0x00000015,0x00000095,0x00000092,0x00000094,0x00050051, + 0x00000015,0x00000096,0x00000091,0x00000000,0x00050051,0x00000015,0x00000097,0x00000091, + 0x00000001,0x00050051,0x00000015,0x00000098,0x00000091,0x00000002,0x00070050,0x00000022, + 0x00000099,0x00000096,0x00000097,0x00000098,0x00000095,0x000200fe,0x00000099,0x00010038 +}; + +// Generated from: +// +// #version 450 core +// +// #extension GL_EXT_samplerless_texture_functions : require +// +// layout(local_size_x = 8, local_size_y = 4, local_size_z = 1)in; +// +// struct TextWidgetData +// { +// uvec4 coordinates; +// vec4 color; +// uvec4 fontSize; +// uvec4 text[256 / 16]; +// }; +// +// struct GraphWidgetData +// { +// uvec4 coordinates; +// vec4 color; +// uvec4 valueWidth; +// uvec4 values[64 / 4]; +// }; +// +// layout(set = 0, binding = 0, rgba32f)uniform image2D blendOutput; +// +// layout(set = 0, binding = 1)uniform TextWidgets +// { +// TextWidgetData textWidgetsData[32]; +// }; +// +// layout(set = 0, binding = 2)uniform GraphWidgets +// { +// GraphWidgetData graphWidgetsData[32]; +// }; +// +// layout(set = 0, binding = 3)uniform utexture2D culledWidgets; +// layout(set = 0, binding = 4)uniform texture2DArray font; +// +// layout(push_constant)uniform PushConstants +// { +// uvec2 outputSize; +// } params; +// +// bool intersects(const uvec2 imageCoords, const uvec4 widgetCoords) +// { +// return all(greaterThanEqual(imageCoords, widgetCoords . xy))&& +// all(lessThan(imageCoords, widgetCoords . zw)); +// } +// +// uint getChar(const uint textWidget, const uvec2 coordInWidget, const uint fontGlyphWidth) +// { +// const uint charIndex = coordInWidget . x / fontGlyphWidth; +// const uint packIndex = charIndex / 4; +// const uint packedChars = textWidgetsData[textWidget]. text[packIndex / 4][packIndex % 4]; +// const uint shift =(charIndex % 4)* 8; +// +// return(packedChars >> shift)& 0xFF; +// +// } +// +// float sampleFont(const uint textChar, +// const uvec2 coordInWidget, +// const uvec2 fontGlyphSize, +// const uint fontLayer) +// { +// const uvec2 coordInGlyph = coordInWidget % fontGlyphSize; +// const uvec2 glyphOffset = fontGlyphSize * +// uvec2(textChar % 32, textChar / 32); +// +// return texelFetch(font, ivec3(glyphOffset + coordInGlyph, fontLayer), 0). x; +// } +// +// uint getValue(const uint graphWidget, const uvec2 coordInWidget, const uint valueWidth) +// { +// const uint valueIndex = coordInWidget . x / valueWidth . x; +// return graphWidgetsData[graphWidget]. values[valueIndex / 4][valueIndex % 4]; +// } +// +// vec4 blend(const vec4 blendedSoFar, const vec4 color) +// { +// +// return vec4(blendedSoFar . rgb *(1 - color . a)+ color . rgb * color . a, +// blendedSoFar . a *(1 - color . a)); +// } +// +// void main() +// { +// const uvec2 imageCoords = gl_GlobalInvocationID . xy; +// if(any(greaterThanEqual(imageCoords, params . outputSize))) +// { +// return; +// } +// +// vec4 blendedWidgets = vec4(0, 0, 0, 1); +// +// const uvec2 subgroupWidgets = texelFetch(culledWidgets, ivec2(gl_WorkGroupID . xy), 0). xy; +// uint textWidgets = subgroupWidgets . x; +// uint graphWidgets = subgroupWidgets . y; +// +// while(graphWidgets != 0) +// { +// const uint graphWidget = findLSB(graphWidgets); +// graphWidgets ^= 1 << graphWidget; +// +// const uvec4 widgetCoords = graphWidgetsData[graphWidget]. coordinates; +// if(! intersects(imageCoords, widgetCoords)) +// { +// continue; +// } +// +// if(imageCoords . x == widgetCoords . x || imageCoords . y == widgetCoords . y || +// imageCoords . x + 1 == widgetCoords . z || imageCoords . y + 1 == widgetCoords . w) +// { +// +// blendedWidgets = vec4(0); +// continue; +// } +// +// const uvec2 coordInWidget = imageCoords - widgetCoords . xy; +// const uint valueWidth = graphWidgetsData[graphWidget]. valueWidth . x; +// +// const uint value = getValue(graphWidget, coordInWidget, valueWidth); +// +// vec4 color = vec4(0); +// const uint widgetHeight = widgetCoords . w - widgetCoords . y; +// +// bool indicateOverflow = value > widgetHeight && coordInWidget . y + 4 >= widgetHeight +// &&((coordInWidget . x ^ coordInWidget . y)& 1)== 0; +// +// if((widgetHeight - coordInWidget . y)< value && ! indicateOverflow) +// { +// color = graphWidgetsData[graphWidget]. color; +// blendedWidgets = blend(blendedWidgets, color); +// } +// } +// +// while(textWidgets != 0) +// { +// const uint textWidget = findLSB(textWidgets); +// textWidgets ^= 1 << textWidget; +// +// const uvec4 widgetCoords = textWidgetsData[textWidget]. coordinates; +// if(! intersects(imageCoords, widgetCoords)) +// { +// continue; +// } +// +// const uvec2 coordInWidget = imageCoords - widgetCoords . xy; +// const uvec4 fontSizePacked = textWidgetsData[textWidget]. fontSize; +// const uvec2 fontGlyphSize = fontSizePacked . xy; +// const uint fontLayer = fontSizePacked . z; +// +// const uint textChar = getChar(textWidget, coordInWidget, fontGlyphSize . x); +// +// if(textChar <(32 * 3)) +// { +// +// const float sampleValue = sampleFont(textChar, coordInWidget, fontGlyphSize, fontLayer); +// +// vec4 color = vec4(0, 0, 0, 0.4); +// color = mix(color, textWidgetsData[textWidget]. color, sampleValue); +// +// blendedWidgets = blend(blendedWidgets, color); +// } +// } +// +// if(blendedWidgets . a < 1) +// { +// vec3 blendedColor = blendedWidgets . rgb; +// if(blendedWidgets . a > 0) +// { +// const vec4 color = imageLoad(blendOutput, ivec2(imageCoords)); +// blendedColor += color . rgb * color . a * blendedWidgets . a; +// } +// imageStore(blendOutput, ivec2(imageCoords), vec4(blendedColor, 1)); +// } +// } diff --git a/src/libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000001.inc b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000001.inc new file mode 100644 index 00000000000..989db78f9c1 --- /dev/null +++ b/src/libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000001.inc @@ -0,0 +1,526 @@ + // 7.12.3226 + #pragma once +const uint32_t kOverlayDraw_comp_00000001[] = { + 0x07230203,0x00010000,0x00080007,0x000001ba,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x0000009f,0x000000b7,0x00060010, + 0x00000004,0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000002,0x000001c2, + 0x000b0004,0x455f4c47,0x735f5458,0x6c706d61,0x656c7265,0x745f7373,0x75747865,0x665f6572, + 0x74636e75,0x736e6f69,0x00000000,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00070005, + 0x0000000d,0x65746e69,0x63657372,0x76287374,0x763b3275,0x003b3475,0x00050005,0x0000000b, + 0x67616d69,0x6f6f4365,0x00736472,0x00060005,0x0000000c,0x67646977,0x6f437465,0x7364726f, + 0x00000000,0x00070005,0x00000013,0x43746567,0x28726168,0x763b3175,0x753b3275,0x00003b31, + 0x00050005,0x00000010,0x74786574,0x67646957,0x00007465,0x00060005,0x00000011,0x726f6f63, + 0x576e4964,0x65676469,0x00000074,0x00060005,0x00000012,0x746e6f66,0x70796c47,0x64695768, + 0x00006874,0x00090005,0x0000001b,0x706d6173,0x6f46656c,0x7528746e,0x75763b31,0x75763b32, + 0x31753b32,0x0000003b,0x00050005,0x00000017,0x74786574,0x72616843,0x00000000,0x00060005, + 0x00000018,0x726f6f63,0x576e4964,0x65676469,0x00000074,0x00060005,0x00000019,0x746e6f66, + 0x70796c47,0x7a695368,0x00000065,0x00050005,0x0000001a,0x746e6f66,0x6579614c,0x00000072, + 0x00070005,0x00000020,0x56746567,0x65756c61,0x3b317528,0x3b327576,0x003b3175,0x00050005, + 0x0000001d,0x70617267,0x64695768,0x00746567,0x00060005,0x0000001e,0x726f6f63,0x576e4964, + 0x65676469,0x00000074,0x00050005,0x0000001f,0x756c6176,0x64695765,0x00006874,0x00060005, + 0x00000026,0x6e656c62,0x66762864,0x66763b34,0x00003b34,0x00060005,0x00000024,0x6e656c62, + 0x53646564,0x7261466f,0x00000000,0x00040005,0x00000025,0x6f6c6f63,0x00000072,0x00050005, + 0x00000035,0x72616863,0x65646e49,0x00000078,0x00050005,0x00000039,0x6b636170,0x65646e49, + 0x00000078,0x00050005,0x0000003d,0x6b636170,0x68436465,0x00737261,0x00060005,0x00000040, + 0x74786554,0x67646957,0x61447465,0x00006174,0x00060006,0x00000040,0x00000000,0x726f6f63, + 0x616e6964,0x00736574,0x00050006,0x00000040,0x00000001,0x6f6c6f63,0x00000072,0x00060006, + 0x00000040,0x00000002,0x746e6f66,0x657a6953,0x00000000,0x00050006,0x00000040,0x00000003, + 0x74786574,0x00000000,0x00050005,0x00000043,0x74786554,0x67646957,0x00737465,0x00070006, + 0x00000043,0x00000000,0x74786574,0x67646957,0x44737465,0x00617461,0x00030005,0x00000045, + 0x00000000,0x00040005,0x00000050,0x66696873,0x00000074,0x00060005,0x0000005d,0x726f6f63, + 0x476e4964,0x6870796c,0x00000000,0x00050005,0x0000005f,0x70796c67,0x66664f68,0x00746573, + 0x00040005,0x00000066,0x746e6f66,0x00000000,0x00050005,0x00000076,0x756c6176,0x646e4965, + 0x00007865,0x00060005,0x0000007a,0x70617247,0x64695768,0x44746567,0x00617461,0x00060006, + 0x0000007a,0x00000000,0x726f6f63,0x616e6964,0x00736574,0x00050006,0x0000007a,0x00000001, + 0x6f6c6f63,0x00000072,0x00060006,0x0000007a,0x00000002,0x756c6176,0x64695765,0x00006874, + 0x00050006,0x0000007a,0x00000003,0x756c6176,0x00007365,0x00060005,0x0000007c,0x70617247, + 0x64695768,0x73746567,0x00000000,0x00080006,0x0000007c,0x00000000,0x70617267,0x64695768, + 0x73746567,0x61746144,0x00000000,0x00030005,0x0000007e,0x00000000,0x00050005,0x0000009c, + 0x67616d69,0x6f6f4365,0x00736472,0x00080005,0x0000009f,0x475f6c67,0x61626f6c,0x766e496c, + 0x7461636f,0x496e6f69,0x00000044,0x00060005,0x000000a3,0x68737550,0x736e6f43,0x746e6174, + 0x00000073,0x00060006,0x000000a3,0x00000000,0x7074756f,0x69537475,0x0000657a,0x00040005, + 0x000000a5,0x61726170,0x0000736d,0x00060005,0x000000af,0x6e656c62,0x57646564,0x65676469, + 0x00007374,0x00060005,0x000000b2,0x67627573,0x70756f72,0x67646957,0x00737465,0x00060005, + 0x000000b5,0x6c6c7563,0x69576465,0x74656764,0x00000073,0x00060005,0x000000b7,0x575f6c67, + 0x476b726f,0x70756f72,0x00004449,0x00050005,0x000000bd,0x74786574,0x67646957,0x00737465, + 0x00060005,0x000000c0,0x70617267,0x64695768,0x73746567,0x00000000,0x00050005,0x000000cb, + 0x70617267,0x64695768,0x00746567,0x00060005,0x000000d6,0x67646977,0x6f437465,0x7364726f, + 0x00000000,0x00060005,0x00000109,0x726f6f63,0x576e4964,0x65676469,0x00000074,0x00050005, + 0x0000010e,0x756c6176,0x64695765,0x00006874,0x00040005,0x00000113,0x756c6176,0x00000065, + 0x00040005,0x00000118,0x6f6c6f63,0x00000072,0x00060005,0x00000119,0x67646977,0x65487465, + 0x74686769,0x00000000,0x00070005,0x00000120,0x69646e69,0x65746163,0x7265764f,0x776f6c66, + 0x00000000,0x00050005,0x0000014f,0x74786574,0x67646957,0x00007465,0x00060005,0x00000158, + 0x67646977,0x6f437465,0x7364726f,0x00000000,0x00060005,0x00000163,0x726f6f63,0x576e4964, + 0x65676469,0x00000074,0x00060005,0x00000168,0x746e6f66,0x657a6953,0x6b636150,0x00006465, + 0x00060005,0x0000016c,0x746e6f66,0x70796c47,0x7a695368,0x00000065,0x00050005,0x0000016f, + 0x746e6f66,0x6579614c,0x00000072,0x00050005,0x00000172,0x74786574,0x72616843,0x00000000, + 0x00050005,0x0000017e,0x706d6173,0x6156656c,0x0065756c,0x00040005,0x00000184,0x6f6c6f63, + 0x00000072,0x00060005,0x00000197,0x6e656c62,0x43646564,0x726f6c6f,0x00000000,0x00040005, + 0x0000019f,0x6f6c6f63,0x00000072,0x00050005,0x000001a2,0x6e656c62,0x74754f64,0x00747570, + 0x00040047,0x0000003f,0x00000006,0x00000010,0x00050048,0x00000040,0x00000000,0x00000023, + 0x00000000,0x00050048,0x00000040,0x00000001,0x00000023,0x00000010,0x00050048,0x00000040, + 0x00000002,0x00000023,0x00000020,0x00050048,0x00000040,0x00000003,0x00000023,0x00000030, + 0x00040047,0x00000042,0x00000006,0x00000130,0x00050048,0x00000043,0x00000000,0x00000023, + 0x00000000,0x00030047,0x00000043,0x00000002,0x00040047,0x00000045,0x00000022,0x00000000, + 0x00040047,0x00000045,0x00000021,0x00000001,0x00040047,0x00000066,0x00000022,0x00000000, + 0x00040047,0x00000066,0x00000021,0x00000004,0x00040047,0x00000079,0x00000006,0x00000010, + 0x00050048,0x0000007a,0x00000000,0x00000023,0x00000000,0x00050048,0x0000007a,0x00000001, + 0x00000023,0x00000010,0x00050048,0x0000007a,0x00000002,0x00000023,0x00000020,0x00050048, + 0x0000007a,0x00000003,0x00000023,0x00000030,0x00040047,0x0000007b,0x00000006,0x00000130, + 0x00050048,0x0000007c,0x00000000,0x00000023,0x00000000,0x00030047,0x0000007c,0x00000002, + 0x00040047,0x0000007e,0x00000022,0x00000000,0x00040047,0x0000007e,0x00000021,0x00000002, + 0x00040047,0x0000009f,0x0000000b,0x0000001c,0x00050048,0x000000a3,0x00000000,0x00000023, + 0x00000000,0x00030047,0x000000a3,0x00000002,0x00040047,0x000000b5,0x00000022,0x00000000, + 0x00040047,0x000000b5,0x00000021,0x00000003,0x00040047,0x000000b7,0x0000000b,0x0000001a, + 0x00040047,0x000001a2,0x00000022,0x00000000,0x00040047,0x000001a2,0x00000021,0x00000000, + 0x00040047,0x000001b9,0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003, + 0x00000002,0x00040015,0x00000006,0x00000020,0x00000000,0x00040017,0x00000007,0x00000006, + 0x00000002,0x00040017,0x00000008,0x00000006,0x00000004,0x00020014,0x00000009,0x00050021, + 0x0000000a,0x00000009,0x00000007,0x00000008,0x00060021,0x0000000f,0x00000006,0x00000006, + 0x00000007,0x00000006,0x00030016,0x00000015,0x00000020,0x00070021,0x00000016,0x00000015, + 0x00000006,0x00000007,0x00000007,0x00000006,0x00040017,0x00000022,0x00000015,0x00000004, + 0x00050021,0x00000023,0x00000022,0x00000022,0x00000022,0x00040017,0x00000029,0x00000009, + 0x00000002,0x00040020,0x00000034,0x00000007,0x00000006,0x0004002b,0x00000006,0x00000036, + 0x00000000,0x0004002b,0x00000006,0x0000003b,0x00000004,0x0004002b,0x00000006,0x0000003e, + 0x00000010,0x0004001c,0x0000003f,0x00000008,0x0000003e,0x0006001e,0x00000040,0x00000008, + 0x00000022,0x00000008,0x0000003f,0x0004002b,0x00000006,0x00000041,0x00000020,0x0004001c, + 0x00000042,0x00000040,0x00000041,0x0003001e,0x00000043,0x00000042,0x00040020,0x00000044, + 0x00000002,0x00000043,0x0004003b,0x00000044,0x00000045,0x00000002,0x00040015,0x00000046, + 0x00000020,0x00000001,0x0004002b,0x00000046,0x00000047,0x00000000,0x0004002b,0x00000046, + 0x00000048,0x00000003,0x00040020,0x0000004d,0x00000002,0x00000006,0x0004002b,0x00000006, + 0x00000053,0x00000008,0x0004002b,0x00000006,0x00000058,0x000000ff,0x00040020,0x0000005c, + 0x00000007,0x00000007,0x00090019,0x00000064,0x00000015,0x00000001,0x00000000,0x00000001, + 0x00000000,0x00000001,0x00000000,0x00040020,0x00000065,0x00000000,0x00000064,0x0004003b, + 0x00000065,0x00000066,0x00000000,0x00040017,0x0000006b,0x00000046,0x00000002,0x00040017, + 0x0000006e,0x00000046,0x00000003,0x0004001c,0x00000079,0x00000008,0x0000003e,0x0006001e, + 0x0000007a,0x00000008,0x00000022,0x00000008,0x00000079,0x0004001c,0x0000007b,0x0000007a, + 0x00000041,0x0003001e,0x0000007c,0x0000007b,0x00040020,0x0000007d,0x00000002,0x0000007c, + 0x0004003b,0x0000007d,0x0000007e,0x00000002,0x00040017,0x00000087,0x00000015,0x00000003, + 0x0004002b,0x00000015,0x00000089,0x3f800000,0x0004002b,0x00000006,0x0000008a,0x00000003, + 0x00040017,0x0000009d,0x00000006,0x00000003,0x00040020,0x0000009e,0x00000001,0x0000009d, + 0x0004003b,0x0000009e,0x0000009f,0x00000001,0x0003001e,0x000000a3,0x00000007,0x00040020, + 0x000000a4,0x00000009,0x000000a3,0x0004003b,0x000000a4,0x000000a5,0x00000009,0x00040020, + 0x000000a6,0x00000009,0x00000007,0x00040020,0x000000ae,0x00000007,0x00000022,0x0004002b, + 0x00000015,0x000000b0,0x00000000,0x0007002c,0x00000022,0x000000b1,0x000000b0,0x000000b0, + 0x000000b0,0x00000089,0x00090019,0x000000b3,0x00000006,0x00000001,0x00000000,0x00000000, + 0x00000000,0x00000001,0x00000000,0x00040020,0x000000b4,0x00000000,0x000000b3,0x0004003b, + 0x000000b4,0x000000b5,0x00000000,0x0004003b,0x0000009e,0x000000b7,0x00000001,0x0004002b, + 0x00000006,0x000000c1,0x00000001,0x0004002b,0x00000046,0x000000cf,0x00000001,0x00040020, + 0x000000d5,0x00000007,0x00000008,0x00040020,0x000000d8,0x00000002,0x00000008,0x0004002b, + 0x00000006,0x000000f6,0x00000002,0x0007002c,0x00000022,0x00000107,0x000000b0,0x000000b0, + 0x000000b0,0x000000b0,0x0004002b,0x00000046,0x00000110,0x00000002,0x00040020,0x0000011f, + 0x00000007,0x00000009,0x00040020,0x00000142,0x00000002,0x00000022,0x0004002b,0x00000006, + 0x00000179,0x00000060,0x00040020,0x0000017d,0x00000007,0x00000015,0x0004002b,0x00000015, + 0x00000185,0x3ecccccd,0x0007002c,0x00000022,0x00000186,0x000000b0,0x000000b0,0x000000b0, + 0x00000185,0x00040020,0x00000196,0x00000007,0x00000087,0x00090019,0x000001a0,0x00000015, + 0x00000001,0x00000000,0x00000000,0x00000000,0x00000002,0x00000001,0x00040020,0x000001a1, + 0x00000000,0x000001a0,0x0004003b,0x000001a1,0x000001a2,0x00000000,0x0006002c,0x0000009d, + 0x000001b9,0x00000053,0x00000053,0x000000c1,0x00050036,0x00000002,0x00000004,0x00000000, + 0x00000003,0x000200f8,0x00000005,0x0004003b,0x0000005c,0x0000009c,0x00000007,0x0004003b, + 0x000000ae,0x000000af,0x00000007,0x0004003b,0x0000005c,0x000000b2,0x00000007,0x0004003b, + 0x00000034,0x000000bd,0x00000007,0x0004003b,0x00000034,0x000000c0,0x00000007,0x0004003b, + 0x00000034,0x000000cb,0x00000007,0x0004003b,0x000000d5,0x000000d6,0x00000007,0x0004003b, + 0x0000005c,0x00000109,0x00000007,0x0004003b,0x00000034,0x0000010e,0x00000007,0x0004003b, + 0x00000034,0x00000113,0x00000007,0x0004003b,0x000000ae,0x00000118,0x00000007,0x0004003b, + 0x00000034,0x00000119,0x00000007,0x0004003b,0x0000011f,0x00000120,0x00000007,0x0004003b, + 0x00000034,0x0000014f,0x00000007,0x0004003b,0x000000d5,0x00000158,0x00000007,0x0004003b, + 0x0000005c,0x00000163,0x00000007,0x0004003b,0x000000d5,0x00000168,0x00000007,0x0004003b, + 0x0000005c,0x0000016c,0x00000007,0x0004003b,0x00000034,0x0000016f,0x00000007,0x0004003b, + 0x00000034,0x00000172,0x00000007,0x0004003b,0x0000017d,0x0000017e,0x00000007,0x0004003b, + 0x000000ae,0x00000184,0x00000007,0x0004003b,0x00000196,0x00000197,0x00000007,0x0004003b, + 0x000000ae,0x0000019f,0x00000007,0x0004003d,0x0000009d,0x000000a0,0x0000009f,0x0007004f, + 0x00000007,0x000000a1,0x000000a0,0x000000a0,0x00000000,0x00000001,0x0003003e,0x0000009c, + 0x000000a1,0x0004003d,0x00000007,0x000000a2,0x0000009c,0x00050041,0x000000a6,0x000000a7, + 0x000000a5,0x00000047,0x0004003d,0x00000007,0x000000a8,0x000000a7,0x000500ae,0x00000029, + 0x000000a9,0x000000a2,0x000000a8,0x0004009a,0x00000009,0x000000aa,0x000000a9,0x000300f7, + 0x000000ac,0x00000000,0x000400fa,0x000000aa,0x000000ab,0x000000ac,0x000200f8,0x000000ab, + 0x000100fd,0x000200f8,0x000000ac,0x0003003e,0x000000af,0x000000b1,0x0004003d,0x000000b3, + 0x000000b6,0x000000b5,0x0004003d,0x0000009d,0x000000b8,0x000000b7,0x0007004f,0x00000007, + 0x000000b9,0x000000b8,0x000000b8,0x00000000,0x00000001,0x0004007c,0x0000006b,0x000000ba, + 0x000000b9,0x0007005f,0x00000008,0x000000bb,0x000000b6,0x000000ba,0x00000002,0x00000047, + 0x0007004f,0x00000007,0x000000bc,0x000000bb,0x000000bb,0x00000000,0x00000001,0x0003003e, + 0x000000b2,0x000000bc,0x00050041,0x00000034,0x000000be,0x000000b2,0x00000036,0x0004003d, + 0x00000006,0x000000bf,0x000000be,0x0003003e,0x000000bd,0x000000bf,0x00050041,0x00000034, + 0x000000c2,0x000000b2,0x000000c1,0x0004003d,0x00000006,0x000000c3,0x000000c2,0x0003003e, + 0x000000c0,0x000000c3,0x000200f9,0x000000c4,0x000200f8,0x000000c4,0x000400f6,0x000000c6, + 0x000000c7,0x00000000,0x000200f9,0x000000c8,0x000200f8,0x000000c8,0x0004003d,0x00000006, + 0x000000c9,0x000000c0,0x000500ab,0x00000009,0x000000ca,0x000000c9,0x00000036,0x000400fa, + 0x000000ca,0x000000c5,0x000000c6,0x000200f8,0x000000c5,0x0004003d,0x00000006,0x000000cc, + 0x000000c0,0x0006000c,0x00000046,0x000000cd,0x00000001,0x00000049,0x000000cc,0x0004007c, + 0x00000006,0x000000ce,0x000000cd,0x0003003e,0x000000cb,0x000000ce,0x0004003d,0x00000006, + 0x000000d0,0x000000cb,0x000500c4,0x00000046,0x000000d1,0x000000cf,0x000000d0,0x0004007c, + 0x00000006,0x000000d2,0x000000d1,0x0004003d,0x00000006,0x000000d3,0x000000c0,0x000500c6, + 0x00000006,0x000000d4,0x000000d3,0x000000d2,0x0003003e,0x000000c0,0x000000d4,0x0004003d, + 0x00000006,0x000000d7,0x000000cb,0x00070041,0x000000d8,0x000000d9,0x0000007e,0x00000047, + 0x000000d7,0x00000047,0x0004003d,0x00000008,0x000000da,0x000000d9,0x0003003e,0x000000d6, + 0x000000da,0x0004003d,0x00000007,0x000000db,0x0000009c,0x0004003d,0x00000008,0x000000dc, + 0x000000d6,0x00060039,0x00000009,0x000000dd,0x0000000d,0x000000db,0x000000dc,0x000400a8, + 0x00000009,0x000000de,0x000000dd,0x000300f7,0x000000e0,0x00000000,0x000400fa,0x000000de, + 0x000000df,0x000000e0,0x000200f8,0x000000df,0x000200f9,0x000000c7,0x000200f8,0x000000e0, + 0x00050041,0x00000034,0x000000e2,0x0000009c,0x00000036,0x0004003d,0x00000006,0x000000e3, + 0x000000e2,0x00050041,0x00000034,0x000000e4,0x000000d6,0x00000036,0x0004003d,0x00000006, + 0x000000e5,0x000000e4,0x000500aa,0x00000009,0x000000e6,0x000000e3,0x000000e5,0x000400a8, + 0x00000009,0x000000e7,0x000000e6,0x000300f7,0x000000e9,0x00000000,0x000400fa,0x000000e7, + 0x000000e8,0x000000e9,0x000200f8,0x000000e8,0x00050041,0x00000034,0x000000ea,0x0000009c, + 0x000000c1,0x0004003d,0x00000006,0x000000eb,0x000000ea,0x00050041,0x00000034,0x000000ec, + 0x000000d6,0x000000c1,0x0004003d,0x00000006,0x000000ed,0x000000ec,0x000500aa,0x00000009, + 0x000000ee,0x000000eb,0x000000ed,0x000200f9,0x000000e9,0x000200f8,0x000000e9,0x000700f5, + 0x00000009,0x000000ef,0x000000e6,0x000000e0,0x000000ee,0x000000e8,0x000400a8,0x00000009, + 0x000000f0,0x000000ef,0x000300f7,0x000000f2,0x00000000,0x000400fa,0x000000f0,0x000000f1, + 0x000000f2,0x000200f8,0x000000f1,0x00050041,0x00000034,0x000000f3,0x0000009c,0x00000036, + 0x0004003d,0x00000006,0x000000f4,0x000000f3,0x00050080,0x00000006,0x000000f5,0x000000f4, + 0x000000c1,0x00050041,0x00000034,0x000000f7,0x000000d6,0x000000f6,0x0004003d,0x00000006, + 0x000000f8,0x000000f7,0x000500aa,0x00000009,0x000000f9,0x000000f5,0x000000f8,0x000200f9, + 0x000000f2,0x000200f8,0x000000f2,0x000700f5,0x00000009,0x000000fa,0x000000ef,0x000000e9, + 0x000000f9,0x000000f1,0x000400a8,0x00000009,0x000000fb,0x000000fa,0x000300f7,0x000000fd, + 0x00000000,0x000400fa,0x000000fb,0x000000fc,0x000000fd,0x000200f8,0x000000fc,0x00050041, + 0x00000034,0x000000fe,0x0000009c,0x000000c1,0x0004003d,0x00000006,0x000000ff,0x000000fe, + 0x00050080,0x00000006,0x00000100,0x000000ff,0x000000c1,0x00050041,0x00000034,0x00000101, + 0x000000d6,0x0000008a,0x0004003d,0x00000006,0x00000102,0x00000101,0x000500aa,0x00000009, + 0x00000103,0x00000100,0x00000102,0x000200f9,0x000000fd,0x000200f8,0x000000fd,0x000700f5, + 0x00000009,0x00000104,0x000000fa,0x000000f2,0x00000103,0x000000fc,0x000300f7,0x00000106, + 0x00000000,0x000400fa,0x00000104,0x00000105,0x00000106,0x000200f8,0x00000105,0x0003003e, + 0x000000af,0x00000107,0x000200f9,0x000000c7,0x000200f8,0x00000106,0x0004003d,0x00000007, + 0x0000010a,0x0000009c,0x0004003d,0x00000008,0x0000010b,0x000000d6,0x0007004f,0x00000007, + 0x0000010c,0x0000010b,0x0000010b,0x00000000,0x00000001,0x00050082,0x00000007,0x0000010d, + 0x0000010a,0x0000010c,0x0003003e,0x00000109,0x0000010d,0x0004003d,0x00000006,0x0000010f, + 0x000000cb,0x00080041,0x0000004d,0x00000111,0x0000007e,0x00000047,0x0000010f,0x00000110, + 0x00000036,0x0004003d,0x00000006,0x00000112,0x00000111,0x0003003e,0x0000010e,0x00000112, + 0x0004003d,0x00000006,0x00000114,0x000000cb,0x0004003d,0x00000007,0x00000115,0x00000109, + 0x0004003d,0x00000006,0x00000116,0x0000010e,0x00070039,0x00000006,0x00000117,0x00000020, + 0x00000114,0x00000115,0x00000116,0x0003003e,0x00000113,0x00000117,0x0003003e,0x00000118, + 0x00000107,0x00050041,0x00000034,0x0000011a,0x000000d6,0x0000008a,0x0004003d,0x00000006, + 0x0000011b,0x0000011a,0x00050041,0x00000034,0x0000011c,0x000000d6,0x000000c1,0x0004003d, + 0x00000006,0x0000011d,0x0000011c,0x00050082,0x00000006,0x0000011e,0x0000011b,0x0000011d, + 0x0003003e,0x00000119,0x0000011e,0x0004003d,0x00000006,0x00000121,0x00000113,0x0004003d, + 0x00000006,0x00000122,0x00000119,0x000500ac,0x00000009,0x00000123,0x00000121,0x00000122, + 0x000300f7,0x00000125,0x00000000,0x000400fa,0x00000123,0x00000124,0x00000125,0x000200f8, + 0x00000124,0x00050041,0x00000034,0x00000126,0x00000109,0x000000c1,0x0004003d,0x00000006, + 0x00000127,0x00000126,0x00050080,0x00000006,0x00000128,0x00000127,0x0000003b,0x0004003d, + 0x00000006,0x00000129,0x00000119,0x000500ae,0x00000009,0x0000012a,0x00000128,0x00000129, + 0x000200f9,0x00000125,0x000200f8,0x00000125,0x000700f5,0x00000009,0x0000012b,0x00000123, + 0x00000106,0x0000012a,0x00000124,0x000300f7,0x0000012d,0x00000000,0x000400fa,0x0000012b, + 0x0000012c,0x0000012d,0x000200f8,0x0000012c,0x00050041,0x00000034,0x0000012e,0x00000109, + 0x00000036,0x0004003d,0x00000006,0x0000012f,0x0000012e,0x00050041,0x00000034,0x00000130, + 0x00000109,0x000000c1,0x0004003d,0x00000006,0x00000131,0x00000130,0x000500c6,0x00000006, + 0x00000132,0x0000012f,0x00000131,0x000500c7,0x00000006,0x00000133,0x00000132,0x000000c1, + 0x000500aa,0x00000009,0x00000134,0x00000133,0x00000036,0x000200f9,0x0000012d,0x000200f8, + 0x0000012d,0x000700f5,0x00000009,0x00000135,0x0000012b,0x00000125,0x00000134,0x0000012c, + 0x0003003e,0x00000120,0x00000135,0x0004003d,0x00000006,0x00000136,0x00000119,0x00050041, + 0x00000034,0x00000137,0x00000109,0x000000c1,0x0004003d,0x00000006,0x00000138,0x00000137, + 0x00050082,0x00000006,0x00000139,0x00000136,0x00000138,0x0004003d,0x00000006,0x0000013a, + 0x00000113,0x000500b0,0x00000009,0x0000013b,0x00000139,0x0000013a,0x0004003d,0x00000009, + 0x0000013c,0x00000120,0x000400a8,0x00000009,0x0000013d,0x0000013c,0x000500a7,0x00000009, + 0x0000013e,0x0000013b,0x0000013d,0x000300f7,0x00000140,0x00000000,0x000400fa,0x0000013e, + 0x0000013f,0x00000140,0x000200f8,0x0000013f,0x0004003d,0x00000006,0x00000141,0x000000cb, + 0x00070041,0x00000142,0x00000143,0x0000007e,0x00000047,0x00000141,0x000000cf,0x0004003d, + 0x00000022,0x00000144,0x00000143,0x0003003e,0x00000118,0x00000144,0x0004003d,0x00000022, + 0x00000145,0x000000af,0x0004003d,0x00000022,0x00000146,0x00000118,0x00060039,0x00000022, + 0x00000147,0x00000026,0x00000145,0x00000146,0x0003003e,0x000000af,0x00000147,0x000200f9, + 0x00000140,0x000200f8,0x00000140,0x000200f9,0x000000c7,0x000200f8,0x000000c7,0x000200f9, + 0x000000c4,0x000200f8,0x000000c6,0x000200f9,0x00000148,0x000200f8,0x00000148,0x000400f6, + 0x0000014a,0x0000014b,0x00000000,0x000200f9,0x0000014c,0x000200f8,0x0000014c,0x0004003d, + 0x00000006,0x0000014d,0x000000bd,0x000500ab,0x00000009,0x0000014e,0x0000014d,0x00000036, + 0x000400fa,0x0000014e,0x00000149,0x0000014a,0x000200f8,0x00000149,0x0004003d,0x00000006, + 0x00000150,0x000000bd,0x0006000c,0x00000046,0x00000151,0x00000001,0x00000049,0x00000150, + 0x0004007c,0x00000006,0x00000152,0x00000151,0x0003003e,0x0000014f,0x00000152,0x0004003d, + 0x00000006,0x00000153,0x0000014f,0x000500c4,0x00000046,0x00000154,0x000000cf,0x00000153, + 0x0004007c,0x00000006,0x00000155,0x00000154,0x0004003d,0x00000006,0x00000156,0x000000bd, + 0x000500c6,0x00000006,0x00000157,0x00000156,0x00000155,0x0003003e,0x000000bd,0x00000157, + 0x0004003d,0x00000006,0x00000159,0x0000014f,0x00070041,0x000000d8,0x0000015a,0x00000045, + 0x00000047,0x00000159,0x00000047,0x0004003d,0x00000008,0x0000015b,0x0000015a,0x0003003e, + 0x00000158,0x0000015b,0x0004003d,0x00000007,0x0000015c,0x0000009c,0x0004003d,0x00000008, + 0x0000015d,0x00000158,0x00060039,0x00000009,0x0000015e,0x0000000d,0x0000015c,0x0000015d, + 0x000400a8,0x00000009,0x0000015f,0x0000015e,0x000300f7,0x00000161,0x00000000,0x000400fa, + 0x0000015f,0x00000160,0x00000161,0x000200f8,0x00000160,0x000200f9,0x0000014b,0x000200f8, + 0x00000161,0x0004003d,0x00000007,0x00000164,0x0000009c,0x0004003d,0x00000008,0x00000165, + 0x00000158,0x0007004f,0x00000007,0x00000166,0x00000165,0x00000165,0x00000000,0x00000001, + 0x00050082,0x00000007,0x00000167,0x00000164,0x00000166,0x0003003e,0x00000163,0x00000167, + 0x0004003d,0x00000006,0x00000169,0x0000014f,0x00070041,0x000000d8,0x0000016a,0x00000045, + 0x00000047,0x00000169,0x00000110,0x0004003d,0x00000008,0x0000016b,0x0000016a,0x0003003e, + 0x00000168,0x0000016b,0x0004003d,0x00000008,0x0000016d,0x00000168,0x0007004f,0x00000007, + 0x0000016e,0x0000016d,0x0000016d,0x00000000,0x00000001,0x0003003e,0x0000016c,0x0000016e, + 0x00050041,0x00000034,0x00000170,0x00000168,0x000000f6,0x0004003d,0x00000006,0x00000171, + 0x00000170,0x0003003e,0x0000016f,0x00000171,0x0004003d,0x00000006,0x00000173,0x0000014f, + 0x0004003d,0x00000007,0x00000174,0x00000163,0x00050041,0x00000034,0x00000175,0x0000016c, + 0x00000036,0x0004003d,0x00000006,0x00000176,0x00000175,0x00070039,0x00000006,0x00000177, + 0x00000013,0x00000173,0x00000174,0x00000176,0x0003003e,0x00000172,0x00000177,0x0004003d, + 0x00000006,0x00000178,0x00000172,0x000500b0,0x00000009,0x0000017a,0x00000178,0x00000179, + 0x000300f7,0x0000017c,0x00000000,0x000400fa,0x0000017a,0x0000017b,0x0000017c,0x000200f8, + 0x0000017b,0x0004003d,0x00000006,0x0000017f,0x00000172,0x0004003d,0x00000007,0x00000180, + 0x00000163,0x0004003d,0x00000007,0x00000181,0x0000016c,0x0004003d,0x00000006,0x00000182, + 0x0000016f,0x00080039,0x00000015,0x00000183,0x0000001b,0x0000017f,0x00000180,0x00000181, + 0x00000182,0x0003003e,0x0000017e,0x00000183,0x0003003e,0x00000184,0x00000186,0x0004003d, + 0x00000022,0x00000187,0x00000184,0x0004003d,0x00000006,0x00000188,0x0000014f,0x00070041, + 0x00000142,0x00000189,0x00000045,0x00000047,0x00000188,0x000000cf,0x0004003d,0x00000022, + 0x0000018a,0x00000189,0x0004003d,0x00000015,0x0000018b,0x0000017e,0x00070050,0x00000022, + 0x0000018c,0x0000018b,0x0000018b,0x0000018b,0x0000018b,0x0008000c,0x00000022,0x0000018d, + 0x00000001,0x0000002e,0x00000187,0x0000018a,0x0000018c,0x0003003e,0x00000184,0x0000018d, + 0x0004003d,0x00000022,0x0000018e,0x000000af,0x0004003d,0x00000022,0x0000018f,0x00000184, + 0x00060039,0x00000022,0x00000190,0x00000026,0x0000018e,0x0000018f,0x0003003e,0x000000af, + 0x00000190,0x000200f9,0x0000017c,0x000200f8,0x0000017c,0x000200f9,0x0000014b,0x000200f8, + 0x0000014b,0x000200f9,0x00000148,0x000200f8,0x0000014a,0x00050041,0x0000017d,0x00000191, + 0x000000af,0x0000008a,0x0004003d,0x00000015,0x00000192,0x00000191,0x000500b8,0x00000009, + 0x00000193,0x00000192,0x00000089,0x000300f7,0x00000195,0x00000000,0x000400fa,0x00000193, + 0x00000194,0x00000195,0x000200f8,0x00000194,0x0004003d,0x00000022,0x00000198,0x000000af, + 0x0008004f,0x00000087,0x00000199,0x00000198,0x00000198,0x00000000,0x00000001,0x00000002, + 0x0003003e,0x00000197,0x00000199,0x00050041,0x0000017d,0x0000019a,0x000000af,0x0000008a, + 0x0004003d,0x00000015,0x0000019b,0x0000019a,0x000500ba,0x00000009,0x0000019c,0x0000019b, + 0x000000b0,0x000300f7,0x0000019e,0x00000000,0x000400fa,0x0000019c,0x0000019d,0x0000019e, + 0x000200f8,0x0000019d,0x0004003d,0x000001a0,0x000001a3,0x000001a2,0x0004003d,0x00000007, + 0x000001a4,0x0000009c,0x0004007c,0x0000006b,0x000001a5,0x000001a4,0x00050062,0x00000022, + 0x000001a6,0x000001a3,0x000001a5,0x0003003e,0x0000019f,0x000001a6,0x0004003d,0x00000022, + 0x000001a7,0x0000019f,0x0008004f,0x00000087,0x000001a8,0x000001a7,0x000001a7,0x00000000, + 0x00000001,0x00000002,0x00050041,0x0000017d,0x000001a9,0x0000019f,0x0000008a,0x0004003d, + 0x00000015,0x000001aa,0x000001a9,0x0005008e,0x00000087,0x000001ab,0x000001a8,0x000001aa, + 0x00050041,0x0000017d,0x000001ac,0x000000af,0x0000008a,0x0004003d,0x00000015,0x000001ad, + 0x000001ac,0x0005008e,0x00000087,0x000001ae,0x000001ab,0x000001ad,0x0004003d,0x00000087, + 0x000001af,0x00000197,0x00050081,0x00000087,0x000001b0,0x000001af,0x000001ae,0x0003003e, + 0x00000197,0x000001b0,0x000200f9,0x0000019e,0x000200f8,0x0000019e,0x0004003d,0x000001a0, + 0x000001b1,0x000001a2,0x0004003d,0x00000007,0x000001b2,0x0000009c,0x0004007c,0x0000006b, + 0x000001b3,0x000001b2,0x0004003d,0x00000087,0x000001b4,0x00000197,0x00050051,0x00000015, + 0x000001b5,0x000001b4,0x00000000,0x00050051,0x00000015,0x000001b6,0x000001b4,0x00000001, + 0x00050051,0x00000015,0x000001b7,0x000001b4,0x00000002,0x00070050,0x00000022,0x000001b8, + 0x000001b5,0x000001b6,0x000001b7,0x00000089,0x00040063,0x000001b1,0x000001b3,0x000001b8, + 0x000200f9,0x00000195,0x000200f8,0x00000195,0x000100fd,0x00010038,0x00050036,0x00000009, + 0x0000000d,0x00000000,0x0000000a,0x00030037,0x00000007,0x0000000b,0x00030037,0x00000008, + 0x0000000c,0x000200f8,0x0000000e,0x0007004f,0x00000007,0x00000028,0x0000000c,0x0000000c, + 0x00000000,0x00000001,0x000500ae,0x00000029,0x0000002a,0x0000000b,0x00000028,0x0004009b, + 0x00000009,0x0000002b,0x0000002a,0x000300f7,0x0000002d,0x00000000,0x000400fa,0x0000002b, + 0x0000002c,0x0000002d,0x000200f8,0x0000002c,0x0007004f,0x00000007,0x0000002e,0x0000000c, + 0x0000000c,0x00000002,0x00000003,0x000500b0,0x00000029,0x0000002f,0x0000000b,0x0000002e, + 0x0004009b,0x00000009,0x00000030,0x0000002f,0x000200f9,0x0000002d,0x000200f8,0x0000002d, + 0x000700f5,0x00000009,0x00000031,0x0000002b,0x0000000e,0x00000030,0x0000002c,0x000200fe, + 0x00000031,0x00010038,0x00050036,0x00000006,0x00000013,0x00000000,0x0000000f,0x00030037, + 0x00000006,0x00000010,0x00030037,0x00000007,0x00000011,0x00030037,0x00000006,0x00000012, + 0x000200f8,0x00000014,0x0004003b,0x00000034,0x00000035,0x00000007,0x0004003b,0x00000034, + 0x00000039,0x00000007,0x0004003b,0x00000034,0x0000003d,0x00000007,0x0004003b,0x00000034, + 0x00000050,0x00000007,0x00050051,0x00000006,0x00000037,0x00000011,0x00000000,0x00050086, + 0x00000006,0x00000038,0x00000037,0x00000012,0x0003003e,0x00000035,0x00000038,0x0004003d, + 0x00000006,0x0000003a,0x00000035,0x00050086,0x00000006,0x0000003c,0x0000003a,0x0000003b, + 0x0003003e,0x00000039,0x0000003c,0x0004003d,0x00000006,0x00000049,0x00000039,0x00050086, + 0x00000006,0x0000004a,0x00000049,0x0000003b,0x0004003d,0x00000006,0x0000004b,0x00000039, + 0x00050089,0x00000006,0x0000004c,0x0000004b,0x0000003b,0x00090041,0x0000004d,0x0000004e, + 0x00000045,0x00000047,0x00000010,0x00000048,0x0000004a,0x0000004c,0x0004003d,0x00000006, + 0x0000004f,0x0000004e,0x0003003e,0x0000003d,0x0000004f,0x0004003d,0x00000006,0x00000051, + 0x00000035,0x00050089,0x00000006,0x00000052,0x00000051,0x0000003b,0x00050084,0x00000006, + 0x00000054,0x00000052,0x00000053,0x0003003e,0x00000050,0x00000054,0x0004003d,0x00000006, + 0x00000055,0x0000003d,0x0004003d,0x00000006,0x00000056,0x00000050,0x000500c2,0x00000006, + 0x00000057,0x00000055,0x00000056,0x000500c7,0x00000006,0x00000059,0x00000057,0x00000058, + 0x000200fe,0x00000059,0x00010038,0x00050036,0x00000015,0x0000001b,0x00000000,0x00000016, + 0x00030037,0x00000006,0x00000017,0x00030037,0x00000007,0x00000018,0x00030037,0x00000007, + 0x00000019,0x00030037,0x00000006,0x0000001a,0x000200f8,0x0000001c,0x0004003b,0x0000005c, + 0x0000005d,0x00000007,0x0004003b,0x0000005c,0x0000005f,0x00000007,0x00050089,0x00000007, + 0x0000005e,0x00000018,0x00000019,0x0003003e,0x0000005d,0x0000005e,0x00050089,0x00000006, + 0x00000060,0x00000017,0x00000041,0x00050086,0x00000006,0x00000061,0x00000017,0x00000041, + 0x00050050,0x00000007,0x00000062,0x00000060,0x00000061,0x00050084,0x00000007,0x00000063, + 0x00000019,0x00000062,0x0003003e,0x0000005f,0x00000063,0x0004003d,0x00000064,0x00000067, + 0x00000066,0x0004003d,0x00000007,0x00000068,0x0000005f,0x0004003d,0x00000007,0x00000069, + 0x0000005d,0x00050080,0x00000007,0x0000006a,0x00000068,0x00000069,0x0004007c,0x0000006b, + 0x0000006c,0x0000006a,0x0004007c,0x00000046,0x0000006d,0x0000001a,0x00050051,0x00000046, + 0x0000006f,0x0000006c,0x00000000,0x00050051,0x00000046,0x00000070,0x0000006c,0x00000001, + 0x00060050,0x0000006e,0x00000071,0x0000006f,0x00000070,0x0000006d,0x0007005f,0x00000022, + 0x00000072,0x00000067,0x00000071,0x00000002,0x00000047,0x00050051,0x00000015,0x00000073, + 0x00000072,0x00000000,0x000200fe,0x00000073,0x00010038,0x00050036,0x00000006,0x00000020, + 0x00000000,0x0000000f,0x00030037,0x00000006,0x0000001d,0x00030037,0x00000007,0x0000001e, + 0x00030037,0x00000006,0x0000001f,0x000200f8,0x00000021,0x0004003b,0x00000034,0x00000076, + 0x00000007,0x00050051,0x00000006,0x00000077,0x0000001e,0x00000000,0x00050086,0x00000006, + 0x00000078,0x00000077,0x0000001f,0x0003003e,0x00000076,0x00000078,0x0004003d,0x00000006, + 0x0000007f,0x00000076,0x00050086,0x00000006,0x00000080,0x0000007f,0x0000003b,0x0004003d, + 0x00000006,0x00000081,0x00000076,0x00050089,0x00000006,0x00000082,0x00000081,0x0000003b, + 0x00090041,0x0000004d,0x00000083,0x0000007e,0x00000047,0x0000001d,0x00000048,0x00000080, + 0x00000082,0x0004003d,0x00000006,0x00000084,0x00000083,0x000200fe,0x00000084,0x00010038, + 0x00050036,0x00000022,0x00000026,0x00000000,0x00000023,0x00030037,0x00000022,0x00000024, + 0x00030037,0x00000022,0x00000025,0x000200f8,0x00000027,0x0008004f,0x00000087,0x00000088, + 0x00000024,0x00000024,0x00000000,0x00000001,0x00000002,0x00050051,0x00000015,0x0000008b, + 0x00000025,0x00000003,0x00050083,0x00000015,0x0000008c,0x00000089,0x0000008b,0x0005008e, + 0x00000087,0x0000008d,0x00000088,0x0000008c,0x0008004f,0x00000087,0x0000008e,0x00000025, + 0x00000025,0x00000000,0x00000001,0x00000002,0x00050051,0x00000015,0x0000008f,0x00000025, + 0x00000003,0x0005008e,0x00000087,0x00000090,0x0000008e,0x0000008f,0x00050081,0x00000087, + 0x00000091,0x0000008d,0x00000090,0x00050051,0x00000015,0x00000092,0x00000024,0x00000003, + 0x00050051,0x00000015,0x00000093,0x00000025,0x00000003,0x00050083,0x00000015,0x00000094, + 0x00000089,0x00000093,0x00050085,0x00000015,0x00000095,0x00000092,0x00000094,0x00050051, + 0x00000015,0x00000096,0x00000091,0x00000000,0x00050051,0x00000015,0x00000097,0x00000091, + 0x00000001,0x00050051,0x00000015,0x00000098,0x00000091,0x00000002,0x00070050,0x00000022, + 0x00000099,0x00000096,0x00000097,0x00000098,0x00000095,0x000200fe,0x00000099,0x00010038 +}; + +// Generated from: +// +// #version 450 core +// +// #extension GL_EXT_samplerless_texture_functions : require +// +// layout(local_size_x = 8, local_size_y = 8, local_size_z = 1)in; +// +// struct TextWidgetData +// { +// uvec4 coordinates; +// vec4 color; +// uvec4 fontSize; +// uvec4 text[256 / 16]; +// }; +// +// struct GraphWidgetData +// { +// uvec4 coordinates; +// vec4 color; +// uvec4 valueWidth; +// uvec4 values[64 / 4]; +// }; +// +// layout(set = 0, binding = 0, rgba32f)uniform image2D blendOutput; +// +// layout(set = 0, binding = 1)uniform TextWidgets +// { +// TextWidgetData textWidgetsData[32]; +// }; +// +// layout(set = 0, binding = 2)uniform GraphWidgets +// { +// GraphWidgetData graphWidgetsData[32]; +// }; +// +// layout(set = 0, binding = 3)uniform utexture2D culledWidgets; +// layout(set = 0, binding = 4)uniform texture2DArray font; +// +// layout(push_constant)uniform PushConstants +// { +// uvec2 outputSize; +// } params; +// +// bool intersects(const uvec2 imageCoords, const uvec4 widgetCoords) +// { +// return all(greaterThanEqual(imageCoords, widgetCoords . xy))&& +// all(lessThan(imageCoords, widgetCoords . zw)); +// } +// +// uint getChar(const uint textWidget, const uvec2 coordInWidget, const uint fontGlyphWidth) +// { +// const uint charIndex = coordInWidget . x / fontGlyphWidth; +// const uint packIndex = charIndex / 4; +// const uint packedChars = textWidgetsData[textWidget]. text[packIndex / 4][packIndex % 4]; +// const uint shift =(charIndex % 4)* 8; +// +// return(packedChars >> shift)& 0xFF; +// +// } +// +// float sampleFont(const uint textChar, +// const uvec2 coordInWidget, +// const uvec2 fontGlyphSize, +// const uint fontLayer) +// { +// const uvec2 coordInGlyph = coordInWidget % fontGlyphSize; +// const uvec2 glyphOffset = fontGlyphSize * +// uvec2(textChar % 32, textChar / 32); +// +// return texelFetch(font, ivec3(glyphOffset + coordInGlyph, fontLayer), 0). x; +// } +// +// uint getValue(const uint graphWidget, const uvec2 coordInWidget, const uint valueWidth) +// { +// const uint valueIndex = coordInWidget . x / valueWidth . x; +// return graphWidgetsData[graphWidget]. values[valueIndex / 4][valueIndex % 4]; +// } +// +// vec4 blend(const vec4 blendedSoFar, const vec4 color) +// { +// +// return vec4(blendedSoFar . rgb *(1 - color . a)+ color . rgb * color . a, +// blendedSoFar . a *(1 - color . a)); +// } +// +// void main() +// { +// const uvec2 imageCoords = gl_GlobalInvocationID . xy; +// if(any(greaterThanEqual(imageCoords, params . outputSize))) +// { +// return; +// } +// +// vec4 blendedWidgets = vec4(0, 0, 0, 1); +// +// const uvec2 subgroupWidgets = texelFetch(culledWidgets, ivec2(gl_WorkGroupID . xy), 0). xy; +// uint textWidgets = subgroupWidgets . x; +// uint graphWidgets = subgroupWidgets . y; +// +// while(graphWidgets != 0) +// { +// const uint graphWidget = findLSB(graphWidgets); +// graphWidgets ^= 1 << graphWidget; +// +// const uvec4 widgetCoords = graphWidgetsData[graphWidget]. coordinates; +// if(! intersects(imageCoords, widgetCoords)) +// { +// continue; +// } +// +// if(imageCoords . x == widgetCoords . x || imageCoords . y == widgetCoords . y || +// imageCoords . x + 1 == widgetCoords . z || imageCoords . y + 1 == widgetCoords . w) +// { +// +// blendedWidgets = vec4(0); +// continue; +// } +// +// const uvec2 coordInWidget = imageCoords - widgetCoords . xy; +// const uint valueWidth = graphWidgetsData[graphWidget]. valueWidth . x; +// +// const uint value = getValue(graphWidget, coordInWidget, valueWidth); +// +// vec4 color = vec4(0); +// const uint widgetHeight = widgetCoords . w - widgetCoords . y; +// +// bool indicateOverflow = value > widgetHeight && coordInWidget . y + 4 >= widgetHeight +// &&((coordInWidget . x ^ coordInWidget . y)& 1)== 0; +// +// if((widgetHeight - coordInWidget . y)< value && ! indicateOverflow) +// { +// color = graphWidgetsData[graphWidget]. color; +// blendedWidgets = blend(blendedWidgets, color); +// } +// } +// +// while(textWidgets != 0) +// { +// const uint textWidget = findLSB(textWidgets); +// textWidgets ^= 1 << textWidget; +// +// const uvec4 widgetCoords = textWidgetsData[textWidget]. coordinates; +// if(! intersects(imageCoords, widgetCoords)) +// { +// continue; +// } +// +// const uvec2 coordInWidget = imageCoords - widgetCoords . xy; +// const uvec4 fontSizePacked = textWidgetsData[textWidget]. fontSize; +// const uvec2 fontGlyphSize = fontSizePacked . xy; +// const uint fontLayer = fontSizePacked . z; +// +// const uint textChar = getChar(textWidget, coordInWidget, fontGlyphSize . x); +// +// if(textChar <(32 * 3)) +// { +// +// const float sampleValue = sampleFont(textChar, coordInWidget, fontGlyphSize, fontLayer); +// +// vec4 color = vec4(0, 0, 0, 0.4); +// color = mix(color, textWidgetsData[textWidget]. color, sampleValue); +// +// blendedWidgets = blend(blendedWidgets, color); +// } +// } +// +// if(blendedWidgets . a < 1) +// { +// vec3 blendedColor = blendedWidgets . rgb; +// if(blendedWidgets . a > 0) +// { +// const vec4 color = imageLoad(blendOutput, ivec2(imageCoords)); +// blendedColor += color . rgb * color . a * blendedWidgets . a; +// } +// imageStore(blendOutput, ivec2(imageCoords), vec4(blendedColor, 1)); +// } +// } diff --git a/src/libANGLE/renderer/vulkan/shaders/src/OverlayCull.comp b/src/libANGLE/renderer/vulkan/shaders/src/OverlayCull.comp new file mode 100644 index 00000000000..3413f07c27e --- /dev/null +++ b/src/libANGLE/renderer/vulkan/shaders/src/OverlayCull.comp @@ -0,0 +1,164 @@ +// +// 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. +// +// OverlayCull.comp: Cull overlay widgets. A maximum of 32 text widgets and 32 graph widgets is +// supported simultaneously. + +#version 450 core + +#extension GL_EXT_samplerless_texture_functions : require +#if SupportsBallot +#extension GL_KHR_shader_subgroup_ballot: require +#elif SupportsArithmetic +#extension GL_KHR_shader_subgroup_arithmetic: require +#endif + +#if Is8x4 +#define WORKGROUP_WIDTH 32 +#define BLOCK_WIDTH 8 +#define BLOCK_HEIGHT 4 +#elif Is8x8 +#define WORKGROUP_WIDTH 64 +#define BLOCK_WIDTH 8 +#define BLOCK_HEIGHT 8 +#else +#error "Not all subgroup sizes are accounted for" +#endif + +// Limits: +#define MAX_TEXT_WIDGETS 32 +#define MAX_GRAPH_WIDGETS 32 + +layout (local_size_x = WORKGROUP_WIDTH, local_size_y = 1, local_size_z = 1) in; + +layout(set = 0, binding = 0, rgba32ui) uniform writeonly uimage2D culledWidgetsOut; + +layout (set = 0, binding = 1) uniform WidgetCoordinates +{ + uvec4 coordinates[MAX_TEXT_WIDGETS + MAX_GRAPH_WIDGETS]; +}; + +#if SupportsNone +shared uint intersectingWidgets[32]; + +void accumulateWidgets(const uint localId) +{ + // Note: no barriers needed as the workgroup size is the same as hardware subgroup size. + if (localId < 16) + { + intersectingWidgets[localId] |= intersectingWidgets[localId + 16]; + if (localId < 8) + { + intersectingWidgets[localId] |= intersectingWidgets[localId + 8]; + if (localId < 4) + { + intersectingWidgets[localId] |= intersectingWidgets[localId + 4]; + if (localId < 2) + { + intersectingWidgets[localId] |= intersectingWidgets[localId + 2]; + if (localId < 1) + { + intersectingWidgets[localId] |= intersectingWidgets[localId + 1]; + } + } + } + } + } +} +#endif + +uvec2 cullWidgets(const uint offset, const uvec2 blockCoordLow, const uvec2 blockCoordHigh) +{ + const uint localId = gl_LocalInvocationID.x; + const uvec4 widgetCoords = coordinates[offset + localId]; + + const bool intersects = widgetCoords.x < widgetCoords.z && + all(lessThan(widgetCoords.xy, blockCoordHigh)) && + all(greaterThanEqual(widgetCoords.zw, blockCoordLow)); + +#if SupportsBallot + + return subgroupBallot(intersects).xy; + +#elif SupportsArithmetic + +#if Is8x8 + const uint textWidgetBit = + localId < MAX_TEXT_WIDGETS ? uint(intersects) << localId : 0; + const uint graphWidgetBit = + localId >= MAX_TEXT_WIDGETS ? uint(intersects) << (localId - MAX_TEXT_WIDGETS) : 0; + return uvec2(subgroupOr(textWidgetBit), subgroupOr(graphWidgetBit)); +#elif Is8x4 + return uvec2(subgroupOr(uint(intersects) << localId), 0); +#else +#error "Not all subgroup sizes are accounted for" +#endif + +#elif SupportsNone + + uvec2 ballot = uvec2(0, 0); +#if Is8x8 + if (localId < MAX_TEXT_WIDGETS) + { + intersectingWidgets[localId] = uint(intersects) << localId; + accumulateWidgets(localId); + if (localId == 0) + { + ballot.x = intersectingWidgets[0]; + } + } + else + { + const uint graphLocalId = localId - MAX_TEXT_WIDGETS; + intersectingWidgets[graphLocalId] = uint(intersects) << graphLocalId; + accumulateWidgets(graphLocalId); + } + if (localId == 0) + { + ballot.y = intersectingWidgets[0]; + } +#elif Is8x4 + intersectingWidgets[localId] = uint(intersects) << localId; + accumulateWidgets(localId); + if (localId == 0) + { + ballot.x = intersectingWidgets[0]; + } +#else +#error "Not all subgroup sizes are accounted for" +#endif + + return ballot; + +#else +#error "Not all subgroup operations are accounted for" +#endif +} + +void main() +{ + // There is one workgroup invocation per pixel in culledWidgetsOut. Depending on the subgroup + // size, either all widgets and graphs are processed simultaneously (subgroup size 64) or + // separately (subgroup size 32). + const uvec2 outCoord = gl_WorkGroupID.xy; + const uvec2 blockCoordLow = outCoord * uvec2(BLOCK_WIDTH, BLOCK_HEIGHT); + const uvec2 blockCoordHigh = blockCoordLow + uvec2(BLOCK_WIDTH, BLOCK_HEIGHT); + + uvec2 culledWidgets; + +#if Is8x8 + culledWidgets = cullWidgets(0, blockCoordLow, blockCoordHigh); +#elif Is8x4 + culledWidgets.x = cullWidgets(0, blockCoordLow, blockCoordHigh).x; + culledWidgets.y = cullWidgets(MAX_TEXT_WIDGETS, blockCoordLow, blockCoordHigh).x; +#else +#error "Not all subgroup sizes are accounted for" +#endif + + if (gl_LocalInvocationID.x == 0) + { + imageStore(culledWidgetsOut, ivec2(outCoord), uvec4(culledWidgets, 0, 0)); + } +} diff --git a/src/libANGLE/renderer/vulkan/shaders/src/OverlayCull.comp.json b/src/libANGLE/renderer/vulkan/shaders/src/OverlayCull.comp.json new file mode 100644 index 00000000000..25edbf2cf5c --- /dev/null +++ b/src/libANGLE/renderer/vulkan/shaders/src/OverlayCull.comp.json @@ -0,0 +1,19 @@ +{ + "Description": [ + "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.", + "", + "OverlayCull.comp.json: Build parameters for OverlayCull.comp." + ], + "SubgroupSize": [ + "Is8x4", + "Is8x8" + ], + "SubgroupOp": [ + [ "SupportsBallot", "--target-env", "vulkan1.1" ], + [ "SupportsArithmetic", "--target-env", "vulkan1.1" ], + "SupportsNone" + ] +} + diff --git a/src/libANGLE/renderer/vulkan/shaders/src/OverlayDraw.comp b/src/libANGLE/renderer/vulkan/shaders/src/OverlayDraw.comp new file mode 100644 index 00000000000..098a46e4c2e --- /dev/null +++ b/src/libANGLE/renderer/vulkan/shaders/src/OverlayDraw.comp @@ -0,0 +1,230 @@ +// +// 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. +// +// OverlayDraw.comp: Draw overlay widgets. A maximum of 32 text widgets and 32 graph widgets is +// supported simultaneously. + +#version 450 core + +#extension GL_EXT_samplerless_texture_functions : require + +#if Is8x4 +#define BLOCK_WIDTH 8 +#define BLOCK_HEIGHT 4 +#elif Is8x8 +#define BLOCK_WIDTH 8 +#define BLOCK_HEIGHT 8 +#else +#error "Not all subgroup sizes are accounted for" +#endif + +// Limits: +// Note that max length and size is defined such that each buffer length is below 16KB, the minimum +// guaranteed supported size for uniform buffers. +#define MAX_TEXT_WIDGETS 32 +#define MAX_GRAPH_WIDGETS 32 +#define MAX_TEXT_LENGTH 256 +#define MAX_GRAPH_SIZE 64 + +// Font information: +#define FONT_GLYPHS_PER_ROW 32 +#define FONT_GLYPHS_ROWS 3 +#define FONT_CHARACTERS (FONT_GLYPHS_PER_ROW * FONT_GLYPHS_ROWS) + +layout (local_size_x = BLOCK_WIDTH, local_size_y = BLOCK_HEIGHT, local_size_z = 1) in; + +struct TextWidgetData +{ + uvec4 coordinates; + vec4 color; + uvec4 fontSize; // w unused. xy has the font glyph width/height. z has the layer. + uvec4 text[MAX_TEXT_LENGTH / 16]; +}; + +struct GraphWidgetData +{ + uvec4 coordinates; + vec4 color; + uvec4 valueWidth; // yzw unused. x should necessarily divide coordinate's z-x + uvec4 values[MAX_GRAPH_SIZE / 4]; +}; + +layout(set = 0, binding = 0, rgba32f) uniform image2D blendOutput; + +layout (set = 0, binding = 1) uniform TextWidgets +{ + TextWidgetData textWidgetsData[MAX_TEXT_WIDGETS]; +}; + +layout (set = 0, binding = 2) uniform GraphWidgets +{ + GraphWidgetData graphWidgetsData[MAX_GRAPH_WIDGETS]; +}; + +layout(set = 0, binding = 3) uniform utexture2D culledWidgets; +layout(set = 0, binding = 4) uniform texture2DArray font; + +layout (push_constant) uniform PushConstants +{ + uvec2 outputSize; +} params; + +bool intersects(const uvec2 imageCoords, const uvec4 widgetCoords) +{ + return all(greaterThanEqual(imageCoords, widgetCoords.xy)) && + all(lessThan(imageCoords, widgetCoords.zw)); +} + +uint getChar(const uint textWidget, const uvec2 coordInWidget, const uint fontGlyphWidth) +{ + const uint charIndex = coordInWidget.x / fontGlyphWidth; + const uint packIndex = charIndex / 4; + const uint packedChars = textWidgetsData[textWidget].text[packIndex / 4][packIndex % 4]; + const uint shift = (charIndex % 4) * 8; + +#if IsBigEndian + return (packedChars >> (24 - shift)) & 0xFF; +#else + return (packedChars >> shift) & 0xFF; +#endif +} + +float sampleFont(const uint textChar, + const uvec2 coordInWidget, + const uvec2 fontGlyphSize, + const uint fontLayer) +{ + const uvec2 coordInGlyph = coordInWidget % fontGlyphSize; + const uvec2 glyphOffset = fontGlyphSize * + uvec2(textChar % FONT_GLYPHS_PER_ROW, textChar / FONT_GLYPHS_PER_ROW); + + return texelFetch(font, ivec3(glyphOffset + coordInGlyph, fontLayer), 0).x; +} + +uint getValue(const uint graphWidget, const uvec2 coordInWidget, const uint valueWidth) +{ + const uint valueIndex = coordInWidget.x / valueWidth.x; + return graphWidgetsData[graphWidget].values[valueIndex / 4][valueIndex % 4]; +} + +vec4 blend(const vec4 blendedSoFar, const vec4 color) +{ + // Assuming colors (C1, a1), (C2, a2) ... (Cn, an) have been so far blended, blendedSoFar will + // contain: + // + // .rgb = Cn*an + ... + C2*a2*(1-a3)*...*(1-an) + C1*a1*(1-a2)*...*(1-an) + // .a = (1-a1)*(1-a2)*...*(1-an) + // + // Blending with (Cn+1, an+1) is simply: + // + // .rgb = Cn+1*an+1 + .rgb*(1-an+1) + // .a = .a*(1-an+1) + // + // Note that finally, the background color will be multipled by .a and added with .rgb. + + return vec4(blendedSoFar.rgb * (1 - color.a) + color.rgb * color.a, + blendedSoFar.a * (1 - color.a)); +} + +void main() +{ + const uvec2 imageCoords = gl_GlobalInvocationID.xy; + if (any(greaterThanEqual(imageCoords, params.outputSize))) + { + return; + } + + vec4 blendedWidgets = vec4(0, 0, 0, 1); + + const uvec2 subgroupWidgets = texelFetch(culledWidgets, ivec2(gl_WorkGroupID.xy), 0).xy; + uint textWidgets = subgroupWidgets.x; + uint graphWidgets = subgroupWidgets.y; + + // Loop through possible graph widgets that can intersect with this block. + while (graphWidgets != 0) + { + const uint graphWidget = findLSB(graphWidgets); + graphWidgets ^= 1 << graphWidget; + + const uvec4 widgetCoords = graphWidgetsData[graphWidget].coordinates; + if (!intersects(imageCoords, widgetCoords)) + { + continue; + } + + if (imageCoords.x == widgetCoords.x || imageCoords.y == widgetCoords.y || + imageCoords.x + 1 == widgetCoords.z || imageCoords.y + 1 == widgetCoords.w) + { + // Use a black border around the graph to mark the area. + blendedWidgets = vec4(0); + continue; + } + + const uvec2 coordInWidget = imageCoords - widgetCoords.xy; + const uint valueWidth = graphWidgetsData[graphWidget].valueWidth.x; + + // Find the value corresponding to this pixel. + const uint value = getValue(graphWidget, coordInWidget, valueWidth); + + vec4 color = vec4(0); + const uint widgetHeight = widgetCoords.w - widgetCoords.y; + + // If the graph value overflows the designated area, have the last four rows show a + // checkerboard pattern to signify that there is an overflow. + bool indicateOverflow = value > widgetHeight && coordInWidget.y + 4 >= widgetHeight + && ((coordInWidget.x ^ coordInWidget.y) & 1) == 0; + + if ((widgetHeight - coordInWidget.y) < value && !indicateOverflow) + { + color = graphWidgetsData[graphWidget].color; + blendedWidgets = blend(blendedWidgets, color); + } + } + + // Loop through possible text widgets that can intersect with this block. + while (textWidgets != 0) + { + const uint textWidget = findLSB(textWidgets); + textWidgets ^= 1 << textWidget; + + const uvec4 widgetCoords = textWidgetsData[textWidget].coordinates; + if (!intersects(imageCoords, widgetCoords)) + { + continue; + } + + const uvec2 coordInWidget = imageCoords - widgetCoords.xy; + const uvec4 fontSizePacked = textWidgetsData[textWidget].fontSize; + const uvec2 fontGlyphSize = fontSizePacked.xy; + const uint fontLayer = fontSizePacked.z; + + // Find the character corresponding to this pixel. + const uint textChar = getChar(textWidget, coordInWidget, fontGlyphSize.x); + + // The FONT_CHARACTERS value is a value filled where there is no character, so we don't add + // a background to it. + if (textChar < FONT_CHARACTERS) + { + // Sample the font based on this character. + const float sampleValue = sampleFont(textChar, coordInWidget, fontGlyphSize, fontLayer); + + vec4 color = vec4(0, 0, 0, 0.4); + color = mix(color, textWidgetsData[textWidget].color, sampleValue); + + blendedWidgets = blend(blendedWidgets, color); + } + } + + if (blendedWidgets.a < 1) + { + vec3 blendedColor = blendedWidgets.rgb; + if (blendedWidgets.a > 0) + { + const vec4 color = imageLoad(blendOutput, ivec2(imageCoords)); + blendedColor += color.rgb * color.a * blendedWidgets.a; + } + imageStore(blendOutput, ivec2(imageCoords), vec4(blendedColor, 1)); + } +} diff --git a/src/libANGLE/renderer/vulkan/shaders/src/OverlayDraw.comp.json b/src/libANGLE/renderer/vulkan/shaders/src/OverlayDraw.comp.json new file mode 100644 index 00000000000..6295a7a8b56 --- /dev/null +++ b/src/libANGLE/renderer/vulkan/shaders/src/OverlayDraw.comp.json @@ -0,0 +1,14 @@ +{ + "Description": [ + "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.", + "", + "OverlayDraw.comp.json: Build parameters for OverlayDraw.comp." + ], + "SubgroupSize": [ + "Is8x4", + "Is8x8" + ] +} + diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp index 8daa950af4f..53082832b82 100644 --- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp +++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp @@ -1412,7 +1412,7 @@ void BufferHelper::unmap(VkDevice device) } } -angle::Result BufferHelper::flush(ContextVk *contextVk, size_t offset, size_t size) +angle::Result BufferHelper::flush(ContextVk *contextVk, VkDeviceSize offset, VkDeviceSize size) { bool hostVisible = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; bool hostCoherent = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; @@ -1428,7 +1428,7 @@ angle::Result BufferHelper::flush(ContextVk *contextVk, size_t offset, size_t si return angle::Result::Continue; } -angle::Result BufferHelper::invalidate(ContextVk *contextVk, size_t offset, size_t size) +angle::Result BufferHelper::invalidate(ContextVk *contextVk, VkDeviceSize offset, VkDeviceSize size) { bool hostVisible = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; bool hostCoherent = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; @@ -2401,11 +2401,11 @@ void ImageHelper::stageSubresourceUpdateFromImage(vk::ImageHelper *image, const gl::Extents &glExtents, const VkImageType imageType) { - VkImageCopy copyToImage = {}; - copyToImage.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyToImage.srcSubresource.layerCount = index.getLayerCount(); - copyToImage.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyToImage.dstSubresource.mipLevel = index.getLevelIndex(); + VkImageCopy copyToImage = {}; + copyToImage.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyToImage.srcSubresource.layerCount = index.getLayerCount(); + copyToImage.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyToImage.dstSubresource.mipLevel = index.getLevelIndex(); if (imageType == VK_IMAGE_TYPE_3D) { diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h index 0d9de867a66..59c540dd985 100644 --- a/src/libANGLE/renderer/vulkan/vk_helpers.h +++ b/src/libANGLE/renderer/vulkan/vk_helpers.h @@ -535,10 +535,10 @@ class BufferHelper final : public CommandGraphResource void unmap(VkDevice device); // After a sequence of writes, call flush to ensure the data is visible to the device. - angle::Result flush(ContextVk *contextVk, size_t offset, size_t size); + angle::Result flush(ContextVk *contextVk, VkDeviceSize offset, VkDeviceSize size); // After a sequence of writes, call invalidate to ensure the data is visible to the host. - angle::Result invalidate(ContextVk *contextVk, size_t offset, size_t size); + angle::Result invalidate(ContextVk *contextVk, VkDeviceSize offset, VkDeviceSize size); private: angle::Result mapImpl(ContextVk *contextVk); diff --git a/src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.cpp b/src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.cpp index 432b2cebc1f..28152893652 100644 --- a/src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.cpp +++ b/src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.cpp @@ -127,6 +127,14 @@ namespace #include "libANGLE/renderer/vulkan/shaders/gen/ImageCopy.frag.00000013.inc" #include "libANGLE/renderer/vulkan/shaders/gen/ImageCopy.frag.00000014.inc" #include "libANGLE/renderer/vulkan/shaders/gen/ImageCopy.frag.00000015.inc" +#include "libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000000.inc" +#include "libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000001.inc" +#include "libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000002.inc" +#include "libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000003.inc" +#include "libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000004.inc" +#include "libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000005.inc" +#include "libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000000.inc" +#include "libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000001.inc" // This is SPIR-V binary blob and the size. struct ShaderBlob @@ -266,6 +274,18 @@ constexpr ShaderBlob kImageCopy_frag_shaders[] = { {kImageCopy_frag_00000014, sizeof(kImageCopy_frag_00000014)}, {kImageCopy_frag_00000015, sizeof(kImageCopy_frag_00000015)}, }; +constexpr ShaderBlob kOverlayCull_comp_shaders[] = { + {kOverlayCull_comp_00000000, sizeof(kOverlayCull_comp_00000000)}, + {kOverlayCull_comp_00000001, sizeof(kOverlayCull_comp_00000001)}, + {kOverlayCull_comp_00000002, sizeof(kOverlayCull_comp_00000002)}, + {kOverlayCull_comp_00000003, sizeof(kOverlayCull_comp_00000003)}, + {kOverlayCull_comp_00000004, sizeof(kOverlayCull_comp_00000004)}, + {kOverlayCull_comp_00000005, sizeof(kOverlayCull_comp_00000005)}, +}; +constexpr ShaderBlob kOverlayDraw_comp_shaders[] = { + {kOverlayDraw_comp_00000000, sizeof(kOverlayDraw_comp_00000000)}, + {kOverlayDraw_comp_00000001, sizeof(kOverlayDraw_comp_00000001)}, +}; angle::Result GetShader(Context *context, RefCounted *shaders, @@ -329,6 +349,14 @@ void ShaderLibrary::destroy(VkDevice device) { shader.get().destroy(device); } + for (RefCounted &shader : mOverlayCull_comp_shaders) + { + shader.get().destroy(device); + } + for (RefCounted &shader : mOverlayDraw_comp_shaders) + { + shader.get().destroy(device); + } } angle::Result ShaderLibrary::getBlitResolve_frag(Context *context, @@ -397,5 +425,21 @@ angle::Result ShaderLibrary::getImageCopy_frag(Context *context, ArraySize(kImageCopy_frag_shaders), shaderFlags, shaderOut); } +angle::Result ShaderLibrary::getOverlayCull_comp(Context *context, + uint32_t shaderFlags, + RefCounted **shaderOut) +{ + return GetShader(context, mOverlayCull_comp_shaders, kOverlayCull_comp_shaders, + ArraySize(kOverlayCull_comp_shaders), shaderFlags, shaderOut); +} + +angle::Result ShaderLibrary::getOverlayDraw_comp(Context *context, + uint32_t shaderFlags, + RefCounted **shaderOut) +{ + return GetShader(context, mOverlayDraw_comp_shaders, kOverlayDraw_comp_shaders, + ArraySize(kOverlayDraw_comp_shaders), shaderFlags, shaderOut); +} + } // namespace vk } // namespace rx diff --git a/src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.gni b/src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.gni index 3c44caa365a..64a9f6349b9 100644 --- a/src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.gni +++ b/src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.gni @@ -120,4 +120,12 @@ angle_vulkan_internal_shaders = [ "src/libANGLE/renderer/vulkan/shaders/gen/ImageCopy.frag.00000013.inc", "src/libANGLE/renderer/vulkan/shaders/gen/ImageCopy.frag.00000014.inc", "src/libANGLE/renderer/vulkan/shaders/gen/ImageCopy.frag.00000015.inc", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000000.inc", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000001.inc", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000002.inc", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000003.inc", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000004.inc", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayCull.comp.00000005.inc", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000000.inc", + "src/libANGLE/renderer/vulkan/shaders/gen/OverlayDraw.comp.00000001.inc", ] diff --git a/src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h b/src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h index 60ef2dc7394..56f7c764804 100644 --- a/src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h +++ b/src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h @@ -150,6 +150,32 @@ enum DestFormat constexpr size_t kArrayLen = 0x00000016; } // namespace ImageCopy_frag +namespace OverlayCull_comp +{ +enum SubgroupSize +{ + kIs8x4 = 0x00000000, + kIs8x8 = 0x00000001, +}; +enum SubgroupOp +{ + kSupportsBallot = 0x00000000, + kSupportsArithmetic = 0x00000002, + kSupportsNone = 0x00000004, +}; +constexpr size_t kArrayLen = 0x00000006; +} // namespace OverlayCull_comp + +namespace OverlayDraw_comp +{ +enum SubgroupSize +{ + kIs8x4 = 0x00000000, + kIs8x8 = 0x00000001, +}; +constexpr size_t kArrayLen = 0x00000002; +} // namespace OverlayDraw_comp + } // namespace InternalShader class ShaderLibrary final : angle::NonCopyable @@ -184,6 +210,12 @@ class ShaderLibrary final : angle::NonCopyable angle::Result getImageCopy_frag(Context *context, uint32_t shaderFlags, RefCounted **shaderOut); + angle::Result getOverlayCull_comp(Context *context, + uint32_t shaderFlags, + RefCounted **shaderOut); + angle::Result getOverlayDraw_comp(Context *context, + uint32_t shaderFlags, + RefCounted **shaderOut); private: RefCounted @@ -201,6 +233,10 @@ class ShaderLibrary final : angle::NonCopyable RefCounted mImageClear_frag_shaders[InternalShader::ImageClear_frag::kArrayLen]; RefCounted mImageCopy_frag_shaders[InternalShader::ImageCopy_frag::kArrayLen]; + RefCounted + mOverlayCull_comp_shaders[InternalShader::OverlayCull_comp::kArrayLen]; + RefCounted + mOverlayDraw_comp_shaders[InternalShader::OverlayDraw_comp::kArrayLen]; }; } // namespace vk } // namespace rx diff --git a/src/libANGLE/renderer/vulkan/vk_utils.h b/src/libANGLE/renderer/vulkan/vk_utils.h index f4f29b245dd..e7711a66983 100644 --- a/src/libANGLE/renderer/vulkan/vk_utils.h +++ b/src/libANGLE/renderer/vulkan/vk_utils.h @@ -27,6 +27,7 @@ PROC(Framebuffer) \ PROC(MemoryObject) \ PROC(Query) \ + PROC(Overlay) \ PROC(Program) \ PROC(Sampler) \ PROC(Semaphore) \ @@ -45,6 +46,7 @@ class Image; namespace gl { struct Box; +class DummyOverlay; struct Extents; struct RasterizerState; struct Rectangle; @@ -151,6 +153,12 @@ struct ImplTypeHelper \ ANGLE_GL_OBJECTS_X(ANGLE_IMPL_TYPE_HELPER_GL) +template <> +struct ImplTypeHelper +{ + using ImplType = OverlayVk; +}; + template <> struct ImplTypeHelper { @@ -172,6 +180,12 @@ GetImplType *GetImpl(const T *glObject) return GetImplAs>(glObject); } +template <> +inline OverlayVk *GetImpl(const gl::DummyOverlay *glObject) +{ + return nullptr; +} + class GarbageObjectBase { public: diff --git a/src/libANGLE/renderer/vulkan/vk_wrapper.h b/src/libANGLE/renderer/vulkan/vk_wrapper.h index 904b89dd24b..829b8f77feb 100644 --- a/src/libANGLE/renderer/vulkan/vk_wrapper.h +++ b/src/libANGLE/renderer/vulkan/vk_wrapper.h @@ -296,6 +296,8 @@ class CommandBuffer : public WrappedObject void endRenderPass(); void executeCommands(uint32_t commandBufferCount, const CommandBuffer *commandBuffers); + void getMemoryUsageStats(size_t *usedMemoryOut, size_t *allocatedMemoryOut); + void executionBarrier(VkPipelineStageFlags stageMask); void fillBuffer(const Buffer &dstBuffer, @@ -814,6 +816,14 @@ ANGLE_INLINE void CommandBuffer::executeCommands(uint32_t commandBufferCount, vkCmdExecuteCommands(mHandle, commandBufferCount, commandBuffers[0].ptr()); } +ANGLE_INLINE void CommandBuffer::getMemoryUsageStats(size_t *usedMemoryOut, + size_t *allocatedMemoryOut) +{ + // No data available. + *usedMemoryOut = 0; + *allocatedMemoryOut = 1; +} + ANGLE_INLINE void CommandBuffer::fillBuffer(const Buffer &dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, diff --git a/src/libGLESv2.gni b/src/libGLESv2.gni index 987572b2a8e..ba759a22908 100644 --- a/src/libGLESv2.gni +++ b/src/libGLESv2.gni @@ -243,6 +243,13 @@ libangle_sources = [ "src/libANGLE/MemoryProgramCache.h", "src/libANGLE/Observer.cpp", "src/libANGLE/Observer.h", + "src/libANGLE/Overlay.cpp", + "src/libANGLE/Overlay.h", + "src/libANGLE/OverlayWidgets.cpp", + "src/libANGLE/OverlayWidgets.h", + "src/libANGLE/Overlay_autogen.cpp", + "src/libANGLE/Overlay_font_autogen.cpp", + "src/libANGLE/Overlay_font_autogen.h", "src/libANGLE/Path.h", "src/libANGLE/Path.cpp", "src/libANGLE/Platform.cpp", @@ -331,6 +338,7 @@ libangle_sources = [ "src/libANGLE/renderer/GLImplFactory.h", "src/libANGLE/renderer/ImageImpl.h", "src/libANGLE/renderer/MemoryObjectImpl.h", + "src/libANGLE/renderer/OverlayImpl.h", "src/libANGLE/renderer/PathImpl.h", "src/libANGLE/renderer/ProgramImpl.h", "src/libANGLE/renderer/ProgramPipelineImpl.h", @@ -863,6 +871,8 @@ libangle_vulkan_sources = [ "src/libANGLE/renderer/vulkan/ImageVk.h", "src/libANGLE/renderer/vulkan/MemoryObjectVk.cpp", "src/libANGLE/renderer/vulkan/MemoryObjectVk.h", + "src/libANGLE/renderer/vulkan/OverlayVk.cpp", + "src/libANGLE/renderer/vulkan/OverlayVk.h", "src/libANGLE/renderer/vulkan/PersistentCommandPool.cpp", "src/libANGLE/renderer/vulkan/PersistentCommandPool.h", "src/libANGLE/renderer/vulkan/ProgramVk.cpp", diff --git a/src/tests/angle_unittests_utils.h b/src/tests/angle_unittests_utils.h index fb52f706d86..48fecc359a6 100644 --- a/src/tests/angle_unittests_utils.h +++ b/src/tests/angle_unittests_utils.h @@ -76,6 +76,10 @@ class NullFactory : public GLImplFactory { return std::vector(); } + + SemaphoreImpl *createSemaphore() override { return nullptr; } + + OverlayImpl *createOverlay(const gl::OverlayState &state) override { return nullptr; } }; // A class with all the factory methods mocked. @@ -101,6 +105,7 @@ class MockGLFactory : public GLImplFactory MOCK_METHOD1(createSampler, SamplerImpl *(const gl::SamplerState &)); MOCK_METHOD1(createPaths, std::vector(GLsizei)); MOCK_METHOD0(createSemaphore, SemaphoreImpl *()); + MOCK_METHOD1(createOverlay, OverlayImpl *(const gl::OverlayState &)); }; class MockEGLFactory : public EGLImplFactory diff --git a/src/tests/perf_tests/ANGLEPerfTest.cpp b/src/tests/perf_tests/ANGLEPerfTest.cpp index 0668c648580..3f9f850b15d 100644 --- a/src/tests/perf_tests/ANGLEPerfTest.cpp +++ b/src/tests/perf_tests/ANGLEPerfTest.cpp @@ -185,9 +185,7 @@ ANGLEPerfTest::ANGLEPerfTest(const std::string &name, mReporter->RegisterFyiMetric(".steps", "count"); } -ANGLEPerfTest::~ANGLEPerfTest() -{ -} +ANGLEPerfTest::~ANGLEPerfTest() {} void ANGLEPerfTest::run() {