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