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 QSSGRenderImageTexture(), QSSGRenderImageTexture(),
129 QSSGRenderImageTexture(), QSSGRenderImageTexture() };
130 dataToStore.cachedResult = firstFrameResult;
131 m_cache[modelKey] = dataToStore;
132 return firstFrameResult;
133 }
134
135 if (lastFrameDataIterator->visitedThisFrame)
136 return lastFrameDataIterator->cachedResult;
137
138 MotionResultData motionResult;
139
140 motionResult.prevModelViewProjection = lastFrameDataIterator->prevModelViewProjection;
141 lastFrameDataIterator->prevModelViewProjection = currentModelViewProjection;
142
143 motionResult.prevInstanceLocal = lastFrameDataIterator->prevInstanceLocal;
144 lastFrameDataIterator->prevInstanceLocal = currentInstanceLocal;
145
146 motionResult.prevInstanceGlobal = lastFrameDataIterator->prevInstanceGlobal;
147 lastFrameDataIterator->prevInstanceGlobal = currentInstanceGlobal;
148
149 motionResult.prevBoneTexture = loadAndReleaseIfNeeded(
150 lastFrameDataIterator->prevBoneTextureData,
151 lastFrameDataIterator->lastPrevBoneTextureDataSize);
152
153 motionResult.prevInstanceTexture = loadAndReleaseIfNeeded(
154 lastFrameDataIterator->prevInstanceTextureData,
155 lastFrameDataIterator->lastPrevInstanceTextureDataSize);
156
157 motionResult.prevMorphWeightTexture = loadAndReleaseIfNeeded(
158 lastFrameDataIterator->prevMorphWeightTextureData,
159 lastFrameDataIterator->lastPrevMorphWeightTextureDataSize);
160
161 motionResult.currentMorphWeightTexture = loadAndReleaseIfNeeded(
162 lastFrameDataIterator->currentMorphWeightTextureData,
163 lastFrameDataIterator->lastCurrentMorphWeightTextureDataSize);
164
165 if (currentBoneTextureData) {
166 if (!lastFrameDataIterator->prevBoneTextureData)
167 lastFrameDataIterator->prevBoneTextureData = std::make_shared<QSSGRenderTextureData>();
168
169 lastFrameDataIterator->lastPrevBoneTextureDataSize = lastFrameDataIterator->prevBoneTextureData->size();
170 copyToTextureData(lastFrameDataIterator->prevBoneTextureData.get(), currentBoneTextureData);
171 }
172 if (currentInstanceTable) {
173 if (!lastFrameDataIterator->prevInstanceTextureData)
174 lastFrameDataIterator->prevInstanceTextureData = std::make_shared<QSSGRenderTextureData>();
175
176 lastFrameDataIterator->lastPrevInstanceTextureDataSize = lastFrameDataIterator->prevInstanceTextureData->size();
177 copyToTextureData(lastFrameDataIterator->prevInstanceTextureData.get(), currentInstanceTable);
178 }
179
180 if (currentMorphWeights.size()) {
181 if (!lastFrameDataIterator->prevMorphWeightTextureData)
182 lastFrameDataIterator->prevMorphWeightTextureData = std::make_shared<QSSGRenderTextureData>();
183
184 lastFrameDataIterator->lastPrevMorphWeightTextureDataSize = lastFrameDataIterator->prevMorphWeightTextureData->size();
185 copyToTextureData(lastFrameDataIterator->prevMorphWeightTextureData.get(), lastFrameDataIterator->currentMorphWeightTextureData.get());
186
187 if (!lastFrameDataIterator->currentMorphWeightTextureData)
188 lastFrameDataIterator->currentMorphWeightTextureData = std::make_shared<QSSGRenderTextureData>();
189
190 lastFrameDataIterator->lastCurrentMorphWeightTextureDataSize = lastFrameDataIterator->currentMorphWeightTextureData->size();
191 copyToTextureData(lastFrameDataIterator->currentMorphWeightTextureData.get(), currentMorphWeights);
192 }
193
194 lastFrameDataIterator->frameAge = 0;
195 lastFrameDataIterator->visitedThisFrame = true;
196 lastFrameDataIterator->cachedResult = motionResult;
197
198 return motionResult;
199}
200
201void QSSGRenderMotionVectorMap::releaseEntryResources(MotionStoreData& entry)
202{
203 if (entry.prevBoneTextureData)
204 m_context.bufferManager()->releaseTextureData(entry.prevBoneTextureData.get());
205 if (entry.prevInstanceTextureData)
206 m_context.bufferManager()->releaseTextureData(entry.prevInstanceTextureData.get());
207 if (entry.prevMorphWeightTextureData)
208 m_context.bufferManager()->releaseTextureData(entry.prevMorphWeightTextureData.get());
209 if (entry.currentMorphWeightTextureData)
210 m_context.bufferManager()->releaseTextureData(entry.currentMorphWeightTextureData.get());
211}
212
213void QSSGRenderMotionVectorMap::releaseCachedResources()
214{
215 for (auto& entry : m_cache)
216 releaseEntryResources(entry);
217 m_cache.clear();
218}
219
220void QSSGRenderMotionVectorMap::cleanupStaleEntries()
221{
222 constexpr int maxFrameAge = 2;
223 auto it = m_cache.begin();
224 while (it != m_cache.end()) {
225 it->visitedThisFrame = false;
226 it->frameAge++;
227 if (it->frameAge > maxFrameAge) {
228 releaseEntryResources(*it);
229 it = m_cache.erase(it);
230 } else {
231 ++it;
232 }
233 }
234}
235
236QT_END_NAMESPACE
static void copyToTextureData(QSSGRenderTextureData *dst, QSSGRenderTextureData *src)
static void copyToTextureData(QSSGRenderTextureData *dst, const QVector< float > &src)