1// Copyright (C) 2017 Juan José Casafranca
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "sendbuffercapturejob_p.h"
5
6#include <Qt3DRender/private/nodemanagers_p.h>
7#include <Qt3DRender/private/job_common_p.h>
8#include <Qt3DRender/private/buffer_p.h>
9#include <Qt3DRender/private/buffermanager_p.h>
10#include <Qt3DCore/private/qaspectmanager_p.h>
11#include <Qt3DCore/private/qbuffer_p.h>
12#include <Qt3DCore/private/vector_helper_p.h>
13
14QT_BEGIN_NAMESPACE
15
16namespace Qt3DRender {
17
18namespace Render {
19
20class SendBufferCaptureJobPrivate : public Qt3DCore::QAspectJobPrivate
21{
22public:
23 SendBufferCaptureJobPrivate() {}
24 ~SendBufferCaptureJobPrivate() {}
25
26 void postFrame(Qt3DCore::QAspectManager *aspectManager) override;
27
28 mutable QMutex m_mutex;
29 QList<QPair<Qt3DCore::QNodeId, QByteArray>> m_buffersToCapture;
30 QList<QPair<Qt3DCore::QNodeId, QByteArray>> m_buffersToNotify;
31};
32
33SendBufferCaptureJob::SendBufferCaptureJob()
34 : Qt3DCore::QAspectJob(*new SendBufferCaptureJobPrivate)
35 , m_nodeManagers(nullptr)
36{
37 SET_JOB_RUN_STAT_TYPE(this, JobTypes::SendBufferCapture, 0)
38}
39
40SendBufferCaptureJob::~SendBufferCaptureJob()
41{
42}
43
44// Called from SubmitRenderView while rendering
45void SendBufferCaptureJob::addRequest(QPair<Qt3DCore::QNodeId, QByteArray> request)
46{
47 Q_D(SendBufferCaptureJob);
48 QMutexLocker locker(&d->m_mutex);
49 d->m_buffersToCapture.push_back(t: request);
50}
51
52// Called by aspect thread jobs to execute (we may still be rendering at this point)
53bool SendBufferCaptureJob::hasRequests() const
54{
55 Q_D(const SendBufferCaptureJob);
56 QMutexLocker locker(&d->m_mutex);
57 return d->m_buffersToCapture.size() > 0;
58}
59
60void SendBufferCaptureJob::run()
61{
62 Q_ASSERT(m_nodeManagers);
63 Q_D(SendBufferCaptureJob);
64 QMutexLocker locker(&d->m_mutex);
65 for (const QPair<Qt3DCore::QNodeId, QByteArray> &pendingCapture : std::as_const(t&: d->m_buffersToCapture)) {
66 Buffer *buffer = m_nodeManagers->bufferManager()->lookupResource(id: pendingCapture.first);
67 // Buffer might have been destroyed between the time addRequest is made and this job gets run
68 // If it exists however, it cannot be destroyed before this job is done running
69 if (buffer != nullptr)
70 buffer->updateDataFromGPUToCPU(data: pendingCapture.second);
71 }
72 d->m_buffersToNotify = Qt3DCore::moveAndClear(data&: d->m_buffersToCapture);
73}
74
75void SendBufferCaptureJobPrivate::postFrame(Qt3DCore::QAspectManager *aspectManager)
76{
77 QMutexLocker locker(&m_mutex);
78 const QList<QPair<Qt3DCore::QNodeId, QByteArray>> pendingSendBufferCaptures = Qt3DCore::moveAndClear(data&: m_buffersToNotify);
79 for (const auto &bufferDataPair : pendingSendBufferCaptures) {
80 Qt3DCore::QBuffer *frontendBuffer = static_cast<decltype(frontendBuffer)>(aspectManager->lookupNode(id: bufferDataPair.first));
81 if (!frontendBuffer)
82 continue;
83 Qt3DCore::QBufferPrivate *dFrontend = static_cast<decltype(dFrontend)>(Qt3DCore::QNodePrivate::get(q: frontendBuffer));
84 // Calling frontendBuffer->setData would result in forcing a sync against the backend
85 // which isn't necessary
86 dFrontend->setData(bufferDataPair.second);
87 Q_EMIT frontendBuffer->dataAvailable();
88 }
89}
90
91} // Render
92
93} // Qt3DRender
94
95QT_END_NAMESPACE
96

source code of qt3d/src/render/jobs/sendbuffercapturejob.cpp