211void QSSGRenderShadowMap::addShadowMaps(
const QSSGShaderLightList &renderableLights)
213 QRhi *rhi = m_context.rhiContext()->rhi();
218 const quint32 numLights = renderableLights.size();
219 qsizetype numShadows = 0;
220 const bool supports32BitTextures = rhi->isTextureFormatSupported(QRhiTexture::R32F);
221 QRhiTexture::Format format = QRhiTexture::R16F;
223 QHash<quint32, QVector<QSSGShadowMapEntry::AtlasEntry>> lightIndexToAtlasEntries;
226 for (quint32 lightIndex = 0; lightIndex < numLights; ++lightIndex) {
227 const QSSGShaderLight &shaderLight = renderableLights.at(lightIndex);
228 if (!shaderLight.shadows)
232 if (shaderLight.light->m_use32BitShadowmap && supports32BitTextures)
233 format = QRhiTexture::R32F;
236 if (mapSize < shaderLight.light->m_shadowMapRes)
237 mapSize = shaderLight.light->m_shadowMapRes;
242 auto atlasPacker = AtlasHelpers::ShelfPacker(mapSize, mapSize);
247 for (quint32 lightIndex = 0; lightIndex < numLights; ++lightIndex) {
248 const QSSGShaderLight &shaderLight = renderableLights.at(lightIndex);
249 if (!shaderLight.shadows)
252 quint8 mapsNeeded = 0;
254 if (shaderLight.light->type == QSSGRenderLight::Type::DirectionalLight)
255 mapsNeeded = shaderLight.light->m_csmNumSplits + 1;
256 else if (shaderLight.light->type == QSSGRenderLight::Type::SpotLight)
258 else if (shaderLight.light->type == QSSGRenderLight::Type::PointLight)
261 QVarLengthArray<AtlasHelpers::ShelfPacker::AtlasPlacement, 4> atlasPlacements;
262 for (quint8 i = 0; i < mapsNeeded; ++i) {
263 const int size = shaderLight.light->m_shadowMapRes;
264 auto result = atlasPacker.addRectangle(size);
266 atlasPlacements.push_back(result);
268 lightIndexToAtlasEntries.insert(lightIndex, createAtlasEntries(atlasPlacements, shaderLight.light->m_shadowMapRes, mapSize));
270 const QSize texSize = QSize(mapSize, mapSize);
271 const quint32 layersNeeded = atlasPacker.pagesNeeded();
274 bool needsRebuild = numShadows != shadowMapEntryCount();
275 if (!m_shadowMapAtlasTexture ||
276 m_shadowMapAtlasTexture->pixelSize() != texSize ||
277 m_shadowMapAtlasTexture->arraySize() !=
int(layersNeeded) ||
278 m_shadowMapAtlasTexture->format() != format) {
281 if (m_shadowMapAtlasTexture) {
282 m_shadowMapAtlasTexture.reset();
285 m_shadowMapAtlasTexture.reset(allocateRhiShadowTexture(rhi, format, texSize, layersNeeded, QRhiTexture::RenderTarget | QRhiTexture::TextureArray));
287 qDeleteAll(m_layerDepthStencilBuffers);
288 m_layerDepthStencilBuffers.clear();
289 qDeleteAll(m_layerRenderTargets);
290 m_layerRenderTargets.clear();
291 qDeleteAll(m_layerRenderPassDescriptors);
292 m_layerRenderPassDescriptors.clear();
294 for (quint32 i = 0; i < layersNeeded; ++i) {
296 QRhiRenderBuffer *depthStencilBuffer = allocateRhiShadowRenderBuffer(rhi, QRhiRenderBuffer::DepthStencil, texSize);
297 QRhiTextureRenderTargetDescription rtDesc;
298 QRhiColorAttachment attachment(m_shadowMapAtlasTexture.get());
299 attachment.setLayer(i);
300 rtDesc.setColorAttachments({ attachment });
301 rtDesc.setDepthStencilBuffer(depthStencilBuffer);
302 QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget(rtDesc);
303 rt->setDescription(rtDesc);
304 rt->setFlags(QRhiTextureRenderTarget::PreserveColorContents);
305 QRhiRenderPassDescriptor *rpDesc = rt->newCompatibleRenderPassDescriptor();
306 rt->setRenderPassDescriptor(rpDesc);
308 qWarning(
"Failed to build shadow map render target");
309 rt->setName(QByteArrayLiteral(
"shadow map atlas layer") + QByteArray::number(i));
310 m_layerDepthStencilBuffers.append(depthStencilBuffer);
311 m_layerRenderTargets.append(rt);
312 m_layerRenderPassDescriptors.append(rpDesc);
319 if (!m_sharedFrontCubeToAtlasUniformBuffer || !m_sharedBackCubeToAtlasUniformBuffer) {
320 const quint32 uniformValueFront = 0;
321 const quint32 uniformValueBack = 1;
323 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
324 if (!m_sharedFrontCubeToAtlasUniformBuffer) {
325 m_sharedFrontCubeToAtlasUniformBuffer.reset(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer,
sizeof(uint32_t)));
326 m_sharedFrontCubeToAtlasUniformBuffer->create();
327 rub->updateDynamicBuffer(m_sharedFrontCubeToAtlasUniformBuffer.get(), 0,
sizeof(quint32), &uniformValueFront);
330 if (!m_sharedBackCubeToAtlasUniformBuffer) {
331 m_sharedBackCubeToAtlasUniformBuffer.reset(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer,
sizeof(uint32_t)));
332 m_sharedBackCubeToAtlasUniformBuffer->create();
333 rub->updateDynamicBuffer(m_sharedBackCubeToAtlasUniformBuffer.get(), 0,
sizeof(quint32), &uniformValueBack);
335 QRhiCommandBuffer *cb = m_context.rhiContext()->commandBuffer();
336 cb->resourceUpdate(rub);
338 if (!m_sharedCubeToAtlasSampler) {
339 m_sharedCubeToAtlasSampler.reset(rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
340 m_sharedCubeToAtlasSampler->create();
342 if (!m_shadowClearSrb) {
343 m_shadowClearSrb.reset(rhi->newShaderResourceBindings());
344 m_shadowClearSrb->create();
350 for (quint32 lightIndex = 0; lightIndex < numLights; ++lightIndex) {
351 const QSSGShaderLight &shaderLight = renderableLights.at(lightIndex);
352 if (!shaderLight.shadows)
354 QSSGShadowMapEntry *pEntry = shadowMapEntry(lightIndex);
360 const auto &atlasEntires = lightIndexToAtlasEntries.value(lightIndex);
361 if (!checkCompatibility(pEntry, atlasEntires)) {
372 for (QSSGShadowMapEntry &entry : m_shadowMapList)
373 entry.destroyRhiResources();
374 m_shadowMapList.clear();
376 for (quint32 lightIndex = 0; lightIndex < numLights; ++lightIndex) {
377 const QSSGShaderLight &shaderLight = renderableLights.at(lightIndex);
378 if (!shaderLight.shadows)
380 addShadowMap(lightIndex,
382 lightIndexToAtlasEntries.value(lightIndex),
383 shaderLight.light->m_csmNumSplits,
385 shaderLight.light->type == QSSGRenderLight::Type::PointLight,
386 shaderLight.light->debugObjectName);