Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qssgrendershadowmap.cpp
Go to the documentation of this file.
1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
5#include <QtQuick3DRuntimeRender/private/qssgrenderlayer_p.h>
6#include <QtQuick3DRuntimeRender/private/qssgrendershadowmap_p.h>
7#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
9
11
13 : m_context(inContext)
14{
15}
16
21
23{
24 for (QSSGShadowMapEntry &entry : m_shadowMapList)
25 entry.destroyRhiResources();
26
27 m_shadowMapList.clear();
28}
29
32 const QSize &size,
33 QRhiTexture::Flags flags = {})
34{
35 auto texture = rhi->newTexture(format, size, 1, flags);
36 if (!texture->create())
37 qWarning("Failed to create shadow map texture of size %dx%d", size.width(), size.height());
38 return texture;
39}
40
43 const QSize &size)
44{
45 auto renderBuffer = rhi->newRenderBuffer(type, size, 1);
46 if (!renderBuffer->create())
47 qWarning("Failed to build depth-stencil buffer of size %dx%d", size.width(), size.height());
48 return renderBuffer;
49}
50
60
70
75 const QString &renderNodeObjName)
76{
77 QRhi *rhi = m_context.rhiContext()->rhi();
78 // Bail out if there is no QRhi, since we can't add entries without it
79 if (!rhi)
80 return;
81
82
83 const QSize pixelSize(width, height);
84
86 if (!rhi->isTextureFormatSupported(rhiFormat))
87 rhiFormat = QRhiTexture::R16;
88
89 const QByteArray rtName = renderNodeObjName.toLatin1();
90
91 // This function is called once per shadow casting light on every layer
92 // prepare (i.e. once per frame). We must avoid creating resources as much
93 // as possible: if the shadow mode, dimensions, etc. are all the same as in
94 // the previous prepare round, then reuse the existing resources.
95
96 QSSGShadowMapEntry *pEntry = shadowMapEntry(lightIdx);
97 if (pEntry) {
98 if (pEntry->m_rhiDepthMap && mode == ShadowMapModes::CUBE) {
99 // previously VSM now CUBE
100 pEntry->destroyRhiResources();
101 setupForRhiDepthCube(rhi, pEntry, pixelSize, rhiFormat);
102 } else if (pEntry->m_rhiDepthCube && mode != ShadowMapModes::CUBE) {
103 // previously CUBE now VSM
104 pEntry->destroyRhiResources();
105 setupForRhiDepth(rhi, pEntry, pixelSize, rhiFormat);
106 } else if (pEntry->m_rhiDepthMap) {
107 // VSM before and now, see if size has changed
108 if (pEntry->m_rhiDepthMap->pixelSize() != pixelSize) {
109 pEntry->destroyRhiResources();
110 setupForRhiDepth(rhi, pEntry, pixelSize, rhiFormat);
111 }
112 } else if (pEntry->m_rhiDepthCube) {
113 // CUBE before and now, see if size has changed
114 if (pEntry->m_rhiDepthCube->pixelSize() != pixelSize) {
115 pEntry->destroyRhiResources();
116 setupForRhiDepthCube(rhi, pEntry, pixelSize, rhiFormat);
117 }
118 }
119 pEntry->m_shadowMapMode = mode;
120 } else if (mode == ShadowMapModes::CUBE) {
124 m_shadowMapList.push_back(QSSGShadowMapEntry::withRhiDepthCubeMap(lightIdx, mode, depthMap, depthCopy, depthStencil));
125
126 pEntry = &m_shadowMapList.back();
127 } else { // VSM
132 m_shadowMapList.push_back(QSSGShadowMapEntry::withRhiDepthMap(lightIdx, mode, depthMap, depthCopy, depthStencil));
133
134 pEntry = &m_shadowMapList.back();
135 }
136
137 if (pEntry) {
138 // Additional graphics resources: samplers, render targets.
139 if (mode == ShadowMapModes::VSM) {
140 if (pEntry->m_rhiRenderTargets.isEmpty()) {
141 pEntry->m_rhiRenderTargets.resize(1);
142 pEntry->m_rhiRenderTargets[0] = nullptr;
143 }
144 Q_ASSERT(pEntry->m_rhiRenderTargets.size() == 1);
145
146 QRhiTextureRenderTarget *&rt(pEntry->m_rhiRenderTargets[0]);
147 if (!rt) {
149 rtDesc.setColorAttachments({ pEntry->m_rhiDepthMap });
150 rtDesc.setDepthStencilBuffer(pEntry->m_rhiDepthStencil);
151 rt = rhi->newTextureRenderTarget(rtDesc);
152 rt->setDescription(rtDesc);
153 // The same renderpass descriptor can be reused since the
154 // format, load/store ops are the same regardless of the shadow mode.
155 if (!pEntry->m_rhiRenderPassDesc)
156 pEntry->m_rhiRenderPassDesc = rt->newCompatibleRenderPassDescriptor();
157 rt->setRenderPassDescriptor(pEntry->m_rhiRenderPassDesc);
158 if (!rt->create())
159 qWarning("Failed to build shadow map render target");
160 }
161 rt->setName(rtName + QByteArrayLiteral(" shadow map"));
162
163 if (!pEntry->m_rhiBlurRenderTarget0) {
164 // blur X: depthMap -> depthCopy
165 pEntry->m_rhiBlurRenderTarget0 = rhi->newTextureRenderTarget({ pEntry->m_rhiDepthCopy });
166 if (!pEntry->m_rhiBlurRenderPassDesc)
167 pEntry->m_rhiBlurRenderPassDesc = pEntry->m_rhiBlurRenderTarget0->newCompatibleRenderPassDescriptor();
168 pEntry->m_rhiBlurRenderTarget0->setRenderPassDescriptor(pEntry->m_rhiBlurRenderPassDesc);
169 pEntry->m_rhiBlurRenderTarget0->create();
170 }
171 pEntry->m_rhiBlurRenderTarget0->setName(rtName + QByteArrayLiteral(" shadow blur X"));
172 if (!pEntry->m_rhiBlurRenderTarget1) {
173 // blur Y: depthCopy -> depthMap
174 pEntry->m_rhiBlurRenderTarget1 = rhi->newTextureRenderTarget({ pEntry->m_rhiDepthMap });
175 pEntry->m_rhiBlurRenderTarget1->setRenderPassDescriptor(pEntry->m_rhiBlurRenderPassDesc);
176 pEntry->m_rhiBlurRenderTarget1->create();
177 }
178 pEntry->m_rhiBlurRenderTarget1->setName(rtName + QByteArrayLiteral(" shadow blur Y"));
179 } else {
180 if (pEntry->m_rhiRenderTargets.isEmpty()) {
181 pEntry->m_rhiRenderTargets.resize(6);
182 for (int i = 0; i < 6; ++i)
183 pEntry->m_rhiRenderTargets[i] = nullptr;
184 }
185 Q_ASSERT(pEntry->m_rhiRenderTargets.size() == 6);
186
187 for (const auto face : QSSGRenderTextureCubeFaces) {
188 QRhiTextureRenderTarget *&rt(pEntry->m_rhiRenderTargets[quint8(face)]);
189 if (!rt) {
190 QRhiColorAttachment att(pEntry->m_rhiDepthCube);
191 att.setLayer(quint8(face)); // 6 render targets, each referencing one face of the cubemap
193 rtDesc.setColorAttachments({ att });
194 rtDesc.setDepthStencilBuffer(pEntry->m_rhiDepthStencil);
195 rt = rhi->newTextureRenderTarget(rtDesc);
196 rt->setDescription(rtDesc);
197 if (!pEntry->m_rhiRenderPassDesc)
198 pEntry->m_rhiRenderPassDesc = rt->newCompatibleRenderPassDescriptor();
199 rt->setRenderPassDescriptor(pEntry->m_rhiRenderPassDesc);
200 if (!rt->create())
201 qWarning("Failed to build shadow map render target");
202 }
203 rt->setName(rtName + QByteArrayLiteral(" shadow cube face: ") + QSSGBaseTypeHelpers::displayName(face));
204 }
205
206 // blurring cubemap happens via multiple render targets (all faces attached to COLOR0..5)
208 if (!pEntry->m_rhiBlurRenderTarget0) {
209 // blur X: depthCube -> cubeCopy
210 QRhiColorAttachment att[6];
211 for (const auto face : QSSGRenderTextureCubeFaces) {
212 att[quint8(face)].setTexture(pEntry->m_rhiCubeCopy);
214 }
216 rtDesc.setColorAttachments(att, att + 6);
217 pEntry->m_rhiBlurRenderTarget0 = rhi->newTextureRenderTarget(rtDesc);
218 if (!pEntry->m_rhiBlurRenderPassDesc)
219 pEntry->m_rhiBlurRenderPassDesc = pEntry->m_rhiBlurRenderTarget0->newCompatibleRenderPassDescriptor();
220 pEntry->m_rhiBlurRenderTarget0->setRenderPassDescriptor(pEntry->m_rhiBlurRenderPassDesc);
221 pEntry->m_rhiBlurRenderTarget0->create();
222 }
223 pEntry->m_rhiBlurRenderTarget0->setName(rtName + QByteArrayLiteral(" shadow cube blur X"));
224 if (!pEntry->m_rhiBlurRenderTarget1) {
225 // blur Y: cubeCopy -> depthCube
226 QRhiColorAttachment att[6];
227 for (const auto face : QSSGRenderTextureCubeFaces) {
228 att[quint8(face)].setTexture(pEntry->m_rhiDepthCube);
230 }
232 rtDesc.setColorAttachments(att, att + 6);
233 pEntry->m_rhiBlurRenderTarget1 = rhi->newTextureRenderTarget(rtDesc);
234 pEntry->m_rhiBlurRenderTarget1->setRenderPassDescriptor(pEntry->m_rhiBlurRenderPassDesc);
235 pEntry->m_rhiBlurRenderTarget1->create();
236 }
237 pEntry->m_rhiBlurRenderTarget1->setName(rtName + QByteArrayLiteral(" shadow cube blur Y"));
238 } else {
239 static bool warned = false;
240 if (!warned) {
241 warned = true;
242 qWarning("Cubemap-based shadow maps will not be blurred because MaxColorAttachments is less than 6");
243 }
244 }
245 }
246
247 pEntry->m_lightIndex = lightIdx;
248 }
249}
250
252{
253 Q_ASSERT(lightIdx >= 0);
254
255 for (int i = 0; i < m_shadowMapList.size(); i++) {
256 QSSGShadowMapEntry *pEntry = &m_shadowMapList[i];
257 if (pEntry->m_lightIndex == quint32(lightIdx))
258 return pEntry;
259 }
260
261 return nullptr;
262}
263
265 : m_lightIndex(std::numeric_limits<quint32>::max())
266 , m_shadowMapMode(ShadowMapModes::VSM)
267{
268}
269
272 QRhiTexture *depthMap,
273 QRhiTexture *depthCopy,
274 QRhiRenderBuffer *depthStencil)
275{
277 e.m_lightIndex = lightIdx;
279 e.m_rhiDepthMap = depthMap;
280 e.m_rhiDepthCopy = depthCopy;
281 e.m_rhiDepthStencil = depthStencil;
282 return e;
283}
284
287 QRhiTexture *depthCube,
288 QRhiTexture *cubeCopy,
289 QRhiRenderBuffer *depthStencil)
290{
292 e.m_lightIndex = lightIdx;
294 e.m_rhiDepthCube = depthCube;
295 e.m_rhiCubeCopy = cubeCopy;
296 e.m_rhiDepthStencil = depthStencil;
297 return e;
298}
299
301{
302 delete m_rhiDepthMap;
303 m_rhiDepthMap = nullptr;
304 delete m_rhiDepthCopy;
305 m_rhiDepthCopy = nullptr;
306 delete m_rhiDepthCube;
307 m_rhiDepthCube = nullptr;
308 delete m_rhiCubeCopy;
309 m_rhiCubeCopy = nullptr;
310 delete m_rhiDepthStencil;
311 m_rhiDepthStencil = nullptr;
312
315 delete m_rhiRenderPassDesc;
316 m_rhiRenderPassDesc = nullptr;
318 m_rhiBlurRenderTarget0 = nullptr;
320 m_rhiBlurRenderTarget1 = nullptr;
322 m_rhiBlurRenderPassDesc = nullptr;
323}
324
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtGui
Definition qrhi.h:576
void setTexture(QRhiTexture *tex)
Sets the texture tex.
Definition qrhi.h:583
void setLayer(int layer)
Sets the layer index.
Definition qrhi.h:589
\inmodule QtGui
Definition qrhi.h:1094
Type
Specifies the type of the renderbuffer.
Definition qrhi.h:1096
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Sets the QRhiRenderPassDescriptor desc for use with this render target.
Definition qrhi.h:1165
void setName(const QByteArray &name)
Sets a name for the object.
Definition qrhi.cpp:3581
void setColorAttachments(std::initializer_list< QRhiColorAttachment > list)
Sets the list of color attachments.
Definition qrhi.h:627
\inmodule QtGui
Definition qrhi.h:1184
void setDescription(const QRhiTextureRenderTargetDescription &desc)
Sets the render target description desc.
Definition qrhi.h:1196
virtual QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor()=0
virtual bool create()=0
Creates the corresponding native graphics resources.
\inmodule QtGui
Definition qrhi.h:895
@ RenderTarget
Definition qrhi.h:898
@ CubeMap
Definition qrhi.h:899
Format
Specifies the texture format.
Definition qrhi.h:914
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1804
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags={}) const
Definition qrhi.cpp:10102
int resourceLimit(ResourceLimit limit) const
Definition qrhi.cpp:10121
QRhiRenderBuffer * newRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount=1, QRhiRenderBuffer::Flags flags={}, QRhiTexture::Format backingFormatHint=QRhiTexture::UnknownFormat)
Definition qrhi.cpp:10535
QRhiTextureRenderTarget * newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags={})
Definition qrhi.cpp:10682
@ MaxColorAttachments
Definition qrhi.h:1889
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
Definition qrhi.cpp:10562
static const char * displayName(QSSGRenderTextureCubeFace face)
const std::unique_ptr< QSSGRhiContext > & rhiContext() const
const QSSGRenderContextInterface & m_context
QSSGRenderShadowMap(const QSSGRenderContextInterface &inContext)
QSSGShadowMapEntry * shadowMapEntry(int lightIdx)
void addShadowMapEntry(qint32 lightIdx, qint32 width, qint32 height, ShadowMapModes mode, const QString &renderNodeObjName)
\inmodule QtCore
Definition qsize.h:25
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qDeleteAll(list.begin(), list.end())
Combined button and popup list for selecting options.
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
#define qWarning
Definition qlogging.h:166
GLenum mode
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum face
GLint GLsizei width
GLenum type
GLbitfield flags
GLenum GLuint texture
GLint GLsizei GLsizei GLenum format
GLuint entry
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static constexpr QSSGRenderTextureCubeFace QSSGRenderTextureCubeFaces[]
static QRhiTexture * allocateRhiShadowTexture(QRhi *rhi, QRhiTexture::Format format, const QSize &size, QRhiTexture::Flags flags={})
static QRhiRenderBuffer * allocateRhiShadowRenderBuffer(QRhi *rhi, QRhiRenderBuffer::Type type, const QSize &size)
static void setupForRhiDepth(QRhi *rhi, QSSGShadowMapEntry *entry, const QSize &size, QRhiTexture::Format format)
static void setupForRhiDepthCube(QRhi *rhi, QSSGShadowMapEntry *entry, const QSize &size, QRhiTexture::Format format)
@ VSM
variance shadow mapping
@ CUBE
cubemap omnidirectional shadows
unsigned int quint32
Definition qtypes.h:50
int qint32
Definition qtypes.h:49
unsigned char quint8
Definition qtypes.h:46
QRhiTextureRenderTarget * m_rhiBlurRenderTarget0
QRhiRenderPassDescriptor * m_rhiRenderPassDesc
QVarLengthArray< QRhiTextureRenderTarget *, 6 > m_rhiRenderTargets
static QSSGShadowMapEntry withRhiDepthCubeMap(quint32 lightIdx, ShadowMapModes mode, QRhiTexture *depthCube, QRhiTexture *cubeCopy, QRhiRenderBuffer *depthStencil)
QRhiRenderBuffer * m_rhiDepthStencil
QRhiRenderPassDescriptor * m_rhiBlurRenderPassDesc
ShadowMapModes m_shadowMapMode
shadow map method
QRhiTextureRenderTarget * m_rhiBlurRenderTarget1
static QSSGShadowMapEntry withRhiDepthMap(quint32 lightIdx, ShadowMapModes mode, QRhiTexture *depthMap, QRhiTexture *depthCopy, QRhiRenderBuffer *depthStencil)
quint32 m_lightIndex
the light index it belongs to