GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
9 / 9
100.0%
Branches:
8 / 18
44.4%
Functions:
1 / 1, 1 excl
100.0%

app/viewer.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file viewer.h
3 /// @brief The interactive viewer: a window, or an offscreen image, showing the shell's panels
4 /// around the viewport, and the command line that opens it.
5 #pragma once
6
7 #include "ernie/app/imgui_backend.h"
8 #include "ernie/app/ui.h"
9 #include "ernie/device/bindless.h"
10 #include "ernie/render/device_scene.h"
11 #include "ernie/render/rt/camera_pass.h"
12
13 #include <glm/vec2.hpp>
14
15 #include <chrono>
16 #include <cstdint>
17 #include <deque>
18 #include <filesystem>
19 #include <memory>
20 #include <optional>
21 #include <span>
22 #include <string>
23 #include <string_view>
24
25 namespace ernie::app {
26
27 4 struct ViewerOptions {
28 std::string title = "Ernie";
29 /// The window's or the offscreen image's size, in pixels.
30 glm::uvec2 size{1600, 900};
31 /// Draw into an image without a window, for tests and machines without a display.
32 bool offscreen = false;
33 /// Frames to draw before `Run` returns; 0 runs until the window closes.
34 std::uint64_t frames = 0;
35 /// The device: its UUID in hex or part of its name; empty for the best.
36 std::string device;
37 /// The Khronos validation layer, when installed.
38 bool validation = false;
39 /// Wait for the display's refresh; off by default, so frames show what they cost.
40 bool vsync = false;
41 ShellOptions shell;
42 };
43
44 /// @brief The viewer on a scene. Each frame takes input, draws the shell's UI, traces the orbit
45 /// camera into the viewport (or clears it to the theme's colour on devices without ray queries),
46 /// draws the UI over it and presents it. Drive it on the thread that made it.
47 class Viewer {
48 public:
49 /// @param scene Read by the panels; must outlive the viewer.
50 /// @throws std::runtime_error without a display unless offscreen, DeviceError without a
51 /// device.
52 Viewer(const Scene& scene, const ViewerOptions& options = {});
53 ~Viewer();
54 Viewer(const Viewer&) = delete;
55 Viewer& operator=(const Viewer&) = delete;
56
57 /// @brief Draws frames until the window closes, the user quits or the frame count is reached.
58 void Run();
59
60 1 std::uint64_t Frames() const {
61
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 return frames_;
62 }
63 4 Shell& GetShell() {
64
3/6
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
4 return *shell_;
65 }
66 5 DeviceContext& Context() {
67
3/8
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 10 not taken.
5 return *context_;
68 }
69 /// @return The offscreen presenter, or null when presenting to a window.
70 2 const OffscreenPresenter* Offscreen() const {
71
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 return dynamic_cast<const OffscreenPresenter*>(presenter_.get());
72 }
73
74 private:
75 /// @return Whether to keep going.
76 bool Step();
77 /// @brief Sizes the viewport's image to the dock space's central node and draws it there,
78 /// behind the panels.
79 void ShowViewport();
80 /// @brief Makes the viewport's image `pixels` in size, in the UI and the heap.
81 void ResizeViewport(glm::uvec2 pixels);
82 /// @brief Adds the pass filling the viewport: traced, or the theme's colour without ray
83 /// queries.
84 /// @return The viewport, filled.
85 graph::Image AddViewportPass(graph::Graph& graph);
86 /// @brief Adds the frame's own passes: rendering the viewport, then the UI over the target.
87 void AddPasses(graph::Graph& graph, ImDrawData& data, const FrameTarget& target);
88
89 ViewerOptions options_;
90 // Made in this order, destroyed in reverse.
91 ImGuiSession imgui_;
92 std::unique_ptr<DeviceContext> context_;
93 std::unique_ptr<Presenter> presenter_;
94 std::unique_ptr<ImGuiRenderer> renderer_;
95 std::unique_ptr<Shell> shell_;
96 std::unique_ptr<Arenas> arenas_;
97 std::unique_ptr<DeviceScene> deviceScene_;
98 /// The heap and pass tracing the viewport; null without ray queries.
99 std::unique_ptr<BindlessHeap> heap_;
100 std::unique_ptr<CameraPass> camera_;
101 /// The image the viewport is rendered into, the UI's texture of it, and its storage slot.
102 std::unique_ptr<Sampler> sampler_;
103 std::unique_ptr<DeviceImage> viewport_;
104 ImTextureID viewportTexture_ = 0;
105 BindlessIndex viewportImage_;
106 /// The frames the device may still be drawing, oldest first.
107 std::deque<Ticket> inFlight_;
108 std::uint64_t frames_ = 0;
109 std::chrono::steady_clock::time_point last_ = std::chrono::steady_clock::now();
110 };
111
112 /// @brief What the viewer's command line, `ernie [view] [SCENE.json] [options]`, asks for.
113 struct ViewCommand {
114 /// The scene file to open; none for an empty scene.
115 std::optional<std::filesystem::path> scene;
116 ViewerOptions viewer;
117 };
118
119 /// @return The options the viewer's command line usage lists.
120 std::string_view ViewUsage();
121
122 /// @brief Reads the viewer's arguments: an optional scene file and options.
123 /// @throws std::invalid_argument for an unknown option, a missing value or a second scene.
124 ViewCommand ParseViewCommand(std::span<const std::string_view> arguments);
125
126 /// @brief Opens the viewer on the command's scene and runs it until closed.
127 /// @return The process's exit status.
128 int RunView(const ViewCommand& command);
129
130 } // namespace ernie::app
131