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 
32 #include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
33 #include <QtQuick3DRuntimeRender/private/qssgrendererimpl_p.h>
34 #include <QtQuick3DRuntimeRender/private/qssgrenderlayer_p.h>
35 #include <QtQuick3DRuntimeRender/private/qssgrendereffect_p.h>
36 #include <QtQuick3DRuntimeRender/private/qssgrenderlight_p.h>
37 #include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h>
38 #include <QtQuick3DRuntimeRender/private/qssgrendercontextcore_p.h>
39 #include <QtQuick3DRuntimeRender/private/qssgrenderresourcemanager_p.h>
40 #include <QtQuick3DRuntimeRender/private/qssgrendereffectsystem_p.h>
41 #include <QtQuick3DRender/private/qssgrenderframebuffer_p.h>
42 #include <QtQuick3DRender/private/qssgrenderrenderbuffer_p.h>
43 #include <QtQuick3DRuntimeRender/private/qssgrenderresourcebufferobjects_p.h>
44 #include <QtQuick3DUtils/private/qssgperftimer_p.h>
45 #include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h>
46 #include <QtQuick3DRuntimeRender/private/qssgrendercustommaterialsystem_p.h>
47 #include <QtQuick3DRuntimeRender/private/qssgrendererutil_p.h>
48 #include <QtQuick3DUtils/private/qssgutils_p.h>
49 
50 #include <QtQuick/QSGTexture>
51 
52 #include <QtMath>
53 
54 #define QSSG_CACHED_POST_EFFECT
55 
56 namespace {
57 const float QSSG_PI = float(M_PI);
58 const float QSSG_HALFPI = float(M_PI_2);
59 }
60 
61 QT_BEGIN_NAMESPACE
62 
QSSGLayerRenderData(QSSGRenderLayer & inLayer,const QSSGRef<QSSGRendererImpl> & inRenderer)63 QSSGLayerRenderData::QSSGLayerRenderData(QSSGRenderLayer &inLayer, const QSSGRef<QSSGRendererImpl> &inRenderer)
64     : QSSGLayerRenderPreparationData(inLayer, inRenderer)
65     , m_layerTexture(inRenderer->contextInterface()->resourceManager())
66     , m_temporalAATexture(inRenderer->contextInterface()->resourceManager())
67     , m_prevTemporalAATexture(inRenderer->contextInterface()->resourceManager())
68     , m_layerDepthTexture(inRenderer->contextInterface()->resourceManager())
69     , m_layerPrepassDepthTexture(inRenderer->contextInterface()->resourceManager())
70     , m_layerSsaoTexture(inRenderer->contextInterface()->resourceManager())
71     , m_layerMultisampleTexture(inRenderer->contextInterface()->resourceManager())
72     , m_layerMultisamplePrepassDepthTexture(inRenderer->contextInterface()->resourceManager())
73     , m_layerMultisampleWidgetTexture(inRenderer->contextInterface()->resourceManager())
74     , m_progressiveAAPassIndex(0)
75     , m_temporalAAPassIndex(0)
76     , m_nonDirtyTemporalAAPassIndex(0)
77     , m_textScale(1.0f)
78     , m_depthBufferFormat(QSSGRenderTextureFormat::Unknown)
79 {
80 }
81 
~QSSGLayerRenderData()82 QSSGLayerRenderData::~QSSGLayerRenderData()
83 {
84 }
85 
prepareForRender(const QSize & inViewportDimensions)86 void QSSGLayerRenderData::prepareForRender(const QSize &inViewportDimensions)
87 {
88     QSSGLayerRenderPreparationData::prepareForRender(inViewportDimensions);
89     QSSGLayerRenderPreparationResult &thePrepResult(*layerPrepResult);
90     const QSSGRef<QSSGResourceManager> &theResourceManager(renderer->contextInterface()->resourceManager());
91     // at that time all values shoud be updated
92     renderer->updateCbAoShadow(&layer, camera, m_layerDepthTexture);
93 
94     // Generate all necessary lighting keys
95 
96     if (thePrepResult.flags.wasLayerDataDirty()) {
97         m_progressiveAAPassIndex = 0;
98     }
99 
100     // Get rid of the layer texture if we aren't rendering to texture this frame.
101     if (m_layerTexture.getTexture()) {
102         m_layerTexture.releaseTexture();
103         m_layerDepthTexture.releaseTexture();
104         m_layerSsaoTexture.releaseTexture();
105         m_layerMultisampleTexture.releaseTexture();
106         m_layerMultisamplePrepassDepthTexture.releaseTexture();
107         m_layerMultisampleWidgetTexture.releaseTexture();
108     }
109 
110     if (m_layerDepthTexture.getTexture() && !thePrepResult.flags.requiresDepthTexture())
111         m_layerDepthTexture.releaseTexture();
112 
113     if (m_layerSsaoTexture.getTexture() && !thePrepResult.flags.requiresSsaoPass())
114         m_layerSsaoTexture.releaseTexture();
115 
116     renderer->layerNeedsFrameClear(*this);
117 
118     // Clean up the texture cache if layer dimensions changed
119     if (inViewportDimensions.width() != m_previousDimensions.width()
120             || inViewportDimensions.height() != m_previousDimensions.height()) {
121         m_layerTexture.releaseTexture();
122         m_layerDepthTexture.releaseTexture();
123         m_layerSsaoTexture.releaseTexture();
124         m_layerPrepassDepthTexture.releaseTexture();
125         m_temporalAATexture.releaseTexture();
126         m_layerMultisampleTexture.releaseTexture();
127         m_layerMultisamplePrepassDepthTexture.releaseTexture();
128         m_layerMultisampleWidgetTexture.releaseTexture();
129 
130         m_previousDimensions.setWidth(inViewportDimensions.width());
131         m_previousDimensions.setHeight(inViewportDimensions.height());
132 
133         theResourceManager->destroyFreeSizedResources();
134 
135         // Effect system uses different resource manager, so clean that up too
136         renderer->contextInterface()->effectSystem()->getResourceManager()->destroyFreeSizedResources();
137     }
138 }
139 
getDepthBufferFormat()140 QSSGRenderTextureFormat QSSGLayerRenderData::getDepthBufferFormat()
141 {
142     if (m_depthBufferFormat == QSSGRenderTextureFormat::Unknown) {
143         quint32 theExistingDepthBits = renderer->context()->depthBits();
144         quint32 theExistingStencilBits = renderer->context()->stencilBits();
145         switch (theExistingDepthBits) {
146         case 32:
147             m_depthBufferFormat = QSSGRenderTextureFormat::Depth32;
148             break;
149         case 24:
150             //  check if we have stencil bits
151             if (theExistingStencilBits > 0)
152                 m_depthBufferFormat = QSSGRenderTextureFormat::Depth24Stencil8; // currently no stencil usage
153             // should be Depth24Stencil8 in
154             // this case
155             else
156                 m_depthBufferFormat = QSSGRenderTextureFormat::Depth24;
157             break;
158         case 16:
159             m_depthBufferFormat = QSSGRenderTextureFormat::Depth16;
160             break;
161         default:
162             Q_ASSERT(false);
163             m_depthBufferFormat = QSSGRenderTextureFormat::Depth16;
164             break;
165         }
166     }
167     return m_depthBufferFormat;
168 }
169 
getFramebufferDepthAttachmentFormat(QSSGRenderTextureFormat depthFormat)170 QSSGRenderFrameBufferAttachment QSSGLayerRenderData::getFramebufferDepthAttachmentFormat(QSSGRenderTextureFormat depthFormat)
171 {
172     QSSGRenderFrameBufferAttachment fmt = QSSGRenderFrameBufferAttachment::Depth;
173 
174     switch (depthFormat.format) {
175     case QSSGRenderTextureFormat::Depth16:
176     case QSSGRenderTextureFormat::Depth24:
177     case QSSGRenderTextureFormat::Depth32:
178         fmt = QSSGRenderFrameBufferAttachment::Depth;
179         break;
180     case QSSGRenderTextureFormat::Depth24Stencil8:
181         fmt = QSSGRenderFrameBufferAttachment::DepthStencil;
182         break;
183     default:
184         Q_ASSERT(false);
185         break;
186     }
187 
188     return fmt;
189 }
190 
renderClearPass()191 void QSSGLayerRenderData::renderClearPass()
192 {
193     QSSGStackPerfTimer ___timer(renderer->contextInterface()->performanceTimer(), Q_FUNC_INFO);
194     if (camera == nullptr)
195         return;
196 
197     renderer->beginLayerRender(*this);
198 
199     const auto &theContext = renderer->context();
200     auto background = layer.background;
201     if (background == QSSGRenderLayer::Background::SkyBox) {
202         if (layer.lightProbe && !layer.lightProbe->m_textureData.m_texture.isNull()) {
203             theContext->setDepthTestEnabled(false); // Draw to every pixel
204             theContext->setDepthWriteEnabled(false); // Depth will be cleared in a separate step
205             QSSGRef<QSSGSkyBoxShader> shader = renderer->getSkyBoxShader();
206             theContext->setActiveShader(shader->shader);
207             // Setup constants
208             shader->inverseProjection.set(camera->projection.inverted());
209             shader->viewMatrix.set(camera->globalTransform);
210             shader->skyboxTexture.set(layer.lightProbe->m_textureData.m_texture.data());
211             renderer->renderQuad();
212         } else {
213             // Revert to color
214             background = QSSGRenderLayer::Background::Color;
215         }
216     }
217 
218     QSSGRenderClearFlags clearFlags;
219     if (!layer.flags.testFlag(QSSGRenderLayer::Flag::LayerEnableDepthPrePass)) {
220         clearFlags |= QSSGRenderClearValues::Depth;
221         clearFlags |= QSSGRenderClearValues::Stencil;
222         // Enable depth write for the clear below
223         theContext->setDepthWriteEnabled(true);
224     }
225 
226     if (background == QSSGRenderLayer::Background::Color) {
227         clearFlags |= QSSGRenderClearValues::Color;
228         QSSGRenderContextScopedProperty<QVector4D> __clearColor(*theContext,
229                                                                   &QSSGRenderContext::clearColor,
230                                                                   &QSSGRenderContext::setClearColor,
231                                                                   QVector4D(layer.clearColor, 1.0f));
232         theContext->clear(clearFlags);
233     } else if (layerPrepResult->flags.requiresTransparentClear() &&
234                background != QSSGRenderLayer::Background::SkyBox) {
235         clearFlags |= QSSGRenderClearValues::Color;
236         QSSGRenderContextScopedProperty<QVector4D> __clearColor(*theContext,
237                                                                 &QSSGRenderContext::clearColor,
238                                                                 &QSSGRenderContext::setClearColor,
239                                                                 QVector4D(0.0, 0.0, 0.0, 0.0f));
240         theContext->clear(clearFlags);
241     } else if (clearFlags) {
242         theContext->clear(clearFlags);
243     }
244     renderer->endLayerRender();
245 }
246 
renderAoPass()247 void QSSGLayerRenderData::renderAoPass()
248 {
249     renderer->beginLayerDepthPassRender(*this);
250 
251     const auto &theContext = renderer->context();
252     QSSGRef<QSSGDefaultAoPassShader> shader = renderer->getDefaultAoPassShader(getShaderFeatureSet());
253     if (shader == nullptr)
254         return;
255 
256     // Set initial state
257     theContext->setBlendingEnabled(false);
258     theContext->setDepthWriteEnabled(false);
259     theContext->setDepthTestEnabled(false);
260     theContext->setActiveShader(shader->shader);
261 
262     // Setup constants
263     shader->cameraDirection.set(cameraDirection);
264     shader->viewMatrix.set(camera->globalTransform);
265 
266     shader->depthTexture.set(m_layerDepthTexture.getTexture().data());
267     shader->depthTextureSize.set(
268                 QVector2D(m_layerDepthTexture->textureDetails().width, m_layerDepthTexture->textureDetails().height));
269 
270     // Important uniforms for AO calculations
271     QVector2D theCameraProps = QVector2D(camera->clipNear, camera->clipFar);
272     shader->cameraProperties.set(theCameraProps);
273     shader->aoShadowParams.set();
274 
275     // Draw a fullscreen quad
276     renderer->renderQuad();
277 
278     renderer->endLayerDepthPassRender();
279 }
280 
281 #ifdef QT_QUICK3D_DEBUG_SHADOWS
renderDebugDepthMap(QSSGRenderTexture2D * theDepthTex,QSSGRenderTextureCube * theDepthCube)282 void QSSGLayerRenderData::renderDebugDepthMap(QSSGRenderTexture2D *theDepthTex, QSSGRenderTextureCube *theDepthCube)
283 {
284     renderer->beginLayerDepthPassRender(*this);
285 
286     const auto &theContext = renderer->context();
287     QSSGRef<QSSGDefaultAoPassShader> shader = theDepthTex ? renderer->getDebugDepthShader(getShaderFeatureSet())
288                                                           : renderer->getDebugCubeDepthShader(getShaderFeatureSet());
289     if (shader == nullptr)
290         return;
291 
292     // Set initial state
293     theContext->setBlendingEnabled(false);
294     theContext->setDepthWriteEnabled(false);
295     theContext->setDepthTestEnabled(false);
296     theContext->setActiveShader(shader->shader);
297 
298     // Setup constants
299     shader->cameraDirection.set(cameraDirection);
300     shader->viewMatrix.set(camera->globalTransform);
301 
302     shader->depthTexture.set(theDepthTex);
303     shader->cubeTexture.set(theDepthCube);
304     shader->depthTextureSize.set(QVector2D(theDepthTex->textureDetails().width, theDepthTex->textureDetails().height));
305 
306     // Important uniforms for AO calculations
307     QVector2D theCameraProps = QVector2D(camera->clipNear, camera->clipFar);
308     shader->cameraProperties.set(theCameraProps);
309     shader->aoShadowParams.set();
310 
311     // Draw a fullscreen quad
312     renderer->renderQuad();
313 
314     renderer->endLayerDepthPassRender();
315 }
316 #endif
317 
318 namespace {
319 
computeFrustumBounds(const QSSGRenderCamera & inCamera,const QRectF & inViewPort,QVector3D & ctrBound,QVector3D camVerts[8])320 void computeFrustumBounds(const QSSGRenderCamera &inCamera, const QRectF &inViewPort, QVector3D &ctrBound, QVector3D camVerts[8])
321 {
322     QVector3D camEdges[4];
323 
324     const float *dataPtr(inCamera.globalTransform.constData());
325     QVector3D camX(dataPtr[0], dataPtr[1], dataPtr[2]);
326     QVector3D camY(dataPtr[4], dataPtr[5], dataPtr[6]);
327     QVector3D camZ(dataPtr[8], dataPtr[9], dataPtr[10]);
328 
329     float tanFOV = tanf(inCamera.verticalFov(inViewPort) * 0.5f);
330     float asTanFOV = tanFOV * inViewPort.width() / inViewPort.height();
331     camEdges[0] = -asTanFOV * camX + tanFOV * camY + camZ;
332     camEdges[1] = asTanFOV * camX + tanFOV * camY + camZ;
333     camEdges[2] = asTanFOV * camX - tanFOV * camY + camZ;
334     camEdges[3] = -asTanFOV * camX - tanFOV * camY + camZ;
335 
336     for (int i = 0; i < 4; ++i) {
337         camEdges[i].setX(-camEdges[i].x());
338         camEdges[i].setY(-camEdges[i].y());
339     }
340 
341     camVerts[0] = inCamera.position + camEdges[0] * inCamera.clipNear;
342     camVerts[1] = inCamera.position + camEdges[0] * inCamera.clipFar;
343     camVerts[2] = inCamera.position + camEdges[1] * inCamera.clipNear;
344     camVerts[3] = inCamera.position + camEdges[1] * inCamera.clipFar;
345     camVerts[4] = inCamera.position + camEdges[2] * inCamera.clipNear;
346     camVerts[5] = inCamera.position + camEdges[2] * inCamera.clipFar;
347     camVerts[6] = inCamera.position + camEdges[3] * inCamera.clipNear;
348     camVerts[7] = inCamera.position + camEdges[3] * inCamera.clipFar;
349 
350     ctrBound = camVerts[0];
351     for (int i = 1; i < 8; ++i) {
352         ctrBound += camVerts[i];
353     }
354     ctrBound *= 0.125f;
355 }
356 
calculateShadowCameraBoundingBox(const QVector3D * points,const QVector3D & forward,const QVector3D & up,const QVector3D & right)357 QSSGBounds3 calculateShadowCameraBoundingBox(const QVector3D *points, const QVector3D &forward,
358                                              const QVector3D &up, const QVector3D &right)
359 {
360     float minDistanceZ = std::numeric_limits<float>::max();
361     float maxDistanceZ = -std::numeric_limits<float>::max();
362     float minDistanceY = std::numeric_limits<float>::max();
363     float maxDistanceY = -std::numeric_limits<float>::max();
364     float minDistanceX = std::numeric_limits<float>::max();
365     float maxDistanceX = -std::numeric_limits<float>::max();
366     for (int i = 0; i < 8; ++i) {
367         float distanceZ = QVector3D::dotProduct(points[i], forward);
368         if (distanceZ < minDistanceZ)
369             minDistanceZ = distanceZ;
370         if (distanceZ > maxDistanceZ)
371             maxDistanceZ = distanceZ;
372         float distanceY = QVector3D::dotProduct(points[i], up);
373         if (distanceY < minDistanceY)
374             minDistanceY = distanceY;
375         if (distanceY > maxDistanceY)
376             maxDistanceY = distanceY;
377         float distanceX = QVector3D::dotProduct(points[i], right);
378         if (distanceX < minDistanceX)
379             minDistanceX = distanceX;
380         if (distanceX > maxDistanceX)
381             maxDistanceX = distanceX;
382     }
383     return QSSGBounds3(QVector3D(minDistanceX, minDistanceY, minDistanceZ),
384                        QVector3D(maxDistanceX, maxDistanceY, maxDistanceZ));
385 }
386 
setupCameraForShadowMap(const QVector2D &,QSSGRenderContext &,const QRectF & inViewport,const QSSGRenderCamera & inCamera,const QSSGRenderLight * inLight,QSSGRenderCamera & theCamera,QVector3D * scenePoints=nullptr)387 void setupCameraForShadowMap(const QVector2D &/*inCameraVec*/,
388                              QSSGRenderContext & /*inContext*/,
389                              const QRectF &inViewport,
390                              const QSSGRenderCamera &inCamera,
391                              const QSSGRenderLight *inLight,
392                              QSSGRenderCamera &theCamera,
393                              QVector3D *scenePoints = nullptr)
394 {
395     // setup light matrix
396     quint32 mapRes = 1 << inLight->m_shadowMapRes;
397     QRectF theViewport(0.0f, 0.0f, (float)mapRes, (float)mapRes);
398     theCamera.clipNear = 1.0f;
399     theCamera.clipFar = inLight->m_shadowMapFar;
400     // Setup camera projection
401     QVector3D inLightPos = inLight->getGlobalPos();
402     QVector3D inLightDir = inLight->getDirection();
403 
404     inLightPos -= inLightDir * inCamera.clipNear;
405     theCamera.fov = qDegreesToRadians(90.f);
406 
407     if (inLight->m_lightType == QSSGRenderLight::Type::Directional) {
408         QVector3D frustumPoints[8], boundCtr, sceneCtr;
409         computeFrustumBounds(inCamera, inViewport, boundCtr, frustumPoints);
410 
411         if (scenePoints) {
412             sceneCtr = QVector3D(0, 0, 0);
413             for (int i = 0; i < 8; ++i)
414                 sceneCtr += scenePoints[i];
415             sceneCtr *= 0.125f;
416         }
417 
418         QVector3D forward = inLightDir;
419         forward.normalize();
420         QVector3D right;
421         if (!qFuzzyCompare(qAbs(forward.y()), 1.0f))
422             right = QVector3D::crossProduct(forward, QVector3D(0, 1, 0));
423         else
424             right = QVector3D::crossProduct(forward, QVector3D(1, 0, 0));
425         right.normalize();
426         QVector3D up = QVector3D::crossProduct(right, forward);
427         up.normalize();
428 
429         // Calculate bounding box of the scene camera frustum
430         QSSGBounds3 bounds = calculateShadowCameraBoundingBox(frustumPoints, forward, up, right);
431         inLightPos = boundCtr;
432         if (scenePoints) {
433             QSSGBounds3 sceneBounds = calculateShadowCameraBoundingBox(scenePoints, forward, up,
434                                                                        right);
435             if (sceneBounds.extents().x() * sceneBounds.extents().y() * sceneBounds.extents().z()
436                     < bounds.extents().x() * bounds.extents().y() * bounds.extents().z()) {
437                 bounds = sceneBounds;
438                 inLightPos = sceneCtr;
439             }
440         }
441 
442         // Apply bounding box parameters to shadow map camera projection matrix
443         // so that the whole scene is fit inside the shadow map
444         theViewport.setHeight(bounds.extents().y() * 2);
445         theViewport.setWidth(bounds.extents().x() * 2);
446         theCamera.clipNear = -bounds.extents().z() * 2;
447         theCamera.clipFar = bounds.extents().z() * 2;
448     }
449 
450     theCamera.flags.setFlag(QSSGRenderCamera::Flag::Orthographic, inLight->m_lightType == QSSGRenderLight::Type::Directional);
451     theCamera.parent = nullptr;
452     theCamera.pivot = inLight->pivot;
453 
454     if (inLight->m_lightType != QSSGRenderLight::Type::Point) {
455         theCamera.lookAt(inLightPos, QVector3D(0, 1.0, 0), inLightPos + inLightDir);
456     } else {
457         theCamera.lookAt(inLightPos, QVector3D(0, 1.0, 0), QVector3D(0, 0, 0));
458     }
459 
460     theCamera.calculateGlobalVariables(theViewport);
461 }
462 }
463 
setupCubeShadowCameras(const QSSGRenderLight * inLight,QSSGRenderCamera inCameras[6])464 void setupCubeShadowCameras(const QSSGRenderLight *inLight, QSSGRenderCamera inCameras[6])
465 {
466     // setup light matrix
467     quint32 mapRes = 1 << inLight->m_shadowMapRes;
468     QRectF theViewport(0.0f, 0.0f, (float)mapRes, (float)mapRes);
469     QQuaternion rotOfs[6];
470 
471     Q_ASSERT(inLight != nullptr);
472     Q_ASSERT(inLight->m_lightType != QSSGRenderLight::Type::Directional);
473 
474     const QVector3D inLightPos = inLight->getGlobalPos();
475 
476     rotOfs[0] = QQuaternion::fromEulerAngles(0.f, qRadiansToDegrees(-QSSG_HALFPI), qRadiansToDegrees(QSSG_PI));
477     rotOfs[1] = QQuaternion::fromEulerAngles(0.f, qRadiansToDegrees(QSSG_HALFPI), qRadiansToDegrees(QSSG_PI));
478     rotOfs[2] = QQuaternion::fromEulerAngles(qRadiansToDegrees(QSSG_HALFPI), 0.f, 0.f);
479     rotOfs[3] = QQuaternion::fromEulerAngles(qRadiansToDegrees(-QSSG_HALFPI), 0.f, 0.f);
480     rotOfs[4] = QQuaternion::fromEulerAngles(0.f, qRadiansToDegrees(QSSG_PI), qRadiansToDegrees(-QSSG_PI));
481     rotOfs[5] = QQuaternion::fromEulerAngles(0.f, 0.f, qRadiansToDegrees(QSSG_PI));
482 
483     for (int i = 0; i < 6; ++i) {
484         inCameras[i].flags.setFlag(QSSGRenderCamera::Flag::Orthographic, false);
485         inCameras[i].parent = nullptr;
486         inCameras[i].pivot = inLight->pivot;
487         inCameras[i].clipNear = 1.0f;
488         inCameras[i].clipFar = qMax<float>(2.0f, inLight->m_shadowMapFar);
489         inCameras[i].fov = qDegreesToRadians(90.f);
490 
491         inCameras[i].position = inLightPos;
492         inCameras[i].rotation = rotOfs[i];
493         inCameras[i].calculateGlobalVariables(theViewport);
494     }
495 
496     /*
497         if ( inLight->m_LightType == RenderLightTypes::Point ) return;
498 
499         QVector3D viewDirs[6];
500         QVector3D viewUp[6];
501         QMatrix3x3 theDirMatrix( inLight->m_GlobalTransform.getUpper3x3() );
502 
503         viewDirs[0] = theDirMatrix.transform( QVector3D( 1.f, 0.f, 0.f ) );
504         viewDirs[2] = theDirMatrix.transform( QVector3D( 0.f, -1.f, 0.f ) );
505         viewDirs[4] = theDirMatrix.transform( QVector3D( 0.f, 0.f, 1.f ) );
506         viewDirs[0].normalize();  viewDirs[2].normalize();  viewDirs[4].normalize();
507         viewDirs[1] = -viewDirs[0];
508         viewDirs[3] = -viewDirs[2];
509         viewDirs[5] = -viewDirs[4];
510 
511         viewUp[0] = viewDirs[2];
512         viewUp[1] = viewDirs[2];
513         viewUp[2] = viewDirs[5];
514         viewUp[3] = viewDirs[4];
515         viewUp[4] = viewDirs[2];
516         viewUp[5] = viewDirs[2];
517 
518         for (int i = 0; i < 6; ++i)
519         {
520                 inCameras[i].LookAt( inLightPos, viewUp[i], inLightPos + viewDirs[i] );
521                 inCameras[i].CalculateGlobalVariables( theViewport, QVector2D( theViewport.m_Width,
522         theViewport.m_Height ) );
523         }
524         */
525 }
526 
renderRenderableShadowMapPass(QSSGLayerRenderData & inData,QSSGRenderableObject & inObject,const QVector2D & inCameraProps,const ShaderFeatureSetList &,quint32 lightIndex,const QSSGRenderCamera & inCamera)527 inline void renderRenderableShadowMapPass(QSSGLayerRenderData &inData,
528                                           QSSGRenderableObject &inObject,
529                                           const QVector2D &inCameraProps,
530                                           const ShaderFeatureSetList &,
531                                           quint32 lightIndex,
532                                           const QSSGRenderCamera &inCamera)
533 {
534     QSSGShadowMapEntry *pEntry = inData.shadowMapManager->getShadowMapEntry(lightIndex);
535 
536     // If the object is marked that it doesn't cast shadows, then skip it.
537     if (!inObject.renderableFlags.castsShadows())
538         return;
539 
540     if (inObject.renderableFlags.isDefaultMaterialMeshSubset())
541         static_cast<QSSGSubsetRenderableBase &>(inObject).renderShadowMapPass(inCameraProps, inData.globalLights[lightIndex], inCamera, pEntry);
542     else if (inObject.renderableFlags.isCustomMaterialMeshSubset())
543         static_cast<QSSGSubsetRenderableBase &>(inObject).renderShadowMapPass(inCameraProps, inData.globalLights[lightIndex], inCamera, pEntry);
544 }
545 
renderShadowCubeBlurPass(QSSGResourceFrameBuffer * theFB,const QSSGRef<QSSGRenderTextureCube> & target0,const QSSGRef<QSSGRenderTextureCube> & target1,float filterSz,float clipFar)546 void QSSGLayerRenderData::renderShadowCubeBlurPass(QSSGResourceFrameBuffer *theFB,
547                                                      const QSSGRef<QSSGRenderTextureCube> &target0,
548                                                      const QSSGRef<QSSGRenderTextureCube> &target1,
549                                                      float filterSz,
550                                                      float clipFar)
551 {
552     const auto &theContext = renderer->context();
553 
554     QSSGRef<QSSGShadowmapPreblurShader> shaderX = renderer->getCubeShadowBlurXShader();
555     QSSGRef<QSSGShadowmapPreblurShader> shaderY = renderer->getCubeShadowBlurYShader();
556 
557     if (shaderX == nullptr)
558         return;
559     if (shaderY == nullptr)
560         return;
561     // if ( theShader == nullptr ) return;
562 
563     // Enable drawing to 6 color attachment buffers for cubemap passes
564     qint32 buffers[6] = { 0, 1, 2, 3, 4, 5 };
565     QSSGDataView<qint32> bufferList(buffers, 6);
566     theContext->setDrawBuffers(bufferList);
567 
568     // Attach framebuffer targets
569     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color0, target1, QSSGRenderTextureCubeFace::CubePosX);
570     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color1, target1, QSSGRenderTextureCubeFace::CubeNegX);
571     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color2, target1, QSSGRenderTextureCubeFace::CubePosY);
572     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color3, target1, QSSGRenderTextureCubeFace::CubeNegY);
573     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color4, target1, QSSGRenderTextureCubeFace::CubePosZ);
574     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color5, target1, QSSGRenderTextureCubeFace::CubeNegZ);
575 
576     // Set initial state
577     theContext->setBlendingEnabled(false);
578     theContext->setDepthWriteEnabled(false);
579     theContext->setDepthTestEnabled(false);
580     // theContext.SetColorWritesEnabled(true);
581     theContext->setActiveShader(shaderX->shader);
582 
583     shaderX->cameraProperties.set(QVector2D(filterSz, clipFar));
584     shaderX->depthCube.set(target0.data());
585 
586     // Draw a fullscreen quad
587     renderer->renderQuad();
588 
589     theContext->setActiveShader(shaderY->shader);
590 
591     // Lather, Rinse, and Repeat for the Y-blur pass
592     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color0, target0, QSSGRenderTextureCubeFace::CubePosX);
593     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color1, target0, QSSGRenderTextureCubeFace::CubeNegX);
594     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color2, target0, QSSGRenderTextureCubeFace::CubePosY);
595     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color3, target0, QSSGRenderTextureCubeFace::CubeNegY);
596     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color4, target0, QSSGRenderTextureCubeFace::CubePosZ);
597     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color5, target0, QSSGRenderTextureCubeFace::CubeNegZ);
598 
599     shaderY->cameraProperties.set(QVector2D(filterSz, clipFar));
600     shaderY->depthCube.set(target1.data());
601 
602     // Draw a fullscreen quad
603     renderer->renderQuad();
604 
605     theContext->setDepthWriteEnabled(true);
606     theContext->setDepthTestEnabled(true);
607     // theContext.SetColorWritesEnabled(false);
608 
609     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color0,
610                          QSSGRenderTextureOrRenderBuffer(),
611                          QSSGRenderTextureCubeFace::CubePosX);
612     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color1,
613                          QSSGRenderTextureOrRenderBuffer(),
614                          QSSGRenderTextureCubeFace::CubeNegX);
615     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color2,
616                          QSSGRenderTextureOrRenderBuffer(),
617                          QSSGRenderTextureCubeFace::CubePosY);
618     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color3,
619                          QSSGRenderTextureOrRenderBuffer(),
620                          QSSGRenderTextureCubeFace::CubeNegY);
621     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color4,
622                          QSSGRenderTextureOrRenderBuffer(),
623                          QSSGRenderTextureCubeFace::CubePosZ);
624     (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color5,
625                          QSSGRenderTextureOrRenderBuffer(),
626                          QSSGRenderTextureCubeFace::CubeNegZ);
627 
628     qint32 null = 0;
629     theContext->setDrawBuffers(toDataView(null));
630 }
631 
renderShadowMapBlurPass(QSSGResourceFrameBuffer * theFB,const QSSGRef<QSSGRenderTexture2D> & target0,const QSSGRef<QSSGRenderTexture2D> & target1,float filterSz,float clipFar)632 void QSSGLayerRenderData::renderShadowMapBlurPass(QSSGResourceFrameBuffer *theFB,
633                                                     const QSSGRef<QSSGRenderTexture2D> &target0,
634                                                     const QSSGRef<QSSGRenderTexture2D> &target1,
635                                                     float filterSz,
636                                                     float clipFar)
637 {
638     const auto &theContext = renderer->context();
639 
640     QSSGRef<QSSGShadowmapPreblurShader> shaderX = renderer->getOrthoShadowBlurXShader();
641     QSSGRef<QSSGShadowmapPreblurShader> shaderY = renderer->getOrthoShadowBlurYShader();
642 
643     if (shaderX == nullptr)
644         return;
645     if (shaderY == nullptr)
646         return;
647 
648     // Attach framebuffer target
649     (*theFB)->attach(QSSGRenderFrameBufferAttachment::Color0, target1);
650     //(*theFB)->Attach( QSSGRenderFrameBufferAttachments::DepthStencil, *target1 );
651 
652     // Set initial state
653     theContext->setBlendingEnabled(false);
654     theContext->setDepthWriteEnabled(false);
655     theContext->setDepthTestEnabled(false);
656     theContext->setColorWritesEnabled(true);
657     theContext->setActiveShader(shaderX->shader);
658 
659     shaderX->cameraProperties.set(QVector2D(filterSz, clipFar));
660     shaderX->depthMap.set(target0.data());
661 
662     // Draw a fullscreen quad
663     renderer->renderQuad();
664 
665     (*theFB)->attach(QSSGRenderFrameBufferAttachment::Color0, target0);
666     //(*theFB)->Attach( QSSGRenderFrameBufferAttachments::DepthStencil, *target0 );
667     theContext->setActiveShader(shaderY->shader);
668 
669     shaderY->cameraProperties.set(QVector2D(filterSz, clipFar));
670     shaderY->depthMap.set(target1.data());
671 
672     // Draw a fullscreen quad
673     renderer->renderQuad();
674 
675     theContext->setDepthWriteEnabled(true);
676     theContext->setDepthTestEnabled(true);
677     theContext->setColorWritesEnabled(false);
678 
679     //(*theFB)->Attach( QSSGRenderFrameBufferAttachments::DepthStencil,
680     // QSSGRenderTextureOrRenderBuffer() );
681     (*theFB)->attach(QSSGRenderFrameBufferAttachment::Color0, QSSGRenderTextureOrRenderBuffer());
682 }
683 
renderShadowMapPass(QSSGResourceFrameBuffer * theFB)684 void QSSGLayerRenderData::renderShadowMapPass(QSSGResourceFrameBuffer *theFB)
685 {
686     QSSGStackPerfTimer ___timer(renderer->contextInterface()->performanceTimer(), Q_FUNC_INFO);
687 
688     if (!camera)
689         return;
690 
691     if (!shadowMapManager)
692         createShadowMapManager();
693 
694     // Check if we have anything to render
695     if (opaqueObjects.size() == 0 || globalLights.size() == 0)
696         return;
697 
698     renderer->beginLayerDepthPassRender(*this);
699 
700     const auto &theRenderContext = renderer->context();
701 
702     // we may change the viewport
703     QSSGRenderContextScopedProperty<QRect> __viewport(*theRenderContext, &QSSGRenderContext::viewport, &QSSGRenderContext::setViewport);
704 
705     // disable color writes
706     // theRenderContext.SetColorWritesEnabled( false );
707     theRenderContext->setColorWritesEnabled(true);
708     theRenderContext->setDepthWriteEnabled(true);
709     theRenderContext->setCullingEnabled(false);
710     theRenderContext->setClearColor(QVector4D(1.0, 1.0, 1.0, 1.0));
711 
712     // we render the shadow map with a slight offset to prevent shadow acne and cull the front
713     // faces
714     QSSGRef<QSSGRenderRasterizerState> rsdefaultstate = new QSSGRenderRasterizerState(theRenderContext, 0.0, 0.0);
715     QSSGRef<QSSGRenderRasterizerState> rsstate = new QSSGRenderRasterizerState(theRenderContext, 1.5, 2.0);
716     theRenderContext->setRasterizerState(rsstate);
717 
718     QSSGRenderClearFlags clearFlags(QSSGRenderClearValues::Depth | QSSGRenderClearValues::Stencil
719                                       | QSSGRenderClearValues::Color);
720 
721     auto bounds = camera->parent->getBounds(renderer->contextInterface()->bufferManager());
722 
723     QVector3D scenePoints[8];
724     scenePoints[0] = bounds.minimum;
725     scenePoints[1] = QVector3D(bounds.maximum.x(), bounds.minimum.y(), bounds.minimum.z());
726     scenePoints[2] = QVector3D(bounds.minimum.x(), bounds.maximum.y(), bounds.minimum.z());
727     scenePoints[3] = QVector3D(bounds.maximum.x(), bounds.maximum.y(), bounds.minimum.z());
728     scenePoints[4] = QVector3D(bounds.minimum.x(), bounds.minimum.y(), bounds.maximum.z());
729     scenePoints[5] = QVector3D(bounds.maximum.x(), bounds.minimum.y(), bounds.maximum.z());
730     scenePoints[6] = QVector3D(bounds.minimum.x(), bounds.maximum.y(), bounds.maximum.z());
731     scenePoints[7] = bounds.maximum;
732 
733     for (int i = 0; i < globalLights.size(); i++) {
734         // don't render shadows when not casting
735         if (!globalLights[i]->m_castShadow)
736             continue;
737 
738         QSSGShadowMapEntry *pEntry = shadowMapManager->getShadowMapEntry(i);
739         if (pEntry && pEntry->m_depthMap && pEntry->m_depthCopy && pEntry->m_depthRender) {
740             QSSGRenderCamera theCamera;
741 
742             QVector2D theCameraProps = QVector2D(camera->clipNear, camera->clipFar);
743             setupCameraForShadowMap(theCameraProps, *renderer->context(), __viewport.m_initialValue,
744                                     *camera, globalLights[i], theCamera, scenePoints);
745             // we need this matrix for the final rendering
746             theCamera.calculateViewProjectionMatrix(pEntry->m_lightVP);
747             pEntry->m_lightView = theCamera.globalTransform.inverted();
748 
749             QSSGTextureDetails theDetails(pEntry->m_depthMap->textureDetails());
750             theRenderContext->setViewport(QRect(0, 0, (quint32)theDetails.width, (quint32)theDetails.height));
751 
752             (*theFB)->attach(QSSGRenderFrameBufferAttachment::Color0, pEntry->m_depthMap);
753             (*theFB)->attach(QSSGRenderFrameBufferAttachment::DepthStencil, pEntry->m_depthRender);
754             theRenderContext->clear(clearFlags);
755 
756             runRenderPass(renderRenderableShadowMapPass, false, true, true, true, i, theCamera);
757             renderShadowMapBlurPass(theFB, pEntry->m_depthMap, pEntry->m_depthCopy, globalLights[i]->m_shadowFilter, globalLights[i]->m_shadowMapFar);
758         } else if (pEntry && pEntry->m_depthCube && pEntry->m_cubeCopy && pEntry->m_depthRender) {
759             QSSGRenderCamera theCameras[6];
760 
761             setupCubeShadowCameras(globalLights[i], theCameras);
762 
763             // pEntry->m_LightView = m_Lights[i]->m_LightType == RenderLightTypes::Point ?
764             // QMatrix4x4::createIdentity()
765             //	: m_Lights[i]->m_GlobalTransform;
766             pEntry->m_lightView = QMatrix4x4();
767 
768             QSSGTextureDetails theDetails(pEntry->m_depthCube->textureDetails());
769             theRenderContext->setViewport(QRect(0, 0, (quint32)theDetails.width, (quint32)theDetails.height));
770 
771             // int passes = m_Lights[i]->m_LightType == RenderLightTypes::Point ? 6 : 5;
772             int passes = 6;
773             for (int k = 0; k < passes; ++k) {
774                 // theCameras[k].CalculateViewProjectionMatrix( pEntry->m_LightCubeVP[k] );
775                 pEntry->m_lightCubeView[k] = theCameras[k].globalTransform.inverted();
776                 theCameras[k].calculateViewProjectionMatrix(pEntry->m_lightVP);
777 
778                 // Geometry shader multiplication really doesn't work unless you have a
779                 // 6-layered 3D depth texture...
780                 // Otherwise, you have no way to depth test while rendering...
781                 // which more or less completely defeats the purpose of having a cubemap render
782                 // target.
783                 QSSGRenderTextureCubeFace curFace = (QSSGRenderTextureCubeFace)(k + 1);
784                 //(*theFB)->AttachFace( QSSGRenderFrameBufferAttachments::DepthStencil,
785                 //*pEntry->m_DepthCube, curFace );
786                 (*theFB)->attach(QSSGRenderFrameBufferAttachment::DepthStencil, pEntry->m_depthRender);
787                 (*theFB)->attachFace(QSSGRenderFrameBufferAttachment::Color0, pEntry->m_depthCube, curFace);
788                 (*theFB)->isComplete();
789                 theRenderContext->clear(clearFlags);
790 
791                 runRenderPass(renderRenderableShadowMapPass, false, true, true, true, i, theCameras[k]);
792             }
793 
794             renderShadowCubeBlurPass(theFB,
795                                      pEntry->m_depthCube,
796                                      pEntry->m_cubeCopy,
797                                      globalLights[i]->m_shadowFilter,
798                                      globalLights[i]->m_shadowMapFar);
799         }
800     }
801 
802     (*theFB)->attach(QSSGRenderFrameBufferAttachment::Depth, QSSGRenderTextureOrRenderBuffer());
803     (*theFB)->attach(QSSGRenderFrameBufferAttachment::Color0, QSSGRenderTextureOrRenderBuffer());
804 
805     // enable color writes
806     theRenderContext->setColorWritesEnabled(true);
807     theRenderContext->setCullingEnabled(true);
808     theRenderContext->setClearColor(QVector4D(0.0, 0.0, 0.0, 0.0));
809     // reset rasterizer state
810     theRenderContext->setRasterizerState(rsdefaultstate);
811 
812     renderer->endLayerDepthPassRender();
813 }
814 
renderRenderableDepthPass(QSSGLayerRenderData & inData,QSSGRenderableObject & inObject,const QVector2D & inCameraProps,const ShaderFeatureSetList &,quint32,const QSSGRenderCamera & inCamera)815 inline void renderRenderableDepthPass(QSSGLayerRenderData &inData,
816                                       QSSGRenderableObject &inObject,
817                                       const QVector2D &inCameraProps,
818                                       const ShaderFeatureSetList &,
819                                       quint32,
820                                       const QSSGRenderCamera &inCamera)
821 {
822     if (inObject.renderableFlags.isDefaultMaterialMeshSubset())
823         static_cast<QSSGSubsetRenderable &>(inObject).renderDepthPass(inCameraProps);
824     else if (inObject.renderableFlags.isCustomMaterialMeshSubset())
825         static_cast<QSSGCustomMaterialRenderable &>(inObject).renderDepthPass(inCameraProps, inData.layer, inData.globalLights, inCamera, nullptr);
826     else
827         Q_ASSERT(false);
828 
829 }
830 
renderDepthPass(bool inEnableTransparentDepthWrite)831 void QSSGLayerRenderData::renderDepthPass(bool inEnableTransparentDepthWrite)
832 {
833     QSSGStackPerfTimer ___timer(renderer->contextInterface()->performanceTimer(), Q_FUNC_INFO);
834     if (camera == nullptr)
835         return;
836 
837     // Avoid running this method if possible.
838     if ((!inEnableTransparentDepthWrite
839          && (opaqueObjects.size() == 0 || !layer.flags.testFlag(QSSGRenderLayer::Flag::LayerEnableDepthPrePass)))
840         || !layer.flags.testFlag(QSSGRenderLayer::Flag::LayerEnableDepthTest))
841         return;
842 
843     renderer->beginLayerDepthPassRender(*this);
844 
845     const auto &theRenderContext = renderer->context();
846 
847     // disable color writes
848     theRenderContext->setColorWritesEnabled(false);
849     theRenderContext->setDepthWriteEnabled(true);
850 
851     QSSGRenderClearFlags clearFlags(QSSGRenderClearValues::Stencil | QSSGRenderClearValues::Depth);
852     theRenderContext->clear(clearFlags);
853 
854     runRenderPass(renderRenderableDepthPass, false, true, false, inEnableTransparentDepthWrite, 0, *camera);
855 
856     // enable color writes
857     theRenderContext->setColorWritesEnabled(true);
858 
859     renderer->endLayerDepthPassRender();
860 }
861 
renderRenderable(QSSGLayerRenderData & inData,QSSGRenderableObject & inObject,const QVector2D & inCameraProps,const ShaderFeatureSetList & inFeatureSet,quint32,const QSSGRenderCamera & inCamera)862 inline void renderRenderable(QSSGLayerRenderData &inData,
863                              QSSGRenderableObject &inObject,
864                              const QVector2D &inCameraProps,
865                              const ShaderFeatureSetList &inFeatureSet,
866                              quint32,
867                              const QSSGRenderCamera &inCamera)
868 {
869     if (inObject.renderableFlags.isDefaultMaterialMeshSubset()) {
870         static_cast<QSSGSubsetRenderable &>(inObject).render(inCameraProps, inFeatureSet);
871     } else if (inObject.renderableFlags.isCustomMaterialMeshSubset()) {
872         // PKC : Need a better place to do this.
873         QSSGCustomMaterialRenderable &theObject = static_cast<QSSGCustomMaterialRenderable &>(inObject);
874         if (!inData.layer.lightProbe && theObject.material.m_iblProbe)
875             inData.setShaderFeature(QSSGShaderDefines::asString(QSSGShaderDefines::LightProbe), theObject.material.m_iblProbe->m_textureData.m_texture != nullptr);
876         else if (inData.layer.lightProbe)
877             inData.setShaderFeature(QSSGShaderDefines::asString(QSSGShaderDefines::LightProbe), inData.layer.lightProbe->m_textureData.m_texture != nullptr);
878 
879         static_cast<QSSGCustomMaterialRenderable &>(inObject).render(inCameraProps,
880                                                                        inData,
881                                                                        inData.layer,
882                                                                        inData.globalLights,
883                                                                        inCamera,
884                                                                        inData.m_layerDepthTexture,
885                                                                        inData.m_layerSsaoTexture,
886                                                                        inFeatureSet);
887     } else {
888         Q_ASSERT(false);
889     }
890 }
891 
runRenderPass(TRenderRenderableFunction inRenderFn,bool inEnableBlending,bool inEnableDepthWrite,bool inEnableTransparentDepthWrite,bool inSortOpaqueRenderables,quint32 indexLight,const QSSGRenderCamera & inCamera,QSSGResourceFrameBuffer * theFB)892 void QSSGLayerRenderData::runRenderPass(TRenderRenderableFunction inRenderFn,
893                                           bool inEnableBlending,
894                                           bool inEnableDepthWrite,
895                                           bool inEnableTransparentDepthWrite,
896                                           bool inSortOpaqueRenderables,
897                                           quint32 indexLight,
898                                           const QSSGRenderCamera &inCamera,
899                                           QSSGResourceFrameBuffer *theFB)
900 {
901     Q_UNUSED(theFB)
902     const auto &theRenderContext = renderer->context();
903     theRenderContext->setDepthFunction(QSSGRenderBoolOp::LessThanOrEqual);
904     theRenderContext->setBlendingEnabled(false);
905     QVector2D theCameraProps = QVector2D(camera->clipNear, camera->clipFar);
906     const auto &theOpaqueObjects = getOpaqueRenderableObjects(inSortOpaqueRenderables);
907     bool usingDepthBuffer = layer.flags.testFlag(QSSGRenderLayer::Flag::LayerEnableDepthTest) && theOpaqueObjects.size() > 0;
908 
909     if (usingDepthBuffer) {
910         theRenderContext->setDepthTestEnabled(true);
911         theRenderContext->setDepthWriteEnabled(inEnableDepthWrite);
912     } else {
913         theRenderContext->setDepthWriteEnabled(false);
914         theRenderContext->setDepthTestEnabled(false);
915     }
916 
917     for (const auto &handle : theOpaqueObjects) {
918         QSSGRenderableObject *theObject = handle.obj;
919         QSSGScopedLightsListScope lightsScope(globalLights, lightDirections, sourceLightDirections, theObject->scopedLights);
920         setShaderFeature(QSSGShaderDefines::asString(QSSGShaderDefines::CgLighting), !globalLights.empty());
921         inRenderFn(*this, *theObject, theCameraProps, getShaderFeatureSet(), indexLight, inCamera);
922     }
923 
924     // Render Quick items
925     for (auto theNodeEntry : getRenderableItem2Ds()) {
926         QSSGRenderItem2D *item2D = static_cast<QSSGRenderItem2D *>(theNodeEntry.node);
927         // Fast-path to avoid rendering totally transparent items
928         if (item2D->combinedOpacity < QSSG_RENDER_MINIMUM_RENDER_OPACITY)
929             continue;
930         // Don't try rendering until texture exists
931         if (!item2D->qsgTexture)
932             continue;
933         QVector2D dimensions = QVector2D(item2D->qsgTexture->textureSize().width(),
934                                          item2D->qsgTexture->textureSize().height());
935         QSSGRenderTexture2D tex(renderer->context(), item2D->qsgTexture);
936 
937         renderer->renderFlippedQuad(dimensions, item2D->MVP, tex, item2D->combinedOpacity);
938     }
939 
940     // transparent objects
941     if (inEnableBlending || !layer.flags.testFlag(QSSGRenderLayer::Flag::LayerEnableDepthTest)) {
942         theRenderContext->setBlendingEnabled(inEnableBlending);
943         theRenderContext->setDepthWriteEnabled(inEnableTransparentDepthWrite);
944 
945         const auto &theTransparentObjects = getTransparentRenderableObjects();
946         // Assume all objects have transparency if the layer's depth test enabled flag is true.
947         if (layer.flags.testFlag(QSSGRenderLayer::Flag::LayerEnableDepthTest)) {
948             for (const auto &handle : theTransparentObjects) {
949                 QSSGRenderableObject *theObject = handle.obj;
950                 if (!(theObject->renderableFlags.isCompletelyTransparent())) {
951                     QSSGScopedLightsListScope lightsScope(globalLights, lightDirections, sourceLightDirections, theObject->scopedLights);
952                     setShaderFeature(QSSGShaderDefines::asString(QSSGShaderDefines::CgLighting), !globalLights.empty());
953 
954                     inRenderFn(*this, *theObject, theCameraProps, getShaderFeatureSet(), indexLight, inCamera);
955                 }
956             }
957         }
958         // If the layer doesn't have depth enabled then we have to render via an alternate route
959         // where the transparent objects vector could have both opaque and transparent objects.
960         else {
961             for (const auto &handle : theTransparentObjects) {
962                 QSSGRenderableObject *theObject = handle.obj;
963                 if (!(theObject->renderableFlags.isCompletelyTransparent())) {
964                     QSSGScopedLightsListScope lightsScope(globalLights, lightDirections, sourceLightDirections, theObject->scopedLights);
965                     setShaderFeature(QSSGShaderDefines::asString(QSSGShaderDefines::CgLighting), !globalLights.empty());
966                     inRenderFn(*this, *theObject, theCameraProps, getShaderFeatureSet(), indexLight, inCamera);
967                 }
968             }
969         }
970     }
971 }
972 
render(QSSGResourceFrameBuffer * theFB)973 void QSSGLayerRenderData::render(QSSGResourceFrameBuffer *theFB)
974 {
975     QSSGStackPerfTimer ___timer(renderer->contextInterface()->performanceTimer(), Q_FUNC_INFO);
976     if (camera == nullptr)
977         return;
978 
979     renderer->beginLayerRender(*this);
980     runRenderPass(renderRenderable, true, !layer.flags.testFlag(QSSGRenderLayer::Flag::LayerEnableDepthPrePass), false, true, 0, *camera, theFB);
981     renderer->endLayerRender();
982 }
983 
createGpuProfiler()984 void QSSGLayerRenderData::createGpuProfiler()
985 {
986     if (renderer->context()->supportsTimerQuery()) {
987         m_layerProfilerGpu.reset(new QSSGRenderGPUProfiler(renderer->contextInterface(), renderer->context()));
988     }
989 }
990 
startProfiling(QString & nameID,bool sync)991 void QSSGLayerRenderData::startProfiling(QString &nameID, bool sync)
992 {
993     if (m_layerProfilerGpu) {
994         m_layerProfilerGpu->startTimer(nameID, false, sync);
995     }
996 }
997 
endProfiling(QString & nameID)998 void QSSGLayerRenderData::endProfiling(QString &nameID)
999 {
1000     if (m_layerProfilerGpu) {
1001         m_layerProfilerGpu->endTimer(nameID);
1002     }
1003 }
1004 
startProfiling(const char * nameID,bool sync)1005 void QSSGLayerRenderData::startProfiling(const char *nameID, bool sync)
1006 {
1007     if (m_layerProfilerGpu) {
1008         QString theStr(QString::fromLocal8Bit(nameID));
1009         m_layerProfilerGpu->startTimer(theStr, false, sync);
1010     }
1011 }
1012 
endProfiling(const char * nameID)1013 void QSSGLayerRenderData::endProfiling(const char *nameID)
1014 {
1015     if (m_layerProfilerGpu) {
1016         QString theStr(QString::fromLocal8Bit(nameID));
1017         m_layerProfilerGpu->endTimer(theStr);
1018     }
1019 }
1020 
addVertexCount(quint32 count)1021 void QSSGLayerRenderData::addVertexCount(quint32 count)
1022 {
1023     if (m_layerProfilerGpu) {
1024         m_layerProfilerGpu->addVertexCount(count);
1025     }
1026 }
1027 
1028 // These are meant to be pixel offsets, so you need to divide them by the width/height
1029 // of the layer respectively.
1030 const QVector2D s_VertexOffsets[QSSGLayerRenderPreparationData::MAX_AA_LEVELS] = {
1031     QVector2D(-0.170840f, -0.553840f), // 1x
1032     QVector2D(0.162960f, -0.319340f), // 2x
1033     QVector2D(0.360260f, -0.245840f), // 3x
1034     QVector2D(-0.561340f, -0.149540f), // 4x
1035     QVector2D(0.249460f, 0.453460f), // 5x
1036     QVector2D(-0.336340f, 0.378260f), // 6x
1037     QVector2D(0.340000f, 0.166260f), // 7x
1038     QVector2D(0.235760f, 0.527760f), // 8x
1039 };
1040 
1041 // Blend factors are in the form of (frame blend factor, accumulator blend factor)
1042 const QVector2D s_BlendFactors[QSSGLayerRenderPreparationData::MAX_AA_LEVELS] = {
1043     QVector2D(0.500000f, 0.500000f), // 1x
1044     QVector2D(0.333333f, 0.666667f), // 2x
1045     QVector2D(0.250000f, 0.750000f), // 3x
1046     QVector2D(0.200000f, 0.800000f), // 4x
1047     QVector2D(0.166667f, 0.833333f), // 5x
1048     QVector2D(0.142857f, 0.857143f), // 6x
1049     QVector2D(0.125000f, 0.875000f), // 7x
1050     QVector2D(0.111111f, 0.888889f), // 8x
1051 };
1052 
offsetProjectionMatrix(QMatrix4x4 & inProjectionMatrix,const QVector2D & inVertexOffsets)1053 static inline void offsetProjectionMatrix(QMatrix4x4 &inProjectionMatrix,
1054                                           const QVector2D &inVertexOffsets)
1055 {
1056     inProjectionMatrix(0, 3) += inProjectionMatrix(3, 3) * inVertexOffsets.x();
1057     inProjectionMatrix(1, 3) += inProjectionMatrix(3, 3) * inVertexOffsets.y();
1058 }
1059 
applyLayerPostEffects(const QSSGRef<QSSGRenderFrameBuffer> & theFB)1060 void QSSGLayerRenderData::applyLayerPostEffects(const QSSGRef<QSSGRenderFrameBuffer> &theFB)
1061 {
1062     if (layer.firstEffect == nullptr || camera == nullptr)
1063         return;
1064 
1065     QSSGLayerRenderPreparationResult &thePrepResult(*layerPrepResult);
1066     const auto lastEffect = thePrepResult.lastEffect;
1067     // we use the non MSAA buffer for the effect
1068     const QSSGRef<QSSGRenderTexture2D> &theLayerColorTexture = m_layerTexture.getTexture();
1069     const QSSGRef<QSSGRenderTexture2D> &theLayerDepthTexture = m_layerDepthTexture.getTexture();
1070 
1071     QSSGRef<QSSGRenderTexture2D> theCurrentTexture = theLayerColorTexture;
1072     const QSSGRef<QSSGEffectSystem> &theEffectSystem(renderer->contextInterface()->effectSystem());
1073     const QSSGRef<QSSGResourceManager> &theResourceManager(renderer->contextInterface()->resourceManager());
1074 
1075     // Process all effect except the last one as the last effect should target the original FB
1076     for (QSSGRenderEffect *theEffect = layer.firstEffect; theEffect && theEffect != lastEffect; theEffect = theEffect->m_nextEffect) {
1077         if (theEffect->flags.testFlag(QSSGRenderEffect::Flag::Active)) {
1078             startProfiling(theEffect->className, false);
1079             QSSGRef<QSSGRenderTexture2D> theRenderedEffect = theEffectSystem->renderEffect(QSSGEffectRenderArgument(theEffect,
1080                                                                                                                     theCurrentTexture,
1081                                                                                                                     QVector2D(camera->clipNear, camera->clipFar),
1082                                                                                                                     theLayerDepthTexture,
1083                                                                                                                     m_layerPrepassDepthTexture));
1084 
1085             endProfiling(theEffect->className);
1086 
1087             // If the texture came from rendering a chain of effects, then we don't need it
1088             // after this.
1089             if (theCurrentTexture != theLayerColorTexture)
1090                 theResourceManager->release(theCurrentTexture);
1091 
1092             theCurrentTexture = theRenderedEffect;
1093 
1094             if (Q_UNLIKELY(!theRenderedEffect)) {
1095                 QString errorMsg = QObject::tr("Failed to compile \"%1\" effect.\nConsider"
1096                                                " removing it from the presentation.")
1097                                            .arg(QString::fromLatin1(theEffect->className));
1098                 qFatal("%s", errorMsg.toUtf8().constData());
1099             }
1100         }
1101     }
1102 
1103     // Last Effect should render directly to theFB
1104     // If there is a last effect, it has already been confirmed to be active
1105     if (layerPrepResult->lastEffect) {
1106         const auto &theContext = renderer->context();
1107         theContext->setRenderTarget(theFB);
1108         theContext->setViewport(layerPrepResult->viewport().toRect());
1109         theContext->setScissorTestEnabled(true);
1110         theContext->setScissorRect(layerPrepResult->scissor().toRect());
1111         const QSSGRef<QSSGEffectSystem> &theEffectSystem(renderer->contextInterface()->effectSystem());
1112         startProfiling(lastEffect->className, false);
1113         QMatrix4x4 theMVP;
1114         QSSGRenderCamera::setupOrthographicCameraForOffscreenRender(*theCurrentTexture, theMVP);
1115         theEffectSystem->renderEffect(QSSGEffectRenderArgument(lastEffect,
1116                                                                theCurrentTexture,
1117                                                                QVector2D(camera->clipNear, camera->clipFar),
1118                                                                theLayerDepthTexture,
1119                                                                m_layerPrepassDepthTexture),
1120                                       theMVP,
1121                                       false);
1122 
1123         endProfiling(lastEffect->className);
1124     }
1125 }
1126 
anyCompletelyNonTransparentObjects(const QSSGLayerRenderPreparationData::TRenderableObjectList & inObjects)1127 inline bool anyCompletelyNonTransparentObjects(const QSSGLayerRenderPreparationData::TRenderableObjectList &inObjects)
1128 {
1129     for (int idx = 0, end = inObjects.size(); idx < end; ++idx) {
1130         if (!inObjects.at(idx).obj->renderableFlags.isCompletelyTransparent())
1131             return true;
1132     }
1133     return false;
1134 }
1135 
progressiveAARenderRequest() const1136 bool QSSGLayerRenderData::progressiveAARenderRequest() const
1137 {
1138     const QSSGLayerRenderPreparationResult &thePrepResult(*layerPrepResult);
1139     return m_progressiveAAPassIndex && m_progressiveAAPassIndex < thePrepResult.maxAAPassIndex;
1140 }
1141 
runnableRenderToViewport(const QSSGRef<QSSGRenderFrameBuffer> & theFB)1142 void QSSGLayerRenderData::runnableRenderToViewport(const QSSGRef<QSSGRenderFrameBuffer> &theFB)
1143 {
1144     const auto &theContext = renderer->context();
1145     theContext->resetStates();
1146 
1147     QSSGRenderContextScopedProperty<const QSSGRef<QSSGRenderFrameBuffer> &> __fbo(*theContext,
1148                                                                                 &QSSGRenderContext::renderTarget,
1149                                                                                 &QSSGRenderContext::setRenderTarget);
1150     QSSGRenderContextScopedProperty<QRect> __viewport(*theContext, &QSSGRenderContext::viewport, &QSSGRenderContext::setViewport);
1151     QSSGRenderContextScopedProperty<bool> theScissorEnabled(*theContext,
1152                                                               &QSSGRenderContext::isScissorTestEnabled,
1153                                                               &QSSGRenderContext::setScissorTestEnabled);
1154     QSSGRenderContextScopedProperty<QRect> theScissorRect(*theContext,
1155                                                             &QSSGRenderContext::scissorRect,
1156                                                             &QSSGRenderContext::setScissorRect);
1157     QSSGLayerRenderPreparationResult &thePrepResult(*layerPrepResult);
1158     QRectF theScreenRect(thePrepResult.viewport());
1159 
1160     const bool isProgressiveAABlendPass = m_progressiveAAPassIndex
1161                     && m_progressiveAAPassIndex < thePrepResult.maxAAPassIndex;
1162     const bool isProgressiveAACopyPass = !isProgressiveAABlendPass
1163                     && layer.antialiasingMode == QSSGRenderLayer::AAMode::ProgressiveAA;
1164     const bool isTemporalAABlendPass = layer.temporalAAEnabled
1165                     && !qFuzzyIsNull(layer.temporalAAStrength);
1166     const bool isTemporalNoProgressiveBlend = isTemporalAABlendPass && !isProgressiveAABlendPass;
1167     quint32 aaFactorIndex = 0;
1168 
1169     // here used only for temporal aa
1170     QSSGRef<QSSGLayerProgAABlendShader> temporalAABlendShader = nullptr;
1171 
1172     // progressive aa uses this one
1173     QSSGRef<QSSGLayerLastFrameBlendShader> progAABlendShader = nullptr;
1174 
1175     // Composit shader used by the post-processing effect stage
1176     QSSGRef<QSSGCompositShader> compositShader = nullptr;
1177 
1178     qint32 sampleCount = 1;
1179     // check multsample mode and MSAA texture support
1180     if (layer.antialiasingMode == QSSGRenderLayer::AAMode::MSAA && theContext->supportsMultisampleTextures())
1181         sampleCount = qint32(layer.antialiasingQuality);
1182 
1183     if (isTemporalAABlendPass || isProgressiveAABlendPass || isProgressiveAACopyPass) {
1184         if (isTemporalAABlendPass)
1185             temporalAABlendShader = renderer->getLayerProgAABlendShader();
1186         if (isProgressiveAABlendPass)
1187             progAABlendShader = renderer->getLayerLastFrameBlendShader();
1188 
1189         // we use the temporal aa texture for progressive aa too
1190         m_temporalAATexture.ensureTexture(theScreenRect.width(), theScreenRect.height(),
1191                                           QSSGRenderTextureFormat::RGBA8);
1192 
1193         if ((!isProgressiveAACopyPass || isTemporalNoProgressiveBlend) && sampleCount <= 1) {
1194             // Note: TemporalAA doesn't work together with multisampling
1195             QVector2D theVertexOffsets;
1196             if (isProgressiveAABlendPass) {
1197                 aaFactorIndex = (m_progressiveAAPassIndex - 1);
1198                 theVertexOffsets = s_VertexOffsets[aaFactorIndex];
1199             } else {
1200                 const float temporalStrength = layer.temporalAAStrength;
1201                 const QVector2D s_TemporalVertexOffsets[QSSGLayerRenderPreparationData::MAX_TEMPORAL_AA_LEVELS] = {
1202                     QVector2D(temporalStrength, temporalStrength),
1203                     QVector2D(-temporalStrength, -temporalStrength)
1204                 };
1205                 theVertexOffsets = s_TemporalVertexOffsets[m_temporalAAPassIndex];
1206                 if (layer.antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
1207                     // temporal offset needs to grow with SSAA resolution
1208                     theVertexOffsets *= layer.ssaaMultiplier;
1209                 }
1210                 ++m_temporalAAPassIndex;
1211                 m_temporalAAPassIndex = m_temporalAAPassIndex % MAX_TEMPORAL_AA_LEVELS;
1212             }
1213 
1214             theVertexOffsets.setX(theVertexOffsets.x() / (theScreenRect.width() / 2.0f));
1215             theVertexOffsets.setY(theVertexOffsets.y() / (theScreenRect.height() / 2.0f));
1216             // Run through all models and update MVP.
1217 
1218             // TODO - optimize this exact matrix operation.
1219             for (qint32 idx = 0, end = modelContexts.size(); idx < end; ++idx) {
1220                 QMatrix4x4 &originalProjection(modelContexts[idx]->modelViewProjection);
1221                 offsetProjectionMatrix(originalProjection, theVertexOffsets);
1222             }
1223         }
1224     }
1225 
1226     // Shadows and SSAO require an FBO, so create one if we are using those
1227     if (thePrepResult.flags.requiresSsaoPass() || thePrepResult.flags.requiresShadowMapPass()) {
1228         QSize theLayerTextureDimensions = thePrepResult.textureDimensions();
1229         QSSGRef<QSSGResourceManager> theResourceManager = renderer->contextInterface()->resourceManager();
1230         QSSGResourceFrameBuffer theFBO(theResourceManager);
1231         // Allocates the frame buffer which has the side effect of setting the current render target
1232         // to that frame buffer.
1233         theFBO.ensureFrameBuffer();
1234 
1235         theContext->setScissorTestEnabled(false);
1236 
1237         if (thePrepResult.flags.requiresSsaoPass()) {
1238             if (m_layerSsaoTexture.ensureTexture(theLayerTextureDimensions.width(), theLayerTextureDimensions.height(), QSSGRenderTextureFormat::RGBA8)) {
1239                 m_layerSsaoTexture->setMinFilter(QSSGRenderTextureMinifyingOp::Linear);
1240                 m_layerSsaoTexture->setMagFilter(QSSGRenderTextureMagnifyingOp::Linear);
1241                 m_progressiveAAPassIndex = 0;
1242                 m_nonDirtyTemporalAAPassIndex = 0;
1243             }
1244         }
1245 
1246         if (thePrepResult.flags.requiresDepthTexture()) {
1247             // The depth texture doesn't need to be multisample, the prepass depth does.
1248             if (m_layerDepthTexture.ensureTexture(theLayerTextureDimensions.width(), theLayerTextureDimensions.height(), QSSGRenderTextureFormat::Depth24Stencil8)) {
1249                 // Depth textures are generally not bilinear filtered.
1250                 m_layerDepthTexture->setMinFilter(QSSGRenderTextureMinifyingOp::Nearest);
1251                 m_layerDepthTexture->setMagFilter(QSSGRenderTextureMagnifyingOp::Nearest);
1252                 m_progressiveAAPassIndex = 0;
1253                 m_nonDirtyTemporalAAPassIndex = 0;
1254             }
1255         }
1256 
1257         QRect theNewViewport(0, 0, theLayerTextureDimensions.width(), theLayerTextureDimensions.height());
1258         {
1259             theContext->setRenderTarget(theFBO);
1260             QSSGRenderContextScopedProperty<QRect> __viewport(*theContext,
1261                                                               &QSSGRenderContext::viewport,
1262                                                               &QSSGRenderContext::setViewport,
1263                                                               theNewViewport);
1264 
1265             // Depth Prepass with transparent and opaque renderables (for SSAO)
1266             if (thePrepResult.flags.requiresDepthTexture() && m_progressiveAAPassIndex == 0) {
1267                 // Setup FBO with single depth buffer target.
1268                 // Note this does not use multisample.
1269                 QSSGRenderFrameBufferAttachment theAttachment = getFramebufferDepthAttachmentFormat(QSSGRenderTextureFormat::Depth24Stencil8);
1270                 theFBO->attach(theAttachment, m_layerDepthTexture.getTexture());
1271 
1272                 // In this case transparent objects also may write their depth.
1273                 renderDepthPass(true);
1274                 theFBO->attach(theAttachment, QSSGRenderTextureOrRenderBuffer());
1275             }
1276 
1277             // SSAO
1278             if (thePrepResult.flags.requiresSsaoPass() && m_progressiveAAPassIndex == 0 && camera != nullptr) {
1279                 startProfiling("AO pass", false);
1280                 // Setup FBO with single color buffer target
1281                 theFBO->attach(QSSGRenderFrameBufferAttachment::Color0, m_layerSsaoTexture.getTexture());
1282                 QSSGRenderFrameBufferAttachment theAttachment = getFramebufferDepthAttachmentFormat(QSSGRenderTextureFormat::Depth24Stencil8);
1283                 theFBO->attach(theAttachment, m_layerDepthTexture.getTexture());
1284                 theContext->clear(QSSGRenderClearValues::Color);
1285                 renderAoPass();
1286                 theFBO->attach(QSSGRenderFrameBufferAttachment::Color0, QSSGRenderTextureOrRenderBuffer());
1287                 endProfiling("AO pass");
1288             }
1289 
1290             // Shadow
1291             if (thePrepResult.flags.requiresShadowMapPass() && m_progressiveAAPassIndex == 0) {
1292                 // shadow map path
1293                 renderShadowMapPass(&theFBO);
1294             }
1295         }
1296     }
1297 
1298     QSSGResourceFrameBuffer thePreFBO(nullptr);
1299     const bool hasPostProcessingEffects = (thePrepResult.lastEffect != nullptr); /* we have effects */
1300     if (hasPostProcessingEffects) {
1301         QSize theLayerTextureDimensions = thePrepResult.textureDimensions();
1302         QSSGRef<QSSGResourceManager> theResourceManager = renderer->contextInterface()->resourceManager();
1303         thePreFBO = theResourceManager;
1304         // Allocates the frame buffer which has the side effect of setting the current render target
1305         // to that frame buffer.
1306         thePreFBO.ensureFrameBuffer();
1307         theContext->setScissorTestEnabled(false);
1308         // Setup the default render target type
1309         QSSGRenderTextureFormat outputFormat = QSSGRenderTextureFormat::RGBA8;
1310         if (theContext->supportsFpRenderTarget()) {
1311             if (theContext->renderContextType() == QSSGRenderContextType::GL3 ||
1312                 theContext->renderContextType() == QSSGRenderContextType::GL4)
1313                 outputFormat = QSSGRenderTextureFormat::RGBA32F;
1314             else
1315                 outputFormat = QSSGRenderTextureFormat::RGBA16F;
1316         }
1317 
1318         if (m_layerTexture.ensureTexture(theLayerTextureDimensions.width(), theLayerTextureDimensions.height(), outputFormat)) {
1319             m_layerTexture->setMinFilter(QSSGRenderTextureMinifyingOp::Linear);
1320             m_layerTexture->setMagFilter(QSSGRenderTextureMagnifyingOp::Linear);
1321         }
1322 
1323         if (m_layerDepthTexture.ensureTexture(theLayerTextureDimensions.width(), theLayerTextureDimensions.height(), QSSGRenderTextureFormat::Depth24Stencil8)) {
1324             // Depth textures are generally not bilinear filtered.
1325             m_layerDepthTexture->setMinFilter(QSSGRenderTextureMinifyingOp::Nearest);
1326             m_layerDepthTexture->setMagFilter(QSSGRenderTextureMagnifyingOp::Nearest);
1327         }
1328 
1329         // Setup FBO with single color buffer target
1330         thePreFBO->attach(QSSGRenderFrameBufferAttachment::Color0, m_layerTexture.getTexture());
1331         QSSGRenderFrameBufferAttachment theAttachment = getFramebufferDepthAttachmentFormat(QSSGRenderTextureFormat::Depth24Stencil8);
1332         thePreFBO->attach(theAttachment, m_layerDepthTexture.getTexture());
1333         theContext->setRenderTarget(thePreFBO);
1334     } else {
1335         theContext->setRenderTarget(theFB);
1336     }
1337 
1338     // Multisampling
1339     theContext->setMultisampleEnabled(sampleCount > 1);
1340 
1341     // Start Operations on Viewport
1342     theContext->setViewport(layerPrepResult->viewport().toRect());
1343     theContext->setScissorTestEnabled(true);
1344     theContext->setScissorRect(layerPrepResult->scissor().toRect());
1345 
1346     // Depth Pre-pass
1347     if (layer.flags.testFlag(QSSGRenderLayer::Flag::LayerEnableDepthPrePass)) {
1348         startProfiling("Depth pass", false);
1349         renderDepthPass(false);
1350         endProfiling("Depth pass");
1351     }
1352 
1353     // Viewport Clear
1354     startProfiling("Clear pass", false);
1355     renderClearPass();
1356     endProfiling("Clear pass");
1357 
1358     // Render pass
1359     startProfiling("Render pass", false);
1360     render();
1361     endProfiling("Render pass");
1362 
1363 #ifdef QT_QUICK3D_DEBUG_SHADOWS
1364     if (shadowMapManager->getShadowMapEntry(0)->m_depthMap) {
1365         renderDebugDepthMap(shadowMapManager->getShadowMapEntry(0)->m_depthMap.get(),
1366                             shadowMapManager->getShadowMapEntry(0)->m_depthCube.get());
1367     }
1368 #endif
1369 
1370     if (hasPostProcessingEffects)
1371         applyLayerPostEffects(theFB);
1372 
1373     if (temporalAABlendShader && isTemporalNoProgressiveBlend && sampleCount <= 1) {
1374         // Note: TemporalAA doesn't work together with multisampling
1375         theContext->copyFramebufferTexture(0, 0, theScreenRect.width(), theScreenRect.height(),
1376                                            0, 0,
1377                                            QSSGRenderTextureOrRenderBuffer(m_temporalAATexture));
1378 
1379         if (m_prevTemporalAATexture.isNull()) {
1380             // If m_prevTemporalAATexture doesn't exist yet, copy current to avoid flicker
1381             m_prevTemporalAATexture.ensureTexture(theScreenRect.width(), theScreenRect.height(),
1382                                                   QSSGRenderTextureFormat::RGBA8);
1383             theContext->copyFramebufferTexture(0, 0, theScreenRect.width(), theScreenRect.height(),
1384                                                0, 0,
1385                                                QSSGRenderTextureOrRenderBuffer(m_prevTemporalAATexture));
1386         }
1387         // blend temporal aa textures
1388         QVector2D theBlendFactors;
1389         theBlendFactors = QVector2D(.5f, .5f);
1390 
1391         theContext->setDepthTestEnabled(false);
1392         theContext->setBlendingEnabled(false);
1393         theContext->setCullingEnabled(false);
1394         theContext->setActiveShader(temporalAABlendShader->shader);
1395         temporalAABlendShader->accumSampler.set(m_prevTemporalAATexture.getTexture().data());
1396         temporalAABlendShader->lastFrame.set(m_temporalAATexture.getTexture().data());
1397         temporalAABlendShader->blendFactors.set(theBlendFactors);
1398         renderer->renderQuad();
1399         m_prevTemporalAATexture.swapTexture(m_temporalAATexture);
1400     }
1401     if (isProgressiveAACopyPass || (progAABlendShader && isProgressiveAABlendPass)) {
1402         // first pass is just copying the frame, next passes blend the texture
1403         // on top of the screen
1404         if (m_progressiveAAPassIndex > 1 && progAABlendShader) {
1405             theContext->setDepthTestEnabled(false);
1406             theContext->setBlendingEnabled(true);
1407             theContext->setCullingEnabled(false);
1408             theContext->setBlendFunction(QSSGRenderBlendFunctionArgument(
1409                                              QSSGRenderSrcBlendFunc::One, QSSGRenderDstBlendFunc::OneMinusSrcAlpha,
1410                                              QSSGRenderSrcBlendFunc::Zero, QSSGRenderDstBlendFunc::One));
1411             const float blendFactor = s_BlendFactors[aaFactorIndex].y();
1412             theContext->setActiveShader(progAABlendShader->shader);
1413             progAABlendShader->lastFrame.set(m_temporalAATexture.getTexture().data());
1414             progAABlendShader->blendFactor.set(blendFactor);
1415             renderer->renderQuad();
1416         }
1417         theContext->copyFramebufferTexture(0, 0, theScreenRect.width(), theScreenRect.height(),
1418                                            0, 0,
1419                                            QSSGRenderTextureOrRenderBuffer(m_temporalAATexture));
1420         if (m_progressiveAAPassIndex < thePrepResult.maxAAPassIndex)
1421             ++m_progressiveAAPassIndex;
1422     }
1423 }
1424 
prepareForRender()1425 void QSSGLayerRenderData::prepareForRender()
1426 {
1427     // When we render to the scene itself (as opposed to an offscreen buffer somewhere)
1428     // then we use the MVP of the layer somewhat.
1429     const QSize theViewportSize = renderer->contextInterface()->viewport().size();
1430     prepareForRender(theViewportSize);
1431 }
1432 
resetForFrame()1433 void QSSGLayerRenderData::resetForFrame()
1434 {
1435     QSSGLayerRenderPreparationData::resetForFrame();
1436     m_boundingRectColor.setEmpty();
1437 }
1438 
prepareAndRender(const QMatrix4x4 & inViewProjection)1439 void QSSGLayerRenderData::prepareAndRender(const QMatrix4x4 &inViewProjection)
1440 {
1441     TRenderableObjectList theTransparentObjects(transparentObjects);
1442     TRenderableObjectList theOpaqueObjects(opaqueObjects);
1443     theTransparentObjects.clear();
1444     theOpaqueObjects.clear();
1445     modelContexts.clear();
1446     QSSGLayerRenderPreparationResultFlags theFlags;
1447     prepareRenderablesForRender(inViewProjection, QSSGEmpty(), theFlags);
1448     renderDepthPass(false);
1449     render();
1450 }
1451 
1452 QT_END_NAMESPACE
1453