1 /****************************************************************************
2 **
3 ** Copyright (C) 2008-2012 NVIDIA Corporation.
4 ** Copyright (C) 2019 The Qt Company Ltd.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of Qt Quick 3D.
8 **
9 ** $QT_BEGIN_LICENSE:GPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU
20 ** General Public License version 3 or (at your option) any later version
21 ** approved by the KDE Free Qt Foundation. The licenses are as published by
22 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
23 ** included in the packaging of this file. Please review the following
24 ** information to ensure the GNU General Public License requirements will
25 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
26 **
27 ** $QT_END_LICENSE$
28 **
29 ****************************************************************************/
30
31 #include "qssgrenderresourcemanager_p.h"
32
33 #include <QtQuick3DRender/private/qssgrendercontext_p.h>
34 #include <QtQuick3DRender/private/qssgrenderframebuffer_p.h>
35 #include <QtQuick3DRender/private/qssgrenderrenderbuffer_p.h>
36 #include <QtQuick3DRender/private/qssgrendertexture2d_p.h>
37 #include <QtQuick3DRender/private/qssgrendertexturecube_p.h>
38
39 QT_BEGIN_NAMESPACE
40
41 template <typename T>
replaceWithLast(QVector<T> & vector,int index)42 static void replaceWithLast(QVector<T> &vector, int index)
43 {
44 vector[index] = vector.back();
45 vector.pop_back();
46 }
47
48
QSSGResourceManager(const QSSGRef<QSSGRenderContext> & ctx)49 QSSGResourceManager::QSSGResourceManager(const QSSGRef<QSSGRenderContext> &ctx)
50 : renderContext(ctx)
51 {
52 }
53
54 QSSGResourceManager::~QSSGResourceManager() = default;
55
allocateFrameBuffer()56 QSSGRef<QSSGRenderFrameBuffer> QSSGResourceManager::allocateFrameBuffer()
57 {
58 if (freeFrameBuffers.empty() == true) {
59 auto newBuffer = new QSSGRenderFrameBuffer(renderContext);
60 freeFrameBuffers.push_back(newBuffer);
61 }
62 auto retval = freeFrameBuffers.back();
63 freeFrameBuffers.pop_back();
64 return retval;
65 }
66
release(const QSSGRef<QSSGRenderFrameBuffer> & inBuffer)67 void QSSGResourceManager::release(const QSSGRef<QSSGRenderFrameBuffer> &inBuffer)
68 {
69 if (inBuffer->hasAnyAttachment()) {
70 // Ensure the framebuffer has no attachments.
71 inBuffer->attach(QSSGRenderFrameBufferAttachment::Color0, QSSGRenderTextureOrRenderBuffer());
72 inBuffer->attach(QSSGRenderFrameBufferAttachment::Color1, QSSGRenderTextureOrRenderBuffer());
73 inBuffer->attach(QSSGRenderFrameBufferAttachment::Color2, QSSGRenderTextureOrRenderBuffer());
74 inBuffer->attach(QSSGRenderFrameBufferAttachment::Color3, QSSGRenderTextureOrRenderBuffer());
75 inBuffer->attach(QSSGRenderFrameBufferAttachment::Color4, QSSGRenderTextureOrRenderBuffer());
76 inBuffer->attach(QSSGRenderFrameBufferAttachment::Color5, QSSGRenderTextureOrRenderBuffer());
77 inBuffer->attach(QSSGRenderFrameBufferAttachment::Color6, QSSGRenderTextureOrRenderBuffer());
78 inBuffer->attach(QSSGRenderFrameBufferAttachment::Color7, QSSGRenderTextureOrRenderBuffer());
79 inBuffer->attach(QSSGRenderFrameBufferAttachment::Depth, QSSGRenderTextureOrRenderBuffer());
80 inBuffer->attach(QSSGRenderFrameBufferAttachment::Stencil, QSSGRenderTextureOrRenderBuffer());
81 if (renderContext->supportsDepthStencil())
82 inBuffer->attach(QSSGRenderFrameBufferAttachment::DepthStencil, QSSGRenderTextureOrRenderBuffer());
83 }
84 #ifdef _DEBUG
85 auto theFind = std::find(freeFrameBuffers.begin(), freeFrameBuffers.end(), inBuffer);
86 Q_ASSERT(theFind == freeFrameBuffers.end());
87 #endif
88 freeFrameBuffers.push_back(inBuffer);
89 }
90
allocateRenderBuffer(qint32 inWidth,qint32 inHeight,QSSGRenderRenderBufferFormat inBufferFormat)91 QSSGRef<QSSGRenderRenderBuffer> QSSGResourceManager::allocateRenderBuffer(qint32 inWidth, qint32 inHeight, QSSGRenderRenderBufferFormat inBufferFormat)
92 {
93 Q_ASSERT(inWidth >= 0 && inHeight >= 0);
94 // Look for one of this specific size and format.
95 int existingMatchIdx = freeRenderBuffers.size();
96 for (int idx = 0, end = existingMatchIdx; idx < end; ++idx) {
97 auto theBuffer = freeRenderBuffers[idx];
98 QSize theDims = theBuffer->size();
99 QSSGRenderRenderBufferFormat theFormat = theBuffer->storageFormat();
100 if (theDims.width() == inWidth && theDims.height() == inHeight && theFormat == inBufferFormat) {
101 // Replace idx with last for efficient erasure (that reorders the vector).
102 replaceWithLast(freeRenderBuffers, idx);
103 return theBuffer;
104 }
105 if (theFormat == inBufferFormat)
106 existingMatchIdx = idx;
107 }
108 // If a specific exact match couldn't be found, just use the buffer with
109 // the same format and resize it.
110 if (existingMatchIdx < freeRenderBuffers.size()) {
111 auto theBuffer = freeRenderBuffers[existingMatchIdx];
112 replaceWithLast(freeRenderBuffers, existingMatchIdx);
113 theBuffer->setSize(QSize(inWidth, inHeight));
114 return theBuffer;
115 }
116
117 auto theBuffer = new QSSGRenderRenderBuffer(renderContext, inBufferFormat, inWidth, inHeight);
118 return theBuffer;
119 }
120
release(const QSSGRef<QSSGRenderRenderBuffer> & inBuffer)121 void QSSGResourceManager::release(const QSSGRef<QSSGRenderRenderBuffer> &inBuffer)
122 {
123 freeRenderBuffers.push_back(inBuffer);
124 }
125
setupAllocatedTexture(QSSGRef<QSSGRenderTexture2D> inTexture)126 QSSGRef<QSSGRenderTexture2D> QSSGResourceManager::setupAllocatedTexture(QSSGRef<QSSGRenderTexture2D> inTexture)
127 {
128 inTexture->setMinFilter(QSSGRenderTextureMinifyingOp::Linear);
129 inTexture->setMagFilter(QSSGRenderTextureMagnifyingOp::Linear);
130 return inTexture;
131 }
132
allocateTexture2D(qint32 inWidth,qint32 inHeight,QSSGRenderTextureFormat inTextureFormat,qint32 inSampleCount,bool immutable)133 QSSGRef<QSSGRenderTexture2D> QSSGResourceManager::allocateTexture2D(qint32 inWidth, qint32 inHeight, QSSGRenderTextureFormat inTextureFormat, qint32 inSampleCount, bool immutable)
134 {
135 Q_ASSERT(inWidth >= 0 && inHeight >= 0 && inSampleCount >= 0);
136 bool inMultisample = inSampleCount > 1 && renderContext->supportsMultisampleTextures();
137 for (qint32 idx = 0, end = freeTextures.size(); idx < end; ++idx) {
138 auto theTexture = freeTextures[idx];
139 QSSGTextureDetails theDetails = theTexture->textureDetails();
140 if (theDetails.width == inWidth && theDetails.height == inHeight && inTextureFormat == theDetails.format
141 && theTexture->sampleCount() == inSampleCount) {
142 replaceWithLast(freeTextures, idx);
143 return setupAllocatedTexture(theTexture);
144 }
145 }
146 // else resize an existing texture. This is very expensive
147 // note that MSAA textures are not resizable ( in GLES )
148 /*
149 if ( !freeTextures.empty() && !inMultisample )
150 {
151 QSSGRenderTexture2D* theTexture = freeTextures.back();
152 freeTextures.pop_back();
153
154 // note we could re-use a former MSAA texture
155 // this causes a entiere destroy of the previous texture object
156 theTexture->SetTextureData( QSSGByteView(), 0, inWidth, inHeight, inTextureFormat
157 );
158
159 return SetupAllocatedTexture( *theTexture );
160 }*/
161 // else create a new texture.
162 auto theTexture = new QSSGRenderTexture2D(renderContext);
163
164 if (inMultisample)
165 theTexture->setTextureDataMultisample(inSampleCount, inWidth, inHeight, inTextureFormat);
166 else if (immutable)
167 theTexture->setTextureStorage(1, inWidth, inHeight, inTextureFormat);
168 else
169 theTexture->setTextureData(QSSGByteView(), 0, inWidth, inHeight, inTextureFormat);
170
171 return setupAllocatedTexture(theTexture);
172 }
173
release(const QSSGRef<QSSGRenderTexture2D> & inBuffer)174 void QSSGResourceManager::release(const QSSGRef<QSSGRenderTexture2D> &inBuffer)
175 {
176 #ifdef _DEBUG
177 auto theFind = std::find(freeTextures.begin(), freeTextures.end(), inBuffer);
178 Q_ASSERT(theFind == freeTextures.end());
179 #endif
180 freeTextures.push_back(inBuffer);
181 }
182
allocateTextureCube(qint32 inWidth,qint32 inHeight,QSSGRenderTextureFormat inTextureFormat,qint32 inSampleCount)183 QSSGRef<QSSGRenderTextureCube> QSSGResourceManager::allocateTextureCube(qint32 inWidth, qint32 inHeight, QSSGRenderTextureFormat inTextureFormat, qint32 inSampleCount)
184 {
185 bool inMultisample = inSampleCount > 1 && renderContext->supportsMultisampleTextures();
186 for (int idx = 0, end = freeTexCubes.size(); idx < end; ++idx) {
187 auto theTexture = freeTexCubes[idx];
188 QSSGTextureDetails theDetails = theTexture->textureDetails();
189 if (theDetails.width == inWidth && theDetails.height == inHeight && inTextureFormat == theDetails.format
190 && theTexture->sampleCount() == inSampleCount) {
191 replaceWithLast(freeTexCubes, idx);
192
193 theTexture->setMinFilter(QSSGRenderTextureMinifyingOp::Linear);
194 theTexture->setMagFilter(QSSGRenderTextureMagnifyingOp::Linear);
195 return theTexture;
196 }
197 }
198
199 // else resize an existing texture. This should be fairly quick at the driver level.
200 // note that MSAA textures are not resizable ( in GLES )
201 if (!freeTexCubes.empty() && !inMultisample) {
202 auto theTexture = freeTexCubes.back();
203 freeTexCubes.pop_back();
204
205 // note we could re-use a former MSAA texture
206 // this causes a entire destroy of the previous texture object
207 theTexture->setTextureData(QSSGByteView(), 0, QSSGRenderTextureCubeFace::CubePosX, inWidth, inHeight, inTextureFormat);
208 theTexture->setTextureData(QSSGByteView(), 0, QSSGRenderTextureCubeFace::CubeNegX, inWidth, inHeight, inTextureFormat);
209 theTexture->setTextureData(QSSGByteView(), 0, QSSGRenderTextureCubeFace::CubePosY, inWidth, inHeight, inTextureFormat);
210 theTexture->setTextureData(QSSGByteView(), 0, QSSGRenderTextureCubeFace::CubeNegY, inWidth, inHeight, inTextureFormat);
211 theTexture->setTextureData(QSSGByteView(), 0, QSSGRenderTextureCubeFace::CubePosZ, inWidth, inHeight, inTextureFormat);
212 theTexture->setTextureData(QSSGByteView(), 0, QSSGRenderTextureCubeFace::CubeNegZ, inWidth, inHeight, inTextureFormat);
213 theTexture->setMinFilter(QSSGRenderTextureMinifyingOp::Linear);
214 theTexture->setMagFilter(QSSGRenderTextureMagnifyingOp::Linear);
215 return theTexture;
216 }
217
218 // else create a new texture.
219 QSSGRef<QSSGRenderTextureCube> theTexture = nullptr;
220
221 if (!inMultisample) {
222 theTexture = new QSSGRenderTextureCube(renderContext);
223 theTexture->setTextureData(QSSGByteView(), 0, QSSGRenderTextureCubeFace::CubePosX, inWidth, inHeight, inTextureFormat);
224 theTexture->setTextureData(QSSGByteView(), 0, QSSGRenderTextureCubeFace::CubeNegX, inWidth, inHeight, inTextureFormat);
225 theTexture->setTextureData(QSSGByteView(), 0, QSSGRenderTextureCubeFace::CubePosY, inWidth, inHeight, inTextureFormat);
226 theTexture->setTextureData(QSSGByteView(), 0, QSSGRenderTextureCubeFace::CubeNegY, inWidth, inHeight, inTextureFormat);
227 theTexture->setTextureData(QSSGByteView(), 0, QSSGRenderTextureCubeFace::CubePosZ, inWidth, inHeight, inTextureFormat);
228 theTexture->setTextureData(QSSGByteView(), 0, QSSGRenderTextureCubeFace::CubeNegZ, inWidth, inHeight, inTextureFormat);
229 } else {
230 // Not supported yet
231 return nullptr;
232 }
233
234 theTexture->setMinFilter(QSSGRenderTextureMinifyingOp::Linear);
235 theTexture->setMagFilter(QSSGRenderTextureMagnifyingOp::Linear);
236 return theTexture;
237 }
238
release(const QSSGRef<QSSGRenderTextureCube> & inBuffer)239 void QSSGResourceManager::release(const QSSGRef<QSSGRenderTextureCube> &inBuffer)
240 {
241 #ifdef _DEBUG
242 auto theFind = std::find(freeTexCubes.begin(), freeTexCubes.end(), inBuffer);
243 Q_ASSERT(theFind == freeTexCubes.end());
244 #endif
245 freeTexCubes.push_back(inBuffer);
246 }
247
allocateImage2D(const QSSGRef<QSSGRenderTexture2D> & inTexture,QSSGRenderImageAccessType inAccess)248 QSSGRef<QSSGRenderImage2D> QSSGResourceManager::allocateImage2D(const QSSGRef<QSSGRenderTexture2D> &inTexture,
249 QSSGRenderImageAccessType inAccess)
250 {
251 if (freeImages.empty() == true) {
252 auto newImage = new QSSGRenderImage2D(renderContext, inTexture, inAccess);
253 if (newImage) {
254 freeImages.push_back(newImage);
255 }
256 }
257
258 auto retval = freeImages.back();
259 freeImages.pop_back();
260
261 return retval;
262 }
263
release(const QSSGRef<QSSGRenderImage2D> & inBuffer)264 void QSSGResourceManager::release(const QSSGRef<QSSGRenderImage2D> &inBuffer)
265 {
266 #ifdef _DEBUG
267 auto theFind = std::find(freeImages.begin(), freeImages.end(), inBuffer);
268 Q_ASSERT(theFind == freeImages.end());
269 #endif
270 freeImages.push_back(inBuffer);
271 }
272
getRenderContext()273 QSSGRef<QSSGRenderContext> QSSGResourceManager::getRenderContext() { return renderContext; }
274
destroyFreeSizedResources()275 void QSSGResourceManager::destroyFreeSizedResources()
276 {
277 for (int idx = freeRenderBuffers.size() - 1; idx >= 0; --idx) {
278 auto obj = freeRenderBuffers[idx];
279 replaceWithLast(freeRenderBuffers, idx);
280 }
281 for (int idx = freeTextures.size() - 1; idx >= 0; --idx) {
282 auto obj = freeTextures[idx];
283 replaceWithLast(freeTextures, idx);
284 }
285 for (int idx = freeTexCubes.size() - 1; idx >= 0; --idx) {
286 auto obj = freeTexCubes[idx];
287 replaceWithLast(freeTexCubes, idx);
288 }
289 }
290
291 QT_END_NAMESPACE
292