Revision control

Copy as Markdown

// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#ifndef QSSGRENDERSKYMATERIALMANAGER_H
#define QSSGRENDERSKYMATERIALMANAGER_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtQuick3DRuntimeRender/private/qtquick3druntimerenderglobal_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrenderimagetexture_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrenderskymaterial_p.h>
#include <QtCore/qhash.h>
#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
#include <QtCore/qsize.h>
#include <QtCore/qvarlengtharray.h>
#include <rhi/qrhi.h>
#include <memory>
QT_BEGIN_NAMESPACE
class QSSGRenderContextInterface;
class QSSGRhiShaderPipeline;
using QSSGSkyIblCubeFaceRenderTargets = QVarLengthArray<QRhiTextureRenderTarget *, 6>;
struct QSSGSkyIblFaceTargets
{
QSSGSkyIblCubeFaceRenderTargets renderTargets;
QRhiRenderPassDescriptor *renderPassDesc = nullptr;
};
struct QSSGSkyIblPrefilterTargets
{
int mipmapCount = 0;
QVarLengthArray<QSize, 6> mipLevelSizes;
QVarLengthArray<QSSGSkyIblCubeFaceRenderTargets, 6> mipRenderTargetsMap;
QRhiRenderPassDescriptor *renderPassDesc = nullptr;
};
class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRenderSkyMaterialManager
{
Q_DISABLE_COPY(QSSGRenderSkyMaterialManager)
public:
explicit QSSGRenderSkyMaterialManager(const QSSGRenderContextInterface &inContext);
~QSSGRenderSkyMaterialManager();
void releaseCachedResources();
QSSGRenderImageTexture resolve(QSSGRenderSkyMaterial *settings, QSSGPassKey passKey);
private:
bool ensureEnvironmentMap(QSSGRenderSkyMaterial *settings, QSSGPassKey passKey);
struct FrameState;
bool computeFrameState(QSSGRenderSkyMaterial *inSky, FrameState &fs);
bool ensureTextures(FrameState &fs);
void deriveCycleState(QSSGRenderSkyMaterial *inSky, FrameState &fs);
void validateAndUpdateCacheKey(const FrameState &fs, QSSGRhiShaderPipeline *envShaderPipelineKey);
bool ensureSharedResources(FrameState &fs, QRhiCommandBuffer *cb);
bool renderEnvironmentCube(QSSGRenderSkyMaterial *inSky,
QSSGPassKey passKey,
const FrameState &fs,
const QSSGRhiShaderPipelinePtr &shaderPipeline,
QRhiCommandBuffer *cb,
QRhiResourceUpdateBatch *rub);
void runEnvironmentMipChain(const FrameState &fs, QRhiCommandBuffer *cb);
bool runPrefilterCycle(QSSGRenderSkyMaterial *inSky, const FrameState &fs, QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *&rub);
void initializeTailMips(const FrameState &fs, QRhiCommandBuffer *cb);
const QSSGRenderContextInterface &m_context;
QSSGRenderImageTexture m_skyIblTexture;
// The procedural cubemap is shared between IBL modes;
// m_prefilteredCubeMap is only allocated when IBL is enabled.
QRhiTexture *m_envCubeMap = nullptr;
QRhiTexture *m_prefilteredCubeMap = nullptr;
QSize m_cubeMapSize;
int m_prefilteredMipCount = 0;
// One non-mipmapped GL_TEXTURE_2D_ARRAY per specular mip level.
// Storing them separately (rather than as one mipmapped array) works
// around an Android GLES driver bug where glFramebufferTextureLayer
// silently ignores level > 0, causing all slice writes to land on
// mip 0 and corrupting the prefiltered result. Each texture here has
// exactly one mip level and is always attached at level 0.
QList<QRhiTexture *> m_prefilterAccumulators;
// Set when all slice accumulation is complete (iblRenderFrames >= 1) to trigger a
// dedicated normalize + irradiance frame rather than running it in the last slice frame.
bool m_finalizeIblPending = false;
int m_accumulatedSamples = 0;
int m_accumIblSampleCount = 0;
bool m_haveConvergedResult = false;
bool m_envTailMipsInitialized = false;
bool m_prefilteredTailMipsInitialized = false;
struct PrefilterResourceCache
{
// Invalidation keys
QSize environmentMapSize;
bool enableIBL = false;
int prefilterTotalMipCount = 0;
QRhiTexture *envCubeMap = nullptr;
QRhiTexture *prefilteredCubeMap = nullptr;
// One entry per specular mip level, mirroring m_prefilterAccumulators.
QList<QRhiTexture *> prefilterAccumulators;
QSSGRhiShaderPipeline *envShaderPipeline = nullptr;
// Cached resources.
QRhiBuffer *vertexBuffer = nullptr;
QRhiBuffer *uBuf = nullptr;
QRhiBuffer *uBufSlice = nullptr;
QRhiBuffer *uBufNormalize = nullptr;
QRhiBuffer *uBufIrradiance = nullptr;
QSSGSkyIblFaceTargets envFaceTargets;
QSSGSkyIblPrefilterTargets prefilterTargets;
// Per-mip face targets for the accumulator (one entry per specular mip level).
// Preserve variant: loads existing content so additive slices accumulate.
// Clear variant: clears before drawing, used on the first slice.
QList<QSSGSkyIblFaceTargets> accumPreserveFaceTargets;
QList<QSSGSkyIblFaceTargets> accumClearFaceTargets;
QRhiShaderResourceBindings *sliceSrb = nullptr;
// One SRB per specular mip level, each binding the corresponding
// per-mip accumulator texture so the normalize pass reads the right data.
QVarLengthArray<QRhiShaderResourceBindings *, 6> normalizeSrbs;
QRhiShaderResourceBindings *irradianceSrb = nullptr;
QRhiGraphicsPipeline *envMapPipeline = nullptr;
QRhiGraphicsPipeline *slicePipeline = nullptr;
QRhiGraphicsPipeline *normalizeCubePipeline = nullptr;
QRhiGraphicsPipeline *irradiancePipeline = nullptr;
};
PrefilterResourceCache m_cache;
void clearPrefilterCache();
};
using QSSGRenderSkyMaterialManagerPtr = std::shared_ptr<QSSGRenderSkyMaterialManager>;
QT_END_NAMESPACE
#endif