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