debug_ui.hpp 7.51 KB
Newer Older
1
2
3
4
5
6
7
#pragma once

#include <mirrage/renderer/deferred_renderer.hpp>

#include <mirrage/gui/debug_ui.hpp>
#include <mirrage/gui/gui.hpp>

Florian Oetke's avatar
Florian Oetke committed
8
#include <imgui.h>
9
10


Florian Oetke's avatar
Florian Oetke committed
11
namespace mirrage::renderer {
12

13
	namespace detail {
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
		template <typename T>
		auto to_fixed_str(T num, int digits)
		{
			auto ss = std::stringstream{};
			ss << std::fixed << std::setprecision(digits) << num;
			return ss.str();
		}

		auto pad_left(const std::string& str, int padding)
		{
			return std::string(std::size_t(padding), ' ') + str;
		}

		template <std::size_t N, typename Container, typename Comp>
		auto top_n(const Container& container, Comp&& less)
		{
			auto max_elements = std::array<decltype(container.begin()), N>();
			max_elements.fill(container.end());

			for(auto iter = container.begin(); iter != container.end(); iter++) {
				// compare with each of the top elements
				for(auto i = std::size_t(0); i < N; i++) {
					if(max_elements[i] == container.end() || less(*max_elements[i], *iter)) {
						// move top elements to make room
						for(auto j = i + 1; j < N; j++) {
							max_elements[j] = max_elements[j - 1];
						}
						max_elements[i] = iter;
						break;
					}
				}
			}

			return max_elements;
		}

		template <typename Container, typename T>
		auto index_of(const Container& container, const T& element) -> int
		{
			auto top_entry = std::find(container.begin(), container.end(), element);
			if(top_entry == container.end())
				return -1;

			return gsl::narrow<int>(std::distance(container.begin(), top_entry));
		}
59
	} // namespace detail
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79


	class Deferred_renderer_factory::Profiler_menu : public gui::Debug_menu {
	  public:
		Profiler_menu(std::vector<Deferred_renderer*>& renderer_instances)
		  : Debug_menu("profiler"), _renderer_instances(renderer_instances)
		{
		}

		void on_show() override
		{
			for(auto& r : _renderer_instances)
				r->profiler().enable();
		}
		void on_hide() override
		{
			for(auto& r : _renderer_instances)
				r->profiler().disable();
		}

Florian Oetke's avatar
Florian Oetke committed
80
		void draw(gui::Gui&) override
81
82
83
84
		{
			for(auto& r : _renderer_instances)
				r->profiler().enable();

Florian Oetke's avatar
Florian Oetke committed
85
86
87
88
			ImGui::PositionNextWindow(
			        {330, 380}, ImGui::WindowPosition_X::right, ImGui::WindowPosition_Y::center);
			if(ImGui::Begin("Renderer Profiler")) {
				if(ImGui::Button("Reset")) {
89
90
91
92
93
94
95
96
97
98
					for(auto& r : _renderer_instances)
						r->profiler().reset();
				}

#if 0
				if(_performance_log.is_nothing() && nk_button_label(ctx, "Record")) {
					_performance_log = _engine.assets().save_raw("log:perf.log"_aid);
				}
#endif

Florian Oetke's avatar
Florian Oetke committed
99
100
101
				ImGui::BeginTable("perf",
				                  {"RenderPass", "Curr (ms)", "Min (ms)", "Avg (ms)", "Max (ms)"},
				                  _first_frame);
102
103
104
105
106
107
108

				auto print_entry = [&](auto&&                          printer,
				                       const graphic::Profiler_result& result,
				                       int                             depth = 0,
				                       int                             rank  = -1) -> void {
					auto color = [&] {
						switch(rank) {
Florian Oetke's avatar
Florian Oetke committed
109
110
111
							case 0: return ImColor(255, 0, 0);
							case 1: return ImColor(255, 220, 128);
							default: return ImColor(255, 255, 255);
112
113
114
						}
					}();

Florian Oetke's avatar
Florian Oetke committed
115
116
117
118
119
120
121
122
123
124
					ImGui::TextColored(color, "%s", detail::pad_left(result.name(), depth * 4).c_str());
					ImGui::NextColumn();
					ImGui::TextColored(color, "%s", detail::to_fixed_str(result.time_ms(), 2).c_str());
					ImGui::NextColumn();
					ImGui::TextColored(color, "%s", detail::to_fixed_str(result.time_min_ms(), 2).c_str());
					ImGui::NextColumn();
					ImGui::TextColored(color, "%s", detail::to_fixed_str(result.time_avg_ms(), 2).c_str());
					ImGui::NextColumn();
					ImGui::TextColored(color, "%s", detail::to_fixed_str(result.time_max_ms(), 2).c_str());
					ImGui::NextColumn();
125

126
					auto worst_timings = detail::top_n<2>(result, [](auto&& lhs, auto&& rhs) {
127
128
129
130
						return lhs.time_avg_ms() < rhs.time_avg_ms();
					});

					for(auto iter = result.begin(); iter != result.end(); iter++) {
131
						auto rank = detail::index_of(worst_timings, iter);
132
133
134
135
136
137
138
139
140
						printer(printer, *iter, depth + 1, rank);
					}
				};


				for(auto& r : _renderer_instances)
					print_entry(print_entry, r->profiler().results());
			}

Florian Oetke's avatar
Florian Oetke committed
141
142
			ImGui::End();
			_first_frame = false;
143
144
145
146
		}

	  private:
		std::vector<Deferred_renderer*>& _renderer_instances;
Florian Oetke's avatar
Florian Oetke committed
147
		bool                             _first_frame = true;
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
	};


	class Deferred_renderer_factory::Settings_menu : public gui::Debug_menu {
	  public:
		Settings_menu(Deferred_renderer_factory& factory, graphic::Window& window)
		  : Debug_menu("renderer_settings")
		  , _factory(factory)
		  , _window(window)
		  , _window_width(_window.width())
		  , _window_height(_window.height())
		  , _window_fullscreen(_window.fullscreen() != graphic::Fullscreen::no)
		{
		}

Florian Oetke's avatar
Florian Oetke committed
163
		void draw(gui::Gui&) override
164
		{
Florian Oetke's avatar
Florian Oetke committed
165
166
167
			ImGui::PositionNextWindow(
			        {250, 600}, ImGui::WindowPosition_X::left, ImGui::WindowPosition_Y::center);
			if(ImGui::Begin("Renderer Setting")) {
168
169
170

				auto renderer_settings = _factory.settings();

Florian Oetke's avatar
Florian Oetke committed
171
172
				ImGui::SliderInt("Window Width", &_window_width, 640, 7680);
				ImGui::SliderInt("Window Height", &_window_height, 360, 4320);
173

Florian Oetke's avatar
Florian Oetke committed
174
				ImGui::Checkbox("Fullscreen", &_window_fullscreen);
175

Florian Oetke's avatar
Florian Oetke committed
176
				if(ImGui::Button("Apply")) {
177
178
179
					apply_window_changed();
				}

Florian Oetke's avatar
Florian Oetke committed
180
				ImGui::Spacing();
Florian Oetke's avatar
Florian Oetke committed
181

Florian Oetke's avatar
Florian Oetke committed
182
				ImGui::TextUnformatted("Renderer Settings");
183

Florian Oetke's avatar
Florian Oetke committed
184
				ImGui::Checkbox("Particle Frag. Shadows", &renderer_settings.particle_fragment_shadows);
185

Florian Oetke's avatar
Florian Oetke committed
186
				ImGui::SliderInt("Debug Layer", &renderer_settings.debug_gi_layer, -1, 10);
187

Florian Oetke's avatar
Florian Oetke committed
188
				ImGui::Checkbox("Indirect Illumination", &renderer_settings.gi);
189

Florian Oetke's avatar
Florian Oetke committed
190
				ImGui::Checkbox("Indirect Shadows", &renderer_settings.gi_shadows);
191

Florian Oetke's avatar
Florian Oetke committed
192
				ImGui::Checkbox("High-Resolution GI", &renderer_settings.gi_highres);
193

Florian Oetke's avatar
Florian Oetke committed
194
				ImGui::SliderInt("Minimum GI MIP", &renderer_settings.gi_min_mip_level, 0, 4);
195

Florian Oetke's avatar
Florian Oetke committed
196
				ImGui::SliderInt("Diffuse GI MIP", &renderer_settings.gi_diffuse_mip_level, 0, 4);
197

Florian Oetke's avatar
Florian Oetke committed
198
199
				ImGui::SliderInt("Low-Res Sample Count", &renderer_settings.gi_lowres_samples, 8, 1024);
				ImGui::SliderInt("Sample Count", &renderer_settings.gi_samples, 8, 1024);
200

Florian Oetke's avatar
Florian Oetke committed
201
				ImGui::SliderFloat("Exposure", &renderer_settings.exposure_override, 0.f, 50.f);
202

203
204
205
				ImGui::SliderFloat("Min Disp. Lum.", &renderer_settings.min_display_luminance, 1.f, 100.f);
				ImGui::SliderFloat("Max Disp. Lum.", &renderer_settings.max_display_luminance, 1.f, 1000.f);

Florian Oetke's avatar
Florian Oetke committed
206
207
				ImGui::SliderFloat(
				        "Background Brightness", &renderer_settings.background_intensity, 0.f, 10.f);
208

Florian Oetke's avatar
Florian Oetke committed
209
				ImGui::Checkbox("Ambient Occlusion", &renderer_settings.ssao);
210

Florian Oetke's avatar
Florian Oetke committed
211
				ImGui::Checkbox("Bloom", &renderer_settings.bloom);
212

Florian Oetke's avatar
Florian Oetke committed
213
				ImGui::Checkbox("Tonemapping", &renderer_settings.tonemapping);
Florian Oetke's avatar
Florian Oetke committed
214

Florian Oetke's avatar
Florian Oetke committed
215
				ImGui::Checkbox("Depth of Field", &renderer_settings.depth_of_field);
216
217


Florian Oetke's avatar
Florian Oetke committed
218
				if(ImGui::Button("Apply")) {
219
220
221
222
223
224
					apply_window_changed();
					_factory.settings(renderer_settings, true);
				} else {
					_factory.settings(renderer_settings, false);
				}

Florian Oetke's avatar
Florian Oetke committed
225
				if(ImGui::Button("Reset")) {
226
227
228
					_factory.settings(renderer::Renderer_settings{}, true);
				}
			}
Florian Oetke's avatar
Florian Oetke committed
229
			ImGui::End();
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
		}

		void apply_window_changed()
		{
			if(_window_width != _window.width() || _window_height != _window.height()
			   || _window_fullscreen != (_window.fullscreen() != graphic::Fullscreen::no)) {
				_window.dimensions(_window_width,
				                   _window_height,
				                   _window_fullscreen ? graphic::Fullscreen::yes_borderless
				                                      : graphic::Fullscreen::no);
			}
		}

	  private:
		Deferred_renderer_factory& _factory;
		graphic::Window&           _window;

		int  _window_width;
		int  _window_height;
		bool _window_fullscreen;
	};

} // namespace mirrage::renderer