Unravel Engine C++ Reference
Loading...
Searching...
No Matches
renderer.cpp
Go to the documentation of this file.
1#include "renderer.h"
2#include "eviction_settings.h"
3#include "../events.h"
4#include "spdlog/common.h"
5#include "gpu_program.h"
8
9#include <base/assert.hpp>
10#include <graphics/debugdraw.h>
11#include <graphics/graphics.h>
13
14#include <logging/logging.h>
15
16#include <cstdint>
17#include <vector>
18
19namespace unravel
20{
21namespace
22{
23thread_local std::vector<uint32_t> s_bgfx_profiler_scope_stack;
24}
25
27{
29 [](const std::string& msg, const char* file_path, uint16_t line)
30 {
31 APPLOG_DEBUG_LOC(file_path, line, "renderer", msg);
32 });
34 [](const std::string& msg, const char* file_path, uint16_t line)
35 {
36 APPLOG_TRACE_LOC(file_path, line, "renderer", msg);
37 });
39 [](const std::string& msg, const char* file_path, uint16_t line)
40 {
41 APPLOG_INFO_LOC(file_path, line, "renderer", msg);
42 });
44 [](const std::string& msg, const char* file_path, uint16_t line)
45 {
46 APPLOG_WARNING_LOC(file_path, line, "renderer", msg);
47 });
49 [](const std::string& msg, const char* file_path, uint16_t line)
50 {
51 APPLOG_ERROR_LOC(file_path, line, "renderer", msg);
52 });
53
54 auto main_thread_id = std::this_thread::get_id();
56 [main_thread_id](const char* name, uint32_t abgr, const char* file_path, uint16_t line)
57 {
58 (void)abgr;
59 (void)file_path;
60 (void)line;
61 if(name == nullptr)
62 {
63 return;
64 }
65 auto current_id = std::this_thread::get_id();
66 if(current_id != main_thread_id)
67 {
68 s_bgfx_profiler_scope_stack.push_back(
69 profile_begin_owned(hpp::string_view(name), "Render Thread"));
70 }
71 else
72 {
73 s_bgfx_profiler_scope_stack.push_back(
74 profile_begin_owned(hpp::string_view(name)));
75 }
76 },
77 [main_thread_id](const char* name, uint32_t abgr, const char* file_path, uint16_t line)
78 {
79 (void)abgr;
80 (void)file_path;
81 (void)line;
82 if(name == nullptr)
83 {
84 return;
85 }
86 auto current_id = std::this_thread::get_id();
87 if(current_id != main_thread_id)
88 {
89 s_bgfx_profiler_scope_stack.push_back(
90 profile_begin_owned(hpp::string_view(name), "Render Thread"));
91 }
92 else
93 {
94 s_bgfx_profiler_scope_stack.push_back(profile_begin(name));
95 }
96 },
97 []()
98 {
99 if(s_bgfx_profiler_scope_stack.empty())
100 {
101 return;
102 }
103 const uint32_t token = s_bgfx_profiler_scope_stack.back();
104 s_bgfx_profiler_scope_stack.pop_back();
105 if(token != UINT32_MAX)
106 {
108 }
109 });
110 get_thread_profile_data("Main Thread");
111
112 auto& ev = ctx.get_cached<events>();
113 ev.on_os_event.connect(sentinel_, this, &renderer::on_os_event);
114 ev.on_frame_begin.connect(sentinel_, this, &renderer::frame_begin);
115 ev.on_frame_end.connect(sentinel_, this, &renderer::frame_end);
116
117 parser.set_optional<std::string>("r", "renderer", "auto", "Select preferred renderer.");
118 parser.set_optional<bool>("n", "novsync", false, "Disable vsync.");
119}
120
121auto renderer::init(rtti::context& ctx, const cmd_line::parser& parser) -> bool
122{
123 APPLOG_TRACE("{}::{}", hpp::type_name_str(*this), __func__);
124
125 if(!os::init())
126 {
127 return false;
128 }
129
130 if(!init_backend(parser))
131 {
132 return false;
133 }
134
135 return true;
136}
137
138auto renderer::create_window_for_display(int index, const std::string& title, uint32_t flags)
139 -> const std::unique_ptr<render_window>&
140{
141 auto mode = os::display::get_desktop_mode(index);
142 auto bounds = os::display::get_usable_bounds(index);
143
144 if(flags & os::window::resizable)
145 {
146 auto frame_size = init_window_->get_frame_size();
147 bounds.y += static_cast<int>(static_cast<float>(frame_size.top) / mode.display_scale);
148 bounds.h -= static_cast<int>(static_cast<float>(frame_size.top + frame_size.bottom) / mode.display_scale);
149 bounds.x += static_cast<int>(static_cast<float>(frame_size.left) / mode.display_scale);
150 bounds.w -= static_cast<int>(static_cast<float>(frame_size.left + frame_size.right) / mode.display_scale);
151 }
152
153 os::window window(title, bounds.x, bounds.y, bounds.w * mode.display_scale, bounds.h * mode.display_scale, flags);
154
155 set_main_window(std::move(window));
156 return render_window_;
157}
158
159void renderer::set_main_window(os::window&& window)
160{
161 render_window_ = std::make_unique<render_window>(std::move(window));
162}
163
165{
166 APPLOG_TRACE("{}::{}", hpp::type_name_str(*this), __func__);
167 return true;
168}
169
170auto renderer::init_backend(const cmd_line::parser& parser) -> bool
171{
172 init_window_.reset();
173 init_window_ =
174 std::make_unique<os::window>("INIT", os::window::centered, os::window::centered, 64, 64, os::window::hidden);
175 const auto sz = init_window_->get_size();
176
177 gfx::init_type init_data;
178 init_data.type = get_renderer_type(parser);
179 init_data.resolution.width = sz.w;
180 init_data.resolution.height = sz.h;
181 init_data.resolution.reset = get_reset_flags(parser);
182 init_data.platformData.ndt = init_window_->get_native_display();
183 init_data.platformData.nwh = init_window_->get_native_handle();
184 std::string video_driver = os::window::get_current_video_driver();
185 if(video_driver == "wayland")
186 {
187 init_data.platformData.type = bgfx::NativeWindowHandleType::Wayland;
188 }
189 reset_flags_ = init_data.resolution.reset;
190
191 init_data.limits.numDrawCalls = 65536;
192 init_data.limits.numDrawCallPeakFrames = 0;
193
194 if(!gfx::init(init_data))
195 {
196 APPLOG_ERROR("Could not initialize rendering backend!");
197 return false;
198 }
199 APPLOG_TRACE("Using {0} rendering backend.", gfx::get_renderer_name(gfx::get_renderer_type()));
200
201 APPLOG_TRACE("DebugDraw Init.");
202 ddInit();
203
204 const bgfx::Caps* caps = bgfx::getCaps();
205 if (0 != (caps->supported & BGFX_CAPS_GRAPHICS_DEBUGGER) )
206 {
207 APPLOG_TRACE("Graphics debugger is supported.");
208 }
209 else
210 {
211 APPLOG_TRACE("Graphics debugger is not supported.");
212 }
213
214 return true;
215}
216
217void renderer::on_os_event(rtti::context& ctx, os::event& e)
218{
219 if(e.type == os::events::window)
220 {
221 if(e.window.type == os::window_event_id::close)
222 {
223 auto window_id = e.window.window_id;
225 {
226 if(render_window_->get_window().get_id() == window_id)
227 {
229 }
230 }
231 }
232
233 if(e.window.type == os::window_event_id::resized)
234 {
235 auto window_id = e.window.window_id;
236
238 {
239 if(render_window_->get_window().get_id() == window_id)
240 {
241 render_window_->prepare_surface();
242 }
243 }
244 }
245 }
246}
247
249{
250 // auto detect
251 auto preferred_renderer_type = gfx::renderer_type::Count;
252
253 std::string preferred_renderer;
254 if(parser.try_get("renderer", preferred_renderer))
255 {
256 if(preferred_renderer == "opengl")
257 {
258 preferred_renderer_type = gfx::renderer_type::OpenGL;
259 }
260 else if(preferred_renderer == "vulkan")
261 {
262 preferred_renderer_type = gfx::renderer_type::Vulkan;
263 }
264 else if(preferred_renderer == "directx11" || preferred_renderer == "direct3d11" || preferred_renderer == "dx11")
265 {
266 preferred_renderer_type = gfx::renderer_type::Direct3D11;
267 }
268 else if(preferred_renderer == "directx12" || preferred_renderer == "direct3d12" || preferred_renderer == "dx12")
269 {
270 preferred_renderer_type = gfx::renderer_type::Direct3D12;
271 }
272 }
273
274 return preferred_renderer_type;
275}
276
277auto renderer::get_reset_flags(const cmd_line::parser& parser) const -> uint32_t
278{
279 bool novsync = false;
280 parser.try_get("novsync", novsync);
281 return get_reset_flags(!novsync);
282}
283
284auto renderer::get_reset_flags(bool vsync) const -> uint32_t
285{
286 uint32_t flags = BGFX_RESET_MAXANISOTROPY | BGFX_RESET_HIDPI;
287
288 if(vsync)
289 {
290 flags |= BGFX_RESET_VSYNC;
291 }
292 else
293 {
294 flags |= BGFX_RESET_NONE;
295 }
296
297 return flags;
298}
299
301{
302 render_window_.reset();
303
304 gfx::set_trace_logger(nullptr);
305 gfx::set_info_logger(nullptr);
307 gfx::set_error_logger(nullptr);
308
309 ddShutdown();
311
312 init_window_.reset();
313 os::shutdown();
314}
315
317{
318 return render_window_.get();
319}
320
322{
323 render_window_.reset();
324}
325
326void renderer::request_screenshot(const std::string& file)
327{
328 request_screenshot_ = file;
329}
330
331auto renderer::get_vsync() const -> bool
332{
333 return (reset_flags_ & BGFX_RESET_VSYNC) != 0;
334}
335void renderer::set_vsync(bool vsync)
336{
337 if(vsync)
338 {
339 reset_flags_ |= BGFX_RESET_VSYNC;
340 }
341 else
342 {
343 reset_flags_ &= ~BGFX_RESET_VSYNC;
344 }
345
346 const auto sz = init_window_->get_size();
347
348 gfx::reset(sz.w, sz.h, reset_flags_);
349}
350
352{
353 // Drive GPU eviction at the start of the frame, before this frame's resource creates are
354 // submitted, so freed memory precedes new allocations in bgfx's command stream (lowers peak
355 // usage). Runs on the render thread, independently of the editor, using the policy persisted in
356 // the project's graphics settings (a no-op until a settings instance exists).
357 if(ctx.has<settings>())
358 {
360 }
361
362 auto window = get_main_window();
363 if(window)
364 {
365 auto& pass = window->begin_present_pass();
366 pass.clear();
367 }
368}
369
371{
372 APP_SCOPE_PERF("Graphics Frame Submit");
373
374 gfx::render_pass pass(gfx::render_pass::get_max_pass_id(), "Backbuffer/Update Pass");
375 pass.bind();
376
377 gfx::frame();
378
379 if(!request_screenshot_.empty())
380 {
381 gfx::request_screen_shot(get_main_window()->get_surface()->native_handle(), request_screenshot_.c_str());
383 }
384
386}
387
388} // namespace unravel
void set_optional(const std::string &name, const std::string &alternative, T defaultValue, const std::string &description="", bool dominant=false)
Definition parser.h:303
std::chrono::duration< float > delta_t
const char * title
uint16_t index
std::string name
Definition hub.cpp:33
#define APPLOG_ERROR(...)
Definition logging.h:20
#define APPLOG_INFO_LOC(FILE_LOC, LINE_LOC, FUNC_LOC,...)
Definition logging.h:34
#define APPLOG_DEBUG_LOC(FILE_LOC, LINE_LOC, FUNC_LOC,...)
Definition logging.h:30
#define APPLOG_WARNING_LOC(FILE_LOC, LINE_LOC, FUNC_LOC,...)
Definition logging.h:36
#define APPLOG_ERROR_LOC(FILE_LOC, LINE_LOC, FUNC_LOC,...)
Definition logging.h:38
#define APPLOG_TRACE_LOC(FILE_LOC, LINE_LOC, FUNC_LOC,...)
Definition logging.h:32
#define APPLOG_TRACE(...)
Definition logging.h:17
bgfx::Init init_type
Definition graphics.h:19
renderer_type get_renderer_type()
Definition graphics.cpp:440
void shutdown()
Definition graphics.cpp:279
bool init(init_type init_data)
Definition graphics.cpp:312
void set_info_logger(const std::function< void(const std::string &, const char *, uint16_t)> &logger)
Definition graphics.cpp:58
uint32_t frame(uint8_t _flags)
Definition graphics.cpp:432
void set_debug_logger(const std::function< void(const std::string &, const char *, uint16_t)> &logger)
Definition graphics.cpp:53
const char * get_renderer_name(renderer_type _type)
Definition graphics.cpp:412
void reset(uint32_t _width, uint32_t _height, uint32_t _flags)
Definition graphics.cpp:417
void request_screen_shot(frame_buffer_handle _handle, const char *_filePath)
void set_warning_logger(const std::function< void(const std::string &, const char *, uint16_t)> &logger)
Definition graphics.cpp:62
void set_trace_logger(const std::function< void(const std::string &, const char *, uint16_t)> &logger)
Definition graphics.cpp:48
void set_profiler_hooks(gfx_profiler_begin_hook on_begin, gfx_profiler_begin_literal_hook on_begin_literal, gfx_profiler_end_hook on_end)
Definition graphics.cpp:256
bgfx::RendererType::Enum renderer_type
Definition graphics.h:21
void set_error_logger(const std::function< void(const std::string &, const char *, uint16_t)> &logger)
Definition graphics.cpp:66
auto profile_begin(const char *name) -> uint32_t
Begin a profiling scope. Returns an event index for profile_end().
Definition profiler.h:431
void profile_end(uint32_t idx)
End a profiling scope started by profile_begin().
Definition profiler.h:564
auto get_thread_profile_data() -> thread_profile_data *
Definition profiler.h:410
auto profile_begin_owned(hpp::string_view name) -> uint32_t
Like profile_begin() but copies the label into name_owned (script / dynamic names).
Definition profiler.h:498
void update_eviction(const eviction_settings &settings)
#define APP_SCOPE_PERF(name_literal)
Create a scoped performance timer that records to the timeline profiler. Only accepts string literals...
Definition profiler.h:675
static void reset()
static auto get_max_pass_id() -> gfx::view_id
void bind(const frame_buffer *fb=nullptr) const
auto get_cached() -> T &
Definition context.hpp:49
auto has() const -> bool
Definition context.hpp:28
auto get() -> T &
Definition context.hpp:35
hpp::event< void(rtti::context &, os::event &e)> on_os_event
os events
Definition events.h:35
Struct representing a render window.
auto get_reset_flags(const cmd_line::parser &parser) const -> uint32_t
Definition renderer.cpp:277
std::string request_screenshot_
Definition renderer.h:51
void frame_begin(rtti::context &ctx, delta_t dt)
Definition renderer.cpp:351
auto get_renderer_type(const cmd_line::parser &parser) const -> gfx::renderer_type
Definition renderer.cpp:248
uint32_t reset_flags_
Definition renderer.h:47
auto init_backend(const cmd_line::parser &parser) -> bool
Definition renderer.cpp:170
std::unique_ptr< render_window > render_window_
Definition renderer.h:50
std::unique_ptr< os::window > init_window_
engine windows
Definition renderer.h:49
void on_os_event(rtti::context &ctx, os::event &e)
Definition renderer.cpp:217
auto deinit(rtti::context &ctx) -> bool
Definition renderer.cpp:164
void frame_end(rtti::context &ctx, delta_t dt)
Definition renderer.cpp:370
auto get_vsync() const -> bool
Definition renderer.cpp:331
std::shared_ptr< int > sentinel_
Definition renderer.h:53
void request_screenshot(const std::string &file)
Definition renderer.cpp:326
renderer(rtti::context &ctx, cmd_line::parser &parser)
Definition renderer.cpp:26
auto init(rtti::context &ctx, const cmd_line::parser &parser) -> bool
Definition renderer.cpp:121
void set_vsync(bool vsync)
Definition renderer.cpp:335
void close_main_window()
Definition renderer.cpp:321
void set_main_window(os::window &&window)
Definition renderer.cpp:159
auto create_window_for_display(int index, const std::string &title, uint32_t flags) -> const std::unique_ptr< render_window > &
Definition renderer.cpp:138
auto get_main_window() const -> render_window *
Definition renderer.cpp:316
struct unravel::settings::graphics_settings graphics
void ddShutdown()
void ddInit(bx::AllocatorI *_allocator)
std::string token