Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qssgrendermotionvectormap.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
6#include <ssg/qssgrendercontextcore.h>
7#include <QtQuick3DRuntimeRender/private/qssgrenderlayer_p.h>
8#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
9#include <QtQuick3DRuntimeRender/private/qssgrendermotionvectormap_p.h>
10
11QT_BEGIN_NAMESPACE
12
13QSSGRenderMotionVectorMap::QSSGRenderMotionVectorMap(const QSSGRenderContextInterface &inContext)
14 : m_context(inContext)
15{
16}
17
18QSSGRenderMotionVectorMap::~QSSGRenderMotionVectorMap()
19{
20 releaseCachedResources();
21}
22
23void QSSGRenderMotionVectorMap::endFrame()
24{
25 cleanupStaleEntries();
26}
27
28static void copyToTextureData(QSSGRenderTextureData *dst, QSSGRenderTextureData *src) {
29 dst->setTextureData(src->textureData());
30 dst->setDepth(src->depth());
31 dst->setFormat(src->format());
32 dst->setHasTransparency(src->hasTransparency());
33 dst->setSize(src->size());
34}
35
36static void copyToTextureData(QSSGRenderTextureData *dst, QSSGRenderInstanceTable *src) {
37
38 dst->setDepth(0);
39 dst->setFormat(QSSGRenderTextureFormat::RGBA32F);
40 dst->setHasTransparency(false);
41
42 auto instanceCount = src->count();
43 int totalPixels = qMax(instanceCount * 4, 1);
44 int width = qCeil(qSqrt(static_cast<float>(totalPixels)));
45 int height = qCeil(static_cast<float>(totalPixels) / width);
46 dst->setSize(QSize(width, height));
47
48 QByteArray instanceBuffer(width * height * 4 * sizeof(float), Qt::Uninitialized);
49 float *ptr = reinterpret_cast<float*>(instanceBuffer.data());
50
51 for (int i = 0; i < instanceCount; ++i) {
52 memcpy(ptr + i * 16, src->getTransform(i).constData(), 16 * sizeof(float));
53 }
54 dst->setTextureData(instanceBuffer);
55}
56
57static void copyToTextureData(QSSGRenderTextureData *dst, const QVector<float> &src) {
58
59 dst->setDepth(0);
60 dst->setFormat(QSSGRenderTextureFormat::R32F);
61 dst->setHasTransparency(false);
62 dst->setSize(QSize(src.count(), 1));
63 QByteArray textureData(reinterpret_cast<const char*>(src.constData()), src.count() * sizeof(float));
64 dst->setTextureData(textureData);
65}
66
67QSSGRenderImageTexture QSSGRenderMotionVectorMap::loadAndReleaseIfNeeded(const std::shared_ptr<QSSGRenderTextureData>& textureData, QSize lastSize)
68{
69 if (!textureData)
70 return QSSGRenderImageTexture();
71
72 auto texture = m_context.bufferManager()->loadTextureData(textureData.get(), QSSGBufferManager::MipModeDisable);
73
74 // the only thing might to force to recreate new texture is changing the texture data size
75 // so we should release last one
76 if (lastSize != textureData->size()) {
77 m_context.bufferManager()->releaseTextureData(
78 QSSGBufferManager::CustomImageCacheKey{
79 textureData.get(),
80 lastSize,
81 QSSGBufferManager::MipMode::MipModeDisable});
82 }
83 return texture;
84}
85
86QSSGRenderMotionVectorMap::MotionResultData QSSGRenderMotionVectorMap::trackMotionData(
87 const void *modelKey,
88 const QMatrix4x4 &currentModelViewProjection,
89 const QMatrix4x4 &currentInstanceLocal,
90 const QMatrix4x4 &currentInstanceGlobal,
91 QSSGRenderTextureData *currentBoneTextureData,
92 QSSGRenderInstanceTable *currentInstanceTable,
93 const QVector<float> &currentMorphWeights)
94{
95 auto lastFrameDataIterator = m_cache.find(modelKey);
96
97 if (lastFrameDataIterator == m_cache.end()) {
98 MotionStoreData dataToStore;
99 dataToStore.prevModelViewProjection = currentModelViewProjection;
100 dataToStore.prevInstanceLocal = currentInstanceLocal;
101 dataToStore.prevInstanceGlobal = currentInstanceGlobal;
102 dataToStore.frameAge = 0;
103 dataToStore.visitedThisFrame = true;
104
105 if (currentBoneTextureData) {
106 dataToStore.prevBoneTextureData = std::make_shared<QSSGRenderTextureData>();
107 copyToTextureData(dataToStore.prevBoneTextureData.get(), currentBoneTextureData);
108 dataToStore.lastPrevBoneTextureDataSize = dataToStore.prevBoneTextureData->size();
109 }
110
111 if (currentInstanceTable) {
112 dataToStore.prevInstanceTextureData = std::make_shared<QSSGRenderTextureData>();
113 copyToTextureData(dataToStore.prevInstanceTextureData.get(), currentInstanceTable);
114 dataToStore.lastPrevInstanceTextureDataSize = dataToStore.prevInstanceTextureData->size();
115 }
116
117 if (currentMorphWeights.size()) {
118 dataToStore.currentMorphWeightTextureData = std::make_shared<QSSGRenderTextureData>();
119 copyToTextureData(dataToStore.currentMorphWeightTextureData.get(), currentMorphWeights);
120 dataToStore.lastCurrentMorphWeightTextureDataSize = dataToStore.currentMorphWeightTextureData->size();
121
122 dataToStore.prevMorphWeightTextureData = std::make_shared<QSSGRenderTextureData>();
123 copyToTextureData(dataToStore.prevMorphWeightTextureData.get(), currentMorphWeights);
124 dataToStore.lastPrevMorphWeightTextureDataSize = dataToStore.prevMorphWeightTextureData->size();
125 }
126
127 MotionResultData firstFrameResult = { currentModelViewProjection, currentInstanceLocal, currentInstanceGlobal,
128 loadAndReleaseIfNeeded(dataToStore.prevBoneTextureData, dataToStore.lastPrevBoneTextureDataSize),
129 loadAndReleaseIfNeeded(dataToStore.prevInstanceTextureData, dataToStore.lastPrevInstanceTextureDataSize),
130 loadAndReleaseIfNeeded(dataToStore.currentMorphWeightTextureData, dataToStore.lastCurrentMorphWeightTextureDataSize),
131 loadAndReleaseIfNeeded(dataToStore.prevMorphWeightTextureData, dataToStore.lastPrevMorphWeightTextureDataSize) };
132 dataToStore.cachedResult = firstFrameResult;
133 m_cache[modelKey] = dataToStore;
134 return firstFrameResult;
135 }
136
137 if (lastFrameDataIterator->visitedThisFrame)
138 return lastFrameDataIterator->cachedResult;
139
140 MotionResultData motionResult;
141
142 motionResult.prevModelViewProjection = lastFrameDataIterator->prevModelViewProjection;
143 lastFrameDataIterator->prevModelViewProjection = currentModelViewProjection;
144
145 motionResult.prevInstanceLocal = lastFrameDataIterator->prevInstanceLocal;
146 lastFrameDataIterator->prevInstanceLocal = currentInstanceLocal;
147
148 motionResult.prevInstanceGlobal = lastFrameDataIterator->prevInstanceGlobal;
149 lastFrameDataIterator->prevInstanceGlobal = currentInstanceGlobal;
150
151 motionResult.prevBoneTexture = loadAndReleaseIfNeeded(
152 lastFrameDataIterator->prevBoneTextureData,
153 lastFrameDataIterator->lastPrevBoneTextureDataSize);
154
155 motionResult.prevInstanceTexture = loadAndReleaseIfNeeded(
156 lastFrameDataIterator->prevInstanceTextureData,
157 lastFrameDataIterator->lastPrevInstanceTextureDataSize);
158
159 motionResult.prevMorphWeightTexture = loadAndReleaseIfNeeded(
160 lastFrameDataIterator->prevMorphWeightTextureData,
161 lastFrameDataIterator->lastPrevMorphWeightTextureDataSize);
162
163 motionResult.currentMorphWeightTexture = loadAndReleaseIfNeeded(
164 lastFrameDataIterator->currentMorphWeightTextureData,
165 lastFrameDataIterator->lastCurrentMorphWeightTextureDataSize);
166
167 if (currentBoneTextureData) {
168 if (!lastFrameDataIterator->prevBoneTextureData)
169 lastFrameDataIterator->prevBoneTextureData = std::make_shared<QSSGRenderTextureData>();
170
171 lastFrameDataIterator->lastPrevBoneTextureDataSize = lastFrameDataIterator->prevBoneTextureData->size();
172 copyToTextureData(lastFrameDataIterator->prevBoneTextureData.get(), currentBoneTextureData);
173 }
174 if (currentInstanceTable) {
175 if (!lastFrameDataIterator->prevInstanceTextureData)
176 lastFrameDataIterator->prevInstanceTextureData = std::make_shared<QSSGRenderTextureData>();
177
178 lastFrameDataIterator->lastPrevInstanceTextureDataSize = lastFrameDataIterator->prevInstanceTextureData->size();
179 copyToTextureData(lastFrameDataIterator->prevInstanceTextureData.get(), currentInstanceTable);
180 }
181
182 if (currentMorphWeights.size()) {
183 if (!lastFrameDataIterator->prevMorphWeightTextureData)
184 lastFrameDataIterator->prevMorphWeightTextureData = std::make_shared<QSSGRenderTextureData>();
185
186 lastFrameDataIterator->lastPrevMorphWeightTextureDataSize = lastFrameDataIterator->prevMorphWeightTextureData->size();
187 if (lastFrameDataIterator->currentMorphWeightTextureData)
188 copyToTextureData(lastFrameDataIterator->prevMorphWeightTextureData.get(), lastFrameDataIterator->currentMorphWeightTextureData.get());
189 else
190 copyToTextureData(lastFrameDataIterator->prevMorphWeightTextureData.get(), currentMorphWeights);
191
192 if (!lastFrameDataIterator->currentMorphWeightTextureData)
193 lastFrameDataIterator->currentMorphWeightTextureData = std::make_shared<QSSGRenderTextureData>();
194
195 lastFrameDataIterator->lastCurrentMorphWeightTextureDataSize = lastFrameDataIterator->currentMorphWeightTextureData->size();
196 copyToTextureData(lastFrameDataIterator->currentMorphWeightTextureData.get(), currentMorphWeights);
197 }
198
199 lastFrameDataIterator->frameAge = 0;
200 lastFrameDataIterator->visitedThisFrame = true;
201 lastFrameDataIterator->cachedResult = motionResult;
202
203 return motionResult;
204}
205
206void QSSGRenderMotionVectorMap::releaseEntryResources(MotionStoreData& entry)
207{
208 if (entry.prevBoneTextureData)
209 m_context.bufferManager()->releaseTextureData(entry.prevBoneTextureData.get());
210 if (entry.prevInstanceTextureData)
211 m_context.bufferManager()->releaseTextureData(entry.prevInstanceTextureData.get());
212 if (entry.prevMorphWeightTextureData)
213 m_context.bufferManager()->releaseTextureData(entry.prevMorphWeightTextureData.get());
214 if (entry.currentMorphWeightTextureData)
215 m_context.bufferManager()->releaseTextureData(entry.currentMorphWeightTextureData.get());
216}
217
218void QSSGRenderMotionVectorMap::releaseCachedResources()
219{
220 for (auto& entry : m_cache)
221 releaseEntryResources(entry);
222 m_cache.clear();
223}
224
225void QSSGRenderMotionVectorMap::cleanupStaleEntries()
226{
227 constexpr int maxFrameAge = 2;
228 auto it = m_cache.begin();
229 while (it != m_cache.end()) {
230 it->visitedThisFrame = false;
231 it->frameAge++;
232 if (it->frameAge > maxFrameAge) {
233 releaseEntryResources(*it);
234 it = m_cache.erase(it);
235 } else {
236 ++it;
237 }
238 }
239}
240
241QT_END_NAMESPACE
static void copyToTextureData(QSSGRenderTextureData *dst, QSSGRenderTextureData *src)
static void copyToTextureData(QSSGRenderTextureData *dst, const QVector< float > &src)