4 #include "renderthread.h" 6 #include "../annotations/scene.h" 7 #include "../core/bagplayer.h" 8 #include "../core/loader.h" 9 #include "../core/log.h" 10 #include "../core/profiler.h" 11 #include "../core/topic.h" 12 #include "../core/workspace.h" 13 #include "../render/renderer.h" 14 #include "../render/resource.h" 15 #include "../render/shader.h" 16 #include "renderwindow.h" 18 RenderThread::RenderThread() {
20 _thread = std::thread([
this]() { run(); });
23 void RenderThread::invalidate() {
25 std::unique_lock<std::mutex> lock(_mutex);
27 _condition.notify_all();
30 void RenderThread::run() {
31 LOG_DEBUG(
"render thread started");
33 QOffscreenSurface offscreen_surface;
34 offscreen_surface.create();
35 if (!offscreen_surface.isValid()) {
36 throw std::runtime_error(
"failed to create offscreen surface");
39 QOpenGLContext offscreen_context;
40 offscreen_context.setShareContext(QOpenGLContext::globalShareContext());
41 if (!offscreen_context.create()) {
42 throw std::runtime_error(
"failed to create offscreen context");
45 offscreen_context.makeCurrent(&offscreen_surface);
47 std::vector<std::function<void()>> garbage_list;
48 std::mutex garbage_mutex;
49 ResourceBase::setCleanupFunction([&](
const std::function<
void()> &garbage) {
50 std::lock_guard<std::mutex> lock(garbage_mutex);
51 garbage_list.push_back(garbage);
53 std::vector<std::shared_ptr<RenderWindowBase>> render_window_list;
54 std::vector<std::shared_ptr<Display>> display_list;
55 std::vector<std::shared_ptr<SceneAnnotationBase>> scene_annotations;
62 std::unique_lock<std::mutex> lock(_mutex);
71 _condition.wait(lock);
85 ws->recurse([&render_window_list,
86 &display_list](
const std::shared_ptr<Object> &
object) {
88 if (
auto render_window =
89 std::dynamic_pointer_cast<RenderWindowBase>(
object)) {
90 render_window_list.push_back(render_window);
92 if (
auto display = std::dynamic_pointer_cast<Display>(
object)) {
93 display_list.push_back(display);
98 std::lock_guard<std::mutex> lock(garbage_mutex);
99 for (
auto &f : garbage_list) {
102 garbage_list.clear();
106 render_context.render_list = &render_list;
107 ws->document()->display()->renderSyncRecursive(render_context);
110 scene_annotations.clear();
111 if (ws->player && ws->document()->timeline()) {
112 auto current_time = ws->player->time();
113 for (
auto &track : ws->document()->timeline()->tracks()) {
114 if (
auto annotation_track =
115 std::dynamic_pointer_cast<AnnotationTrack>(track)) {
116 if (
auto branch = annotation_track->branch(ws(),
false)) {
117 for (
auto &span : branch->spans()) {
118 if (span->start() <= current_time &&
119 span->start() + span->duration() >= current_time) {
120 for (
auto &annotation : span->annotations()) {
121 if (
auto scene_annotation =
122 std::dynamic_pointer_cast<SceneAnnotationBase>(
126 render_context.render_list = &render_list;
127 scene_annotation->renderSync(render_context, track,
130 scene_annotations.push_back(scene_annotation);
140 for (
auto &render_window : render_window_list) {
142 render_window->renderWindowSync(render_context);
147 render_context.render_list = &render_list;
148 for (
auto &display : display_list) {
149 display->renderAsync(render_context);
151 for (
auto &scene_annotation : scene_annotations) {
152 scene_annotation->renderAsync(render_context);
157 for (
auto &render_window : render_window_list) {
159 render_context.render_list = &render_list;
160 render_context.renderer = &renderer;
161 render_window->renderWindowAsync(render_context);
163 for (
auto &render_window : render_window_list) {
164 startOnMainThreadAsync([render_window]() { render_window->present(); });
169 for (
auto &display : display_list) {
170 if (display.unique()) {
171 auto ref = std::make_shared<std::shared_ptr<Display>>(display);
172 auto lambda = [ref]() {
178 startOnMainThreadAsync(lambda);
181 display_list.clear();
184 for (
auto &render_window : render_window_list) {
185 if (render_window.unique()) {
186 auto ref = std::make_shared<std::shared_ptr<RenderWindowBase>>(
188 auto lambda = [ref]() {
193 render_window.reset();
194 startOnMainThreadAsync(lambda);
197 render_window_list.clear();
201 offscreen_context.doneCurrent();
202 ResourceBase::setCleanupFunction(
nullptr);
205 void RenderThread::stop() {
208 LOG_DEBUG(
"stopping render thread");
210 std::unique_lock<std::mutex> lock(_mutex);
212 _condition.notify_all();
215 LOG_DEBUG(
"render thread stopped");
219 RenderThread::~RenderThread() { stop(); }
222 static std::shared_ptr<RenderThread> instance = []() {
223 auto instance = std::make_shared<RenderThread>();
227 ws->modified.connect(instance, [ptr]() { ptr->invalidate(); });
228 GlobalEvents::instance()->redraw.connect(instance,
229 [ptr]() { ptr->invalidate(); });
231 LoaderThread::instance()->started.connect(instance,
232 [ptr]() { ptr->invalidate(); });
233 LoaderThread::instance()->finished.connect(instance,
234 [ptr]() { ptr->invalidate(); });
235 TopicManager::instance()->received.connect(instance,
236 [ptr]() { ptr->invalidate(); });
239 return instance.get();