summaryrefslogtreecommitdiffstats
path: root/src/runtime/dragon/qdragonrenderaspect.cpp
blob: e6d57c0dfb4921cf9a2a2c0c542d632d06fa76cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of Qt 3D Studio.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qdragonrenderaspect_p.h"

// General
#include <private/dragonrenderer_p.h>

// Frontend nodes
#include <Qt3DRender/QAbstractTexture>
#include <Qt3DRender/QAbstractTextureImage>
#include <Qt3DRender/QBuffer>
#include <Qt3DRender/qabstractlight.h>
#include <Qt3DRender/qattribute.h>
#include <Qt3DRender/qblitframebuffer.h>
#include <Qt3DRender/qbuffer.h>
#include <Qt3DRender/qbuffercapture.h>
#include <Qt3DRender/qcamera.h>
#include <Qt3DRender/qcameralens.h>
#include <Qt3DRender/qcameraselector.h>
#include <Qt3DRender/qclearbuffers.h>
#include <Qt3DRender/qcomputecommand.h>
#include <Qt3DRender/qdispatchcompute.h>
#include <Qt3DRender/qeffect.h>
#include <Qt3DRender/qenvironmentlight.h>
#include <Qt3DRender/qfrustumculling.h>
#include <Qt3DRender/qgeometry.h>
#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DRender/qlayer.h>
#include <Qt3DRender/qlayerfilter.h>
#include <Qt3DRender/qlevelofdetail.h>
#include <Qt3DRender/qlevelofdetailswitch.h>
#include <Qt3DRender/qmaterial.h>
#include <Qt3DRender/qmemorybarrier.h>
#include <Qt3DRender/qmesh.h>
#include <Qt3DRender/qnodraw.h>
#include <Qt3DRender/qobjectpicker.h>
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/qproximityfilter.h>
#include <Qt3DRender/qraycaster.h>
#include <Qt3DRender/qrendercapture.h>
#include <Qt3DRender/qrenderpass.h>
#include <Qt3DRender/qrenderpassfilter.h>
#include <Qt3DRender/qrendersettings.h>
#include <Qt3DRender/qrenderstateset.h>
#include <Qt3DRender/qrendersurfaceselector.h>
#include <Qt3DRender/qrendertarget.h>
#include <Qt3DRender/qtechnique.h>
#include <Qt3DRender/qrendertargetselector.h>
#include <Qt3DRender/qsceneloader.h>
#include <Qt3DRender/qscreenraycaster.h>
#include <Qt3DRender/qshaderdata.h>
#include <Qt3DRender/qshaderprogrambuilder.h>
#include <Qt3DRender/qtechniquefilter.h>
#include <Qt3DRender/qtexture.h>
#include <Qt3DRender/qviewport.h>
#include <Qt3DQuickScene2D/qscene2d.h>

// Frame graph nodes
#include <private/dragonblitframebuffer_p.h>
#include <private/dragonbuffercapture_p.h>
#include <private/dragoncameraselectornode_p.h>
#include <private/dragonclearbuffers_p.h>
#include <private/dragondispatchcompute_p.h>
#include <private/dragonfrustumculling_p.h>
#include <private/dragonlayerfilternode_p.h>
#include <private/dragonmemorybarrier_p.h>
#include <private/dragonnodraw_p.h>
#include <private/dragonproximityfilter_p.h>
#include <private/dragonrendercapture_p.h>
#include <private/dragonrenderpassfilternode_p.h>
#include <private/dragonrendersurfaceselector_p.h>
#include <private/dragonrendertargetselectornode_p.h>
#include <private/dragonsortpolicy_p.h>
#include <private/dragonstatesetnode_p.h>
#include <private/dragontechniquefilternode_p.h>
#include <private/dragonviewportnode_p.h>
#include <private/dragonscene2d_p.h>

// Jobs
#include <private/dragontransformjobs_p.h>
#include <private/dragonboundingvolumejobs_p.h>

// Qt3DCore
#include <Qt3DCore/QAspectJob>
#include <Qt3DCore/QBackendNodeMapper>
#include <Qt3DCore/QEntity>
#include <Qt3DCore/QNodeCreatedChangeBasePtr>
#include <Qt3DCore/QNodeId>
#include <Qt3DCore/QTransform>

// Qt Core
#include <QQueue>
#include <QtConcurrentRun>

// redefines MemoryBarrier
#include <private/dragonframegraphnode_p.h>

#if defined(_MSC_VER)
#pragma warning(disable : 4503)
#endif

using namespace Qt3DCore;

/*!
\internal
QDragonRenderAspect is an experimental render aspect written in a somewhat functional programming
style with a goal of improving performance and safety. It introduces:

- A task system that wraps around QAspectJob and functions. It makes dependencies explicit and
verified at compile time, and automates passing results from one task to the next.
It also simplifies caching results between frames.
- An immutable/copy-on-write wrapper around backend objects. This is introduced to simplify
data sharing between different threads and improve safety.
- A new container with convenience functions for iterating over new, dirty and removed objects.
This is introduced to simplify tracking the dirty state of frontend objects, through their backend
representation, towards loading data in memory and finally onto the CPU.

This render aspect supports the features needed by Qt3D Studio Runtime,
but lacks some of the features currently present in Qt3D.
This is the reason why it is currently being developed in qt3d-runtime.
Once feature complete, it can be ported back to Qt3D as the default render aspect.

The render aspect is based on the following principles,
which are meant to be broken (but try not to):

- Jobs should only receive copies or const references to immutable data.
- Jobs should have no access to outside state (no pointers to Renderer* or resource managers).
- Jobs should be functions and not functors.

The design has some benefits:

- No shared state between jobs.
- Gets rid of the generator concept by simplifying loading of textures in jobs.

The design also has some caveats or challenges:

- The copy-on-write strategy makes it hard to see exactly where a copy is made, except at runtime.
  However, this can be alleviated by adding debug assertions that try to detect and warn about
  unintentional copying.
- Resource handlers, such as GLBuffer, should not be copyable and need to be changed during the
  course of an application. This means that neither an immutable nor copy-on-write strategy is
  suitable. We therefore introduced Mutable, which is a type that explicitly gets invalidated
  if another copy (reference) to the same resource is changed. This makes it easier to detect
  use of a changed resource by error.

# TODO #

- Add shim-functions for all QOpenGLFunctions calls so that we can create unit tests
  that verify the OpenGL-ish output (before the functions are translated into real functions,
  which of course would change with time).
- Consider using the new change distribution system, while we're at it
- Fix issue with "QAbstractTextureImage was shared", might need to become able
able to collect changes for change arbiter at construction time. (Perhaps solved with new change
system?)
- skinning palette
- render capture
- buffer capture
*/

QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Dragon {

QDragonRenderAspect::QDragonRenderAspect(Renderer::RenderType renderType)
    : m_renderer(new Renderer(renderType))
{
    qDebug() << "Dragon render aspect enabled";

    registerBackendType<Qt3DCore::QEntity>(m_entities);
    registerBackendType<Qt3DCore::QTransform>(m_transforms);
    registerBackendType<QAbstractTexture>(m_textures);
    registerBackendType<QAbstractTextureImage>(m_textureImages);
    registerBackendType<QAttribute>(m_attributes);
    registerBackendType<QBuffer>(m_buffers);
    registerBackendType<QCameraLens>(m_cameraLenses);
    registerBackendType<QRenderTarget>(m_renderTargets);
    registerBackendType<QRenderTargetOutput>(m_renderTargetOutputs);
    registerBackendType<QGeometry>(m_geometries);
    registerBackendType<QGeometryRenderer>(m_geometryRenderers);
    registerBackendType<QRenderPass>(m_renderPasses);
    registerBackendType<QParameter>(m_parameters);
    registerBackendType<QEffect>(m_effects);
    registerBackendType<QMaterial>(m_materials);
    registerBackendType<QTechnique>(m_techniques);
    registerBackendType<QFilterKey>(m_filterKeys);
    registerBackendType<QShaderData>(m_shaderDatas);
    registerBackendType<QShaderProgram>(m_shaders);
    registerBackendType<QRenderState>(m_renderStates);
    registerBackendType<Quick::QScene2D>(m_scene2ds);

    // Custom functors
    registerBackendType<QRenderSettings>(QSharedPointer<RenderSettingsFunctor>::create(this));

    // Framegraph
    registerBackendType<QFrameGraphNode>(
            NodeFunctorPtr<FrameGraphNode, FrameGraphNode>::create(&m_frameGraphNodesContainer));
    registerBackendType<QCameraSelector>(
            NodeFunctorPtr<FrameGraphNode, CameraSelector>::create(&m_frameGraphNodesContainer));
    registerBackendType<QClearBuffers>(
            NodeFunctorPtr<FrameGraphNode, ClearBuffers>::create(&m_frameGraphNodesContainer));
    registerBackendType<QDispatchCompute>(
            NodeFunctorPtr<FrameGraphNode, DispatchCompute>::create(&m_frameGraphNodesContainer));
    registerBackendType<QFrustumCulling>(
            NodeFunctorPtr<FrameGraphNode, FrustumCulling>::create(&m_frameGraphNodesContainer));
    registerBackendType<QLayerFilter>(
            NodeFunctorPtr<FrameGraphNode, LayerFilterNode>::create(&m_frameGraphNodesContainer));
    registerBackendType<QNoDraw>(
            NodeFunctorPtr<FrameGraphNode, NoDraw>::create(&m_frameGraphNodesContainer));
    registerBackendType<QRenderPassFilter>(
            NodeFunctorPtr<FrameGraphNode, RenderPassFilter>::create(&m_frameGraphNodesContainer));
    registerBackendType<QRenderStateSet>(
            NodeFunctorPtr<FrameGraphNode, StateSetNode>::create(&m_frameGraphNodesContainer));
    registerBackendType<QRenderSurfaceSelector>(
            NodeFunctorPtr<FrameGraphNode, RenderSurfaceSelector>::create(&m_frameGraphNodesContainer));
    registerBackendType<QRenderTargetSelector>(
            NodeFunctorPtr<FrameGraphNode, RenderTargetSelector>::create(&m_frameGraphNodesContainer));
    registerBackendType<QSortPolicy>(
            NodeFunctorPtr<FrameGraphNode, SortPolicy>::create(&m_frameGraphNodesContainer));
    registerBackendType<QTechniqueFilter>(
            NodeFunctorPtr<FrameGraphNode, TechniqueFilter>::create(&m_frameGraphNodesContainer));
    registerBackendType<QViewport>(
            NodeFunctorPtr<FrameGraphNode, ViewportNode>::create(&m_frameGraphNodesContainer));
    registerBackendType<QRenderCapture>(
            NodeFunctorPtr<FrameGraphNode, RenderCapture>::create(&m_frameGraphNodesContainer));
    registerBackendType<QBufferCapture>(
            NodeFunctorPtr<FrameGraphNode, BufferCapture>::create(&m_frameGraphNodesContainer));

    // TODO add this back when MemoryBarrier is expanded correctly on MinGW...
//    registerBackendType<QMemoryBarrier>(
//            NodeFunctorPtr<FrameGraphNode, MemoryBarrier>::create(&m_frameGraphNodesContainer));

    registerBackendType<QProximityFilter>(
            NodeFunctorPtr<FrameGraphNode, ProximityFilter>::create(&m_frameGraphNodesContainer));
    registerBackendType<QBlitFramebuffer>(
            NodeFunctorPtr<FrameGraphNode, BlitFramebuffer>::create(&m_frameGraphNodesContainer));

    // TODO could be done in header or initializer
    // TODO syntax could be improved, consider adding a createEdge/setInput function

    m_calculateWorldTransforms = TaskPtr<ValueContainer<Matrix4x4>>::create(
            calculateWorldTransforms, Self, m_entities, m_transforms, m_rootEntitySource);

    m_calculateLocalBoundingVolumes = TaskPtr<LocalBoundingVolumes>::create(
                calculateLocalBoundingVolumes, Self, m_entities, m_attributes,
                m_geometryRenderers, m_geometries, m_buffers);

    m_calculateWorldBoundingVolumes = TaskPtr<WorldBoundingVolumes>::create(
                calculateWorldBoundingVolumes, Self, m_calculateLocalBoundingVolumes,
                m_calculateWorldTransforms);

    m_printTransforms = TaskPtr<int>::create(printTransforms, m_calculateWorldTransforms);

    m_loadTextureImages = TaskPtr<LoadedTextureImages>::create(loadTextureImages,
                                                               Self,
                                                               m_textureImages);

    m_loadTextures = TaskPtr<LoadedTextures>::create(loadTextures,
                                                     Self,
                                                     m_textures,
                                                     m_loadTextureImages);

    m_updateScene2Ds = TaskPtr<ValueContainer<Scene2DState>>::create(updateScene2Ds,
                                                                     Self,
                                                                     m_scene2ds,
                                                                     m_snaggedTexturesSource,
                                                                     m_renderTargetOutputs,
                                                                     m_shareContextSource);

    // TODO might as well upload them as well...
    m_loadBuffers = TaskPtr<LoadedBuffers>::create(loadBuffers, Self, m_buffers);

    //    m_loadShaders = TaskPtr<ValueContainer<GLShader>>::create(uploadShaders, Self, m_shaders);

    m_generateFrameGraph = TaskPtr<TreeInfo>::create(generateInheritanceTable<ValueContainer<FrameGraphNode>>,
                                                     Self,
                                                     m_frameGraphNodes,
                                                     m_rootFrameGraphNodeSource);

    m_buildRenderViews = TaskPtr<RenderViews>::create(buildRenderViews,
                                                      Self,
                                                      m_generateFrameGraph,
                                                      m_frameGraphNodes,
                                                      m_entities,
                                                      m_cameraLenses,
                                                      m_renderTargets,
                                                      m_renderTargetOutputs,
                                                      m_renderStates);

    const auto calculateCameraMatrices = [](ValueContainer<CameraMatrices> renderViewCameraMatrices,
                                            RenderViews renderViews,
                                            ValueContainer<Matrix4x4> worldTransforms) {
        const auto cameraMatrixForRenderView = [worldTransforms](QNodeId id, Immutable<RenderView> renderView) {
            Q_UNUSED(id);
            Immutable<Entity> cameraNode = renderView->cameraNode;
            Immutable<CameraLens> cameraLens = renderView->cameraLens;
            CameraMatrices cameraMatrices;
            const Matrix4x4 cameraWorld = Matrix4x4(*(worldTransforms[cameraNode->peerId()]));
            const auto &viewMatrix = cameraLens->viewMatrix(cameraWorld);
            cameraMatrices.viewMatrix = viewMatrix;
            cameraMatrices.viewProjectionMatrix = cameraLens->projectionMatrix() * viewMatrix;

            //To get the eyePosition of the camera, we need to use the inverse of the
            // camera's worldTransform matrix.
            const Matrix4x4 inverseWorldTransform = viewMatrix.inverted();
            const Vector3D eyePosition(inverseWorldTransform.column(3));
            cameraMatrices.eyePosition = eyePosition;

            // Get the viewing direction of the camera. Use the normal matrix to
            // ensure non-uniform scale works too.
            const QMatrix3x3 normalMat = convertToQMatrix4x4(viewMatrix).normalMatrix();
            // dir = normalize(QVector3D(0, 0, -1) * normalMat)
            cameraMatrices.eyeViewDirection = Vector3D(-normalMat(2, 0), -normalMat(2, 1), -normalMat(2, 2)).normalized();

            return cameraMatrices;
        };

        renderViewCameraMatrices = rebuildAll(std::move(renderViewCameraMatrices),
                                              renderViews, cameraMatrixForRenderView);

        return renderViewCameraMatrices;
    };

    auto cameraMatrices = TaskPtr<ValueContainer<CameraMatrices>>::create(calculateCameraMatrices,
                                                                          Self,
                                                                          m_buildRenderViews,
                                                                          m_calculateWorldTransforms);

    auto requestContextInfoFunction = [this](GraphicsApiFilterData previous,
                                             const RenderViews &renderViews) {
        if (previous.m_major != 0) {
            // no need to do this every frame ;)
            // TODO use a better "flag" than the major version
            return previous;
        }
        auto result = m_renderer->contextInfo(renderViews);
        return result;
    };

    m_requestContextInfo = TaskPtr<GraphicsApiFilterData>::create(requestContextInfoFunction,
                                                                  Self,
                                                                  m_buildRenderViews);

    m_gatherParameters = TaskPtr<GatheredParameters>::create(gatherMaterialParameters,
                                                             Self,
                                                             m_buildRenderViews,
                                                             m_requestContextInfo,
                                                             m_parameters,
                                                             m_materials,
                                                             m_effects,
                                                             m_techniques,
                                                             m_renderPasses,
                                                             m_filterKeys);

    // TODO should filter entities by renderable
    // TODO should filter entities by layer
    // TODO should filter entities by frustum culling
    // TODO should filter entities by proximity

    m_buildRenderCommands = TaskPtr<RenderCommands>::create(buildDrawRenderCommands,
                                                            Self,
                                                            m_buildRenderViews,
                                                            m_entities,
                                                            m_materials,
                                                            m_geometries,
                                                            m_geometryRenderers,
                                                            m_shaders,
                                                            m_renderStates,
                                                            m_gatherParameters);

    //    m_applyParameters = TaskPtr<AppliedRenderCommandss>::create(applyParameters,
    //                                                                Self,
    //                                                                m_buildRenderCommands,
    //                                                                m_calculateWorldTransforms,
    //                                                                m_parameters);

    const auto sortedCommands = TaskPtr<RenderCommands>::create(sortRenderCommands,
                                                                Self,
                                                                m_buildRenderCommands,
                                                                m_calculateWorldBoundingVolumes,
                                                                cameraMatrices);

    // NOTE this is the only job that needs to know about anything external (the Renderer)
    // It would be nice to also make this functional, but I currently have no good solution for
    // this.
    auto uploadRenderViewsFunction = [this](const TreeInfo &frameGraph,
                                            const RenderViews &renderViews,
                                            const RenderCommands &renderCommands,
                                            const LoadedTextures &loadedTextures,
                                            const LoadedBuffers &loadedBuffers,
                                            const ValueContainer<Shader> &shaders,
                                            const ValueContainer<Attribute> &attributes,
                                            const ValueContainer<Parameter> &parameters,
                                            const ValueContainer<Matrix4x4> &worldTransforms,
                                            const ValueContainer<Scene2DState> &scene2ds,
                                            const ValueContainer<CameraMatrices> &renderViewCameraMatrices) {
        // TODO how do we handle incremental changes?
        // TODO if nothing changed, do we really need to upload again?
        FrameInput data;
        data.renderViews = renderViews;
        // TODO consider joining commands and views to avoid having to look up commands based on view id
        data.renderCommands = renderCommands;
        // TODO would also be better to have camera matrices go into the same object as
        // views and commands to reduce lookups on render thread
        data.renderViewCameraMatrices = renderViewCameraMatrices;
        data.loadedTextures = loadedTextures;
        data.loadedBuffers = loadedBuffers;
        data.shaders = shaders;
        data.attributes = attributes;
        data.parameters = parameters;
        data.worldTransforms = worldTransforms;
        data.frameGraph = frameGraph;
        data.scene2ds = scene2ds;
        m_renderer->addLatestData(data);
        return true;
    };

    m_uploadRenderViews = TaskPtr<bool>::create(uploadRenderViewsFunction,
                                                m_generateFrameGraph,
                                                m_buildRenderViews,
                                                sortedCommands,
                                                m_loadTextures,
                                                m_loadBuffers,
                                                m_shaders,
                                                m_attributes,
                                                m_parameters,
                                                m_calculateWorldTransforms,
                                                m_updateScene2Ds,
                                                cameraMatrices);

    // TODO would be nice to have a taskmanager that all the above are put into
    m_jobs = { m_calculateWorldTransforms,
               m_calculateLocalBoundingVolumes,
               m_calculateWorldBoundingVolumes,
               m_printTransforms,
               m_loadTextures,
               m_loadTextureImages,
               m_updateScene2Ds,
               m_loadBuffers,
               m_generateFrameGraph,
               m_buildRenderViews,
               m_gatherParameters,
               m_buildRenderCommands,
               m_uploadRenderViews,
               m_requestContextInfo,
               cameraMatrices,
               sortedCommands };

    // TODO would be nice to automate this in a task-manager as well
    auto resetFunction = [this]() {
        m_entities->reset();
        m_transforms->reset();
        m_textureImages->reset();
        m_textures->reset();
        m_buffers->reset();
        m_geometries->reset();
        m_attributes->reset();
        m_renderPasses->reset();
        m_geometryRenderers->reset();
        m_shaderDatas->reset();
        m_shaders->reset();
        m_renderStates->reset();
        m_materials->reset();
        m_effects->reset();
        m_techniques->reset();
        m_renderPasses->reset();
        m_filterKeys->reset();
        m_parameters->reset();
        m_cameraLenses->reset();
        m_renderTargets->reset();
        m_renderTargetOutputs->reset();
        m_renderStates->reset();
        m_frameGraphNodes->reset();

        return true;
    };

    // TODO a bit annoying that we need this job at all
    m_resetJobs = TaskPtr<bool>::create(resetFunction);
    for (const auto &job : m_jobs) {
        m_resetJobs->addDependency(job);
    }
    m_jobs.append(m_resetJobs);
}

// Waits to be told to create jobs for the next frame
// Called by QRenderAspect jobsToExecute context of QAspectThread
// Returns all the jobs (and with proper dependency chain) required
// for the rendering of the scene
QVector<Qt3DCore::QAspectJobPtr> QDragonRenderAspect::jobsToExecute(qint64 time)
{
    Q_UNUSED(time)

    // TODO remove this once we figure out why the textures need more time...
    if (m_renderSettings == nullptr) {
        qWarning() << "RenderSettings missing. Dragon render aspect not starting.";
        return {};
    }

    m_renderer->nextFrameSemaphore.acquire();

    m_rootFrameGraphNodeSource->setInput(m_renderSettings->activeFrameGraphID());
    m_rootEntitySource->setInput(rootEntityId());
    m_shareContextSource->setInput(m_renderer->shareContext());
    m_snaggedTexturesSource->setInput(&m_renderer->textures());

    // TODO add all to a task container that generates this
    return m_jobs;
}

Renderer::Frame QDragonRenderAspect::renderSynchronous(Renderer::Frame frame)
{
    return m_renderer->doRender(std::move(frame));
}

void QDragonRenderAspect::initialize(QOpenGLContext *context)
{
    m_renderer->initialize(context);
}

void QDragonRenderAspect::beginRenderShutdown()
{
    m_renderer->beginShutdown();
}

void QDragonRenderAspect::endRenderShutdown()
{
    m_renderer->endShutdown();
}

} // namespace Dragon
} // namespace Qt3DRender
QT_END_NAMESPACE