1// Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
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 "buffer_p.h"
5#include <Qt3DCore/private/qbuffer_p.h>
6#include <Qt3DRender/private/buffermanager_p.h>
7
8QT_BEGIN_NAMESPACE
9
10namespace Qt3DRender {
11namespace Render {
12
13Buffer::Buffer()
14 : BackendNode(QBackendNode::ReadWrite)
15 , m_usage(Qt3DCore::QBuffer::StaticDraw)
16 , m_bufferDirty(false)
17 , m_access(Qt3DCore::QBuffer::Write)
18 , m_manager(nullptr)
19{
20 // Maybe it could become read write if we want to inform
21 // the frontend QBuffer node of any backend issue
22}
23
24Buffer::~Buffer()
25{
26}
27
28void Buffer::cleanup()
29{
30 m_usage = Qt3DCore::QBuffer::StaticDraw;
31 m_data.clear();
32 m_bufferUpdates.clear();
33 m_bufferDirty = false;
34 m_access = Qt3DCore::QBuffer::Write;
35}
36
37
38void Buffer::setManager(BufferManager *manager)
39{
40 m_manager = manager;
41}
42
43//Called from th sendBufferJob
44void Buffer::updateDataFromGPUToCPU(QByteArray data)
45{
46 // Note: when this is called, data is what's currently in GPU memory
47 // so m_data shouldn't be reuploaded
48 m_data = data;
49}
50
51void Buffer::forceDataUpload()
52{
53 // We push back an update with offset = -1
54 // As this is the way to force data to be loaded
55 Qt3DCore::QBufferUpdate updateNewData;
56 updateNewData.offset = -1;
57 m_bufferUpdates.clear(); //previous updates are pointless
58 m_bufferUpdates.push_back(x: updateNewData);
59}
60
61void Buffer::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
62{
63 BackendNode::syncFromFrontEnd(frontEnd, firstTime);
64 const Qt3DCore::QBuffer *node = qobject_cast<const Qt3DCore::QBuffer *>(object: frontEnd);
65 if (!node)
66 return;
67
68 if (firstTime && m_manager != nullptr) {
69 m_manager->addBufferReference(bufferId: peerId());
70 m_bufferDirty = true;
71 }
72
73 m_access = node->accessType();
74 if (m_usage != node->usage()) {
75 m_usage = node->usage();
76 m_bufferDirty = true;
77 }
78 {
79 const QVariant v = node->property(name: Qt3DCore::QBufferPrivate::UpdateDataPropertyName);
80
81 // Make sure we record data if it's the first time we are called
82 // or if we have no partial updates
83 if (firstTime || !v.isValid()){
84 const QByteArray newData = node->data();
85 const bool dirty = m_data != newData;
86 m_bufferDirty |= dirty;
87 m_data = newData;
88
89 // Since frontend applies partial updates to its m_data
90 // if we enter this code block, there's no problem in actually
91 // ignoring the partial updates
92 if (v.isValid())
93 const_cast<Qt3DCore::QBuffer *>(node)->setProperty(name: Qt3DCore::QBufferPrivate::UpdateDataPropertyName, value: {});
94
95 if (dirty && !m_data.isEmpty())
96 forceDataUpload();
97 } else if (v.isValid()) {
98 // Apply partial updates and record them to allow partial upload to the GPU
99 const QVariantList updateList = v.toList();
100 for (const QVariant &update : updateList) {
101 Qt3DCore::QBufferUpdate updateData = update.value<Qt3DCore::QBufferUpdate>();
102 m_data.replace(index: updateData.offset, len: updateData.data.size(), s: updateData.data);
103 m_bufferUpdates.push_back(x: updateData);
104 m_bufferDirty = true;
105 }
106
107 const_cast<Qt3DCore::QBuffer *>(node)->setProperty(name: Qt3DCore::QBufferPrivate::UpdateDataPropertyName, value: {});
108 }
109 }
110 markDirty(changes: AbstractRenderer::BuffersDirty);
111}
112
113// Called by Renderer once the buffer has been uploaded to OpenGL
114void Buffer::unsetDirty()
115{
116 m_bufferDirty = false;
117}
118
119BufferFunctor::BufferFunctor(AbstractRenderer *renderer, BufferManager *manager)
120 : m_manager(manager)
121 , m_renderer(renderer)
122{
123}
124
125Qt3DCore::QBackendNode *BufferFunctor::create(Qt3DCore::QNodeId id) const
126{
127 Buffer *buffer = m_manager->getOrCreateResource(id);
128 buffer->setManager(m_manager);
129 buffer->setRenderer(m_renderer);
130 return buffer;
131}
132
133Qt3DCore::QBackendNode *BufferFunctor::get(Qt3DCore::QNodeId id) const
134{
135 return m_manager->lookupResource(id);
136}
137
138void BufferFunctor::destroy(Qt3DCore::QNodeId id) const
139{
140 if (m_manager->contains(id)) {
141 m_manager->removeBufferReference(bufferId: id);
142 m_manager->releaseResource(id);
143 }
144}
145
146} // namespace Render
147} // namespace Qt3DRender
148
149QT_END_NAMESPACE
150

source code of qt3d/src/render/geometry/buffer.cpp