GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
74 / 75
98.7%
Branches:
20 / 38
52.6%
Functions:
11 / 11
100.0%

app/imgui_backend.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file imgui_backend.cpp
3 /// @brief Creating the ImGui context, setting up its Vulkan backend and recording its draws.
4 #include "ernie/app/imgui_backend.h"
5
6 #include "ernie/util/profiler.h"
7
8 #include <imgui.h>
9 #include <imgui_impl_vulkan.h>
10
11 namespace ernie::app {
12 namespace {
13
14 12 void Transition(VkCommandBuffer commands, VkImage image, VkImageLayout from, VkImageLayout to,
15 VkPipelineStageFlags2 srcStage, VkAccessFlags2 srcAccess,
16 VkPipelineStageFlags2 dstStage, VkAccessFlags2 dstAccess) {
17 12 const VkImageMemoryBarrier2 barrier{
18 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
19 .srcStageMask = srcStage,
20 .srcAccessMask = srcAccess,
21 .dstStageMask = dstStage,
22 .dstAccessMask = dstAccess,
23 .oldLayout = from,
24 .newLayout = to,
25 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
26 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
27 .image = image,
28 12 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
29 12 const VkDependencyInfo dependency{.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
30 .imageMemoryBarrierCount = 1,
31 12 .pImageMemoryBarriers = &barrier};
32 12 vkCmdPipelineBarrier2(commands, &dependency);
33 12 }
34
35 } // namespace
36
37 8 ImGuiSession::ImGuiSession(const Theme& theme) {
38 8 ERNIE_ZONE("Set up ImGui");
39
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 IMGUI_CHECKVERSION();
40
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 context_ = ImGui::CreateContext();
41
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 ImGuiIO& io = ImGui::GetIO();
42 // Layouts are the viewer's to save; nothing is written behind its back.
43 8 io.IniFilename = nullptr;
44 8 io.LogFilename = nullptr;
45 8 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableKeyboard;
46
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 io.Fonts->AddFontDefaultVector();
47
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 ApplyTheme(theme);
48 8 }
49
50 8 ImGuiSession::~ImGuiSession() {
51 8 ImGui::DestroyContext(context_);
52 8 }
53
54 2 ImGuiRenderer::ImGuiRenderer(DeviceContext& context, VkFormat format, std::uint32_t imageCount)
55 2 : context_(context) {
56 2 ERNIE_ZONE("Set up ImGui's Vulkan backend");
57
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 ImGui_ImplVulkan_InitInfo info{};
58 2 info.ApiVersion = VK_API_VERSION_1_3;
59
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 info.Instance = context.Instance();
60
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 info.PhysicalDevice = context.Physical();
61
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 info.Device = context.Device();
62
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 info.QueueFamily = context.Main().Family();
63 // Used only by texture uploads, which borrow the queue (`UpdateTextures`).
64
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 info.Queue = context.Main().Handle();
65 2 info.DescriptorPoolSize = 64;
66 2 info.MinImageCount = imageCount;
67 2 info.ImageCount = imageCount;
68 2 info.UseDynamicRendering = true;
69 2 info.PipelineInfoMain.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
70 2 info.PipelineInfoMain.PipelineRenderingCreateInfo = {
71 .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
72 .colorAttachmentCount = 1,
73 .pColorAttachmentFormats = &format};
74
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 info.PipelineCache = context.PipelineCache();
75 2 info.CheckVkResultFn = [](VkResult result) { CheckVk(result, "ImGui's Vulkan backend"); };
76
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
2 if (!ImGui_ImplVulkan_Init(&info)) {
77
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw DeviceError(DeviceErrorKind::Failed, "Could not set up ImGui's Vulkan backend");
78 }
79 2 }
80
81 2 ImGuiRenderer::~ImGuiRenderer() {
82 4 Quietly([this] { context_.Main().Last().Wait(); });
83 2 ImGui_ImplVulkan_Shutdown();
84 2 }
85
86 6 void ImGuiRenderer::NewFrame() {
87 6 ImGui_ImplVulkan_NewFrame();
88 6 }
89
90 4 ImTextureID ImGuiRenderer::AddTexture(VkImageView view, VkSampler sampler) {
91 4 return reinterpret_cast<ImTextureID>(
92 4 ImGui_ImplVulkan_AddTexture(sampler, view, VK_IMAGE_LAYOUT_GENERAL));
93 }
94
95 2 void ImGuiRenderer::RemoveTexture(ImTextureID texture) {
96 2 ImGui_ImplVulkan_RemoveTexture(reinterpret_cast<VkDescriptorSet>(texture));
97 2 }
98
99 6 void ImGuiRenderer::UpdateTextures(ImDrawData& data) {
100
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (data.Textures == nullptr) {
101 return;
102 }
103
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 for (ImTextureData* texture : *data.Textures) {
104
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (texture->Status != ImTextureStatus_OK) {
105 // The font atlas, on the first frame and when it grows; the backend submits the
106 // upload and waits for it itself.
107 2 ERNIE_ZONE("Upload a UI texture");
108
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 context_.Main().Borrow([&](VkQueue) { ImGui_ImplVulkan_UpdateTexture(texture); });
109 2 }
110 }
111 }
112
113 6 void ImGuiRenderer::Record(VkCommandBuffer commands, ImDrawData& data, const FrameTarget& target,
114 const glm::vec4& clear) {
115 // Whatever the image held is replaced; earlier work on it, a previous frame's, finishes first.
116 6 Transition(commands, target.image, VK_IMAGE_LAYOUT_UNDEFINED,
117 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
118 VK_ACCESS_2_MEMORY_WRITE_BIT, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
119 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT);
120 6 const VkRenderingAttachmentInfo attachment{
121 .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
122 6 .imageView = target.view,
123 .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
124 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
125 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
126 6 .clearValue = {.color = {.float32 = {clear.r, clear.g, clear.b, clear.a}}}};
127 6 const VkRenderingInfo rendering{.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
128 6 .renderArea = {{0, 0}, {target.extent.x, target.extent.y}},
129 .layerCount = 1,
130 .colorAttachmentCount = 1,
131 6 .pColorAttachments = &attachment};
132 6 vkCmdBeginRendering(commands, &rendering);
133 6 ImGui_ImplVulkan_RenderDrawData(&data, commands);
134 6 vkCmdEndRendering(commands);
135 6 Transition(commands, target.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, target.finalLayout,
136 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
137 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
138 kAnyAccess);
139 6 }
140
141 } // namespace ernie::app
142