Revision control
++ // Copyright (C) 2008-2012 NVIDIA Corporation.
++ // Copyright (C) 2019 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++
++ #ifndef QSSG_RENDER_IMPL_RENDERABLE_OBJECTS_H
++ #define QSSG_RENDER_IMPL_RENDERABLE_OBJECTS_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/qssgrendermodel_p.h>
++ #include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterial_p.h>
++ #include <QtQuick3DRuntimeRender/private/qssgrendercustommaterial_p.h>
++ #include <QtQuick3DRuntimeRender/private/qssgrenderparticles_p.h>
++ #include <QtQuick3DRuntimeRender/private/qssgrendermesh_p.h>
++ #include <QtQuick3DRuntimeRender/private/qssgrendershaderkeys_p.h>
++ #include <QtQuick3DRuntimeRender/private/qssgrendershadercache_p.h>
++ #include <QtQuick3DRuntimeRender/private/qssgrenderableimage_p.h>
++ #include <QtQuick3DRuntimeRender/private/qssgrenderlight_p.h>
++ #include <QtQuick3DRuntimeRender/private/qssgrenderreflectionprobe_p.h>
++ #include <QtQuick3DRuntimeRender/private/qssgrenderclippingfrustum_p.h>
++
++ #include <QtQuick3DUtils/private/qssginvasivelinkedlist_p.h>
++
++ QT_BEGIN_NAMESPACE
++
++ class QSSGRenderer;
++ class QSSGRenderableObject;
++ struct QSSGRenderItem2D;
++
++ enum class QSSGRenderableObjectFlag : quint32
++ {
++ HasTransparency = 1 << 0,
++ CompletelyTransparent = 1 << 1,
++ Dirty = 1 << 2,
++ CastsShadows = 1 << 3,
++ ReceivesShadows = 1 << 4,
++ HasAttributePosition = 1 << 5,
++ HasAttributeNormal = 1 << 6,
++ HasAttributeTexCoord0 = 1 << 7,
++ HasAttributeTexCoord1 = 1 << 8,
++ HasAttributeTangent = 1 << 9,
++ HasAttributeBinormal = 1 << 10,
++ HasAttributeColor = 1 << 11,
++ HasAttributeJointAndWeight = 1 << 12,
++ IsPointsTopology = 1 << 13,
++ // The number of target models' attributes are too many
++ // to store in a renderable flag.
++ // They will be recorded in shaderKey.
++ HasAttributeMorphTarget = 1 << 14,
++ RequiresScreenTexture = 1 << 15,
++ ReceivesReflections = 1 << 16,
++ UsedInBakedLighting = 1 << 17,
++ RendersWithLightmap = 1 << 18,
++ HasAttributeTexCoordLightmap = 1 << 19,
++ CastsReflections = 1 << 20,
++ RequiresNormalTexture = 1 << 21,
++ IsMotionVectorParticipant = 1 << 22
++ };
++
++ struct QSSGRenderableObjectFlags : public QFlags<QSSGRenderableObjectFlag>
++ {
++ void setHasTransparency(bool inHasTransparency)
++ {
++ setFlag(QSSGRenderableObjectFlag::HasTransparency, inHasTransparency);
++ }
++ bool hasTransparency() const { return this->operator&(QSSGRenderableObjectFlag::HasTransparency); }
++ void setCompletelyTransparent(bool inTransparent)
++ {
++ setFlag(QSSGRenderableObjectFlag::CompletelyTransparent, inTransparent);
++ }
++ bool isCompletelyTransparent() const
++ {
++ return this->operator&(QSSGRenderableObjectFlag::CompletelyTransparent);
++ }
++ void setDirty(bool inDirty) { setFlag(QSSGRenderableObjectFlag::Dirty, inDirty); }
++ bool isDirty() const { return this->operator&(QSSGRenderableObjectFlag::Dirty); }
++
++ void setCastsShadows(bool inCastsShadows) { setFlag(QSSGRenderableObjectFlag::CastsShadows, inCastsShadows); }
++ bool castsShadows() const { return this->operator&(QSSGRenderableObjectFlag::CastsShadows); }
++
++ void setReceivesShadows(bool inReceivesShadows) { setFlag(QSSGRenderableObjectFlag::ReceivesShadows, inReceivesShadows); }
++ bool receivesShadows() const { return this->operator&(QSSGRenderableObjectFlag::ReceivesShadows); }
++
++ void setReceivesReflections(bool inReceivesReflections) { setFlag(QSSGRenderableObjectFlag::ReceivesReflections, inReceivesReflections); }
++ bool receivesReflections() const { return this->operator&(QSSGRenderableObjectFlag::ReceivesReflections); }
++
++ void setCastsReflections(bool inCastsReflections) { setFlag(QSSGRenderableObjectFlag::CastsReflections, inCastsReflections); }
++ bool castsReflections() const { return this->operator&(QSSGRenderableObjectFlag::CastsReflections); }
++
++ void setUsedInBakedLighting(bool inUsedInBakedLighting) { setFlag(QSSGRenderableObjectFlag::UsedInBakedLighting, inUsedInBakedLighting); }
++ bool usedInBakedLighting() const { return this->operator&(QSSGRenderableObjectFlag::UsedInBakedLighting); }
++
++ void setRendersWithLightmap(bool inRendersWithLightmap) { setFlag(QSSGRenderableObjectFlag::RendersWithLightmap, inRendersWithLightmap); }
++ bool rendersWithLightmap() const { return this->operator&(QSSGRenderableObjectFlag::RendersWithLightmap); }
++
++ void setHasAttributePosition(bool b) { setFlag(QSSGRenderableObjectFlag::HasAttributePosition, b); }
++ bool hasAttributePosition() const { return this->operator&(QSSGRenderableObjectFlag::HasAttributePosition); }
++
++ void setHasAttributeNormal(bool b) { setFlag(QSSGRenderableObjectFlag::HasAttributeNormal, b); }
++ bool hasAttributeNormal() const { return this->operator&(QSSGRenderableObjectFlag::HasAttributeNormal); }
++
++ void setHasAttributeTexCoord0(bool b) { setFlag(QSSGRenderableObjectFlag::HasAttributeTexCoord0, b); }
++ bool hasAttributeTexCoord0() const { return this->operator&(QSSGRenderableObjectFlag::HasAttributeTexCoord0); }
++
++ void setHasAttributeTexCoord1(bool b) { setFlag(QSSGRenderableObjectFlag::HasAttributeTexCoord1, b); }
++ bool hasAttributeTexCoord1() const { return this->operator&(QSSGRenderableObjectFlag::HasAttributeTexCoord1); }
++
++ void setHasAttributeTexCoordLightmap(bool b) { setFlag(QSSGRenderableObjectFlag::HasAttributeTexCoordLightmap, b); }
++ bool hasAttributeTexCoordLightmap() const { return this->operator&(QSSGRenderableObjectFlag::HasAttributeTexCoordLightmap); }
++
++ void setHasAttributeTangent(bool b) { setFlag(QSSGRenderableObjectFlag::HasAttributeTangent, b); }
++ bool hasAttributeTangent() const { return this->operator&(QSSGRenderableObjectFlag::HasAttributeTangent); }
++
++ void setHasAttributeBinormal(bool b) { setFlag(QSSGRenderableObjectFlag::HasAttributeBinormal, b); }
++ bool hasAttributeBinormal() const { return this->operator&(QSSGRenderableObjectFlag::HasAttributeBinormal); }
++
++ void setHasAttributeColor(bool b) { setFlag(QSSGRenderableObjectFlag::HasAttributeColor, b); }
++ bool hasAttributeColor() const { return this->operator&(QSSGRenderableObjectFlag::HasAttributeColor); }
++
++ void setHasAttributeJointAndWeight(bool b) { setFlag(QSSGRenderableObjectFlag::HasAttributeJointAndWeight, b);
++ }
++ bool hasAttributeJointAndWeight() const { return this->operator&(QSSGRenderableObjectFlag::HasAttributeJointAndWeight); }
++
++ void setHasAttributeMorphTarget(bool b) { setFlag(QSSGRenderableObjectFlag::HasAttributeMorphTarget, b);
++ }
++ bool hasAttributeMorphTarget() const { return this->operator&(QSSGRenderableObjectFlag::HasAttributeMorphTarget); }
++
++ void setPointsTopology(bool v)
++ {
++ setFlag(QSSGRenderableObjectFlag::IsPointsTopology, v);
++ }
++ bool isPointsTopology() const
++ {
++ return this->operator&(QSSGRenderableObjectFlag::IsPointsTopology);
++ }
++ void setRequiresScreenTexture(bool v)
++ {
++ setFlag(QSSGRenderableObjectFlag::RequiresScreenTexture, v);
++ }
++ bool requiresScreenTexture() const {
++ return this->operator&(QSSGRenderableObjectFlag::RequiresScreenTexture);
++ }
++
++ void setRequiresNormalTexture(bool v)
++ {
++ setFlag(QSSGRenderableObjectFlag::RequiresNormalTexture, v);
++ }
++ bool requiresNormalTexture() const {
++ return this->operator&(QSSGRenderableObjectFlag::RequiresNormalTexture);
++ }
++ void setMotionVectorParticipant(bool v) { setFlag(QSSGRenderableObjectFlag::IsMotionVectorParticipant, v); }
++ bool isMotionVectorParticipant() const { return this->operator&(QSSGRenderableObjectFlag::IsMotionVectorParticipant); }
++ };
++
++ struct QSSGShaderLight
++ {
++ QSSGRenderLight *light = nullptr;
++ bool shadows = false;
++ QVector3D direction;
++
++ inline bool operator < (const QSSGShaderLight &o) const
++ {
++ // sort by light type
++ if (light->type < o.light->type)
++ return true;
++ // then shadow lights first
++ if (shadows > o.shadows)
++ return true;
++ return false;
++ }
++ };
++
++ struct QSSGShaderReflectionProbe
++ {
++ QVector3D probeCubeMapCenter;
++ QVector3D probeBoxMax;
++ QVector3D probeBoxMin;
++ bool enabled = false;
++ int parallaxCorrection = 0;
++ };
++
++ // Having this as a QVLA is beneficial mainly because QVector would need to
++ // detach somewhere in QSSGLayerRenderPreparationData::prepareForRender so the
++ // implicit sharing's benefits do not outweigh the cost of allocations in this case.
++ typedef QVarLengthArray<QSSGShaderLight, 16> QSSGShaderLightList;
++ using QSSGShaderLightListView = QSSGDataView<QSSGShaderLight>;
++
++ struct QSSGRenderableNodeEntry
++ {
++ enum Overridden : quint16
++ {
++ Original = 0,
++ Disabled = 0x1,
++ GlobalTransform = 0x2,
++ Materials = 0x4,
++ GlobalOpacity = 0x8,
++ };
++
++ QSSGRenderNode *node = nullptr;
++ mutable QSSGShaderLightListView lights;
++ mutable quint16 overridden { Original };
++
++ // FIXME: This is just for the extension API and
++ // should be removed in the future.
++ struct ExtensionOverrides
++ {
++ QMatrix4x4 globalTransform;
++ QVector<QSSGRenderGraphObject *> materials;
++ float globalOpacity { 1.0f };
++ } mutable extOverrides;
++
++ bool isNull() const { return (node == nullptr); }
++ QSSGRenderableNodeEntry() = default;
++ QSSGRenderableNodeEntry(QSSGRenderNode &inNode) : node(&inNode) {}
++ QSSGRenderableNodeEntry(QSSGRenderNode *inNode) : node(inNode) {}
++ };
++
++ // Used for sorting
++ struct QSSGRenderableObjectHandle
++ {
++ QSSGRenderableObjectHandle() = default;
++ QSSGRenderableObjectHandle(QSSGRenderableObject *o, float camDistSq, QSSGRenderNodeTag tag)
++ : obj(o)
++ , cameraDistanceSq(camDistSq)
++ , tag(tag)
++ {}
++ QSSGRenderableObject *obj = nullptr;
++ float cameraDistanceSq = 0.0f;
++ QSSGRenderNodeTag tag;
++ };
++ Q_DECLARE_TYPEINFO(QSSGRenderableObjectHandle, Q_PRIMITIVE_TYPE);
++
++ using QSSGRenderableObjectList = QVector<QSSGRenderableObjectHandle>;
++
++ class QSSGRenderableObject
++ {
++ Q_DISABLE_COPY_MOVE(QSSGRenderableObject)
++ public:
++ enum class Type : quint8
++ {
++ DefaultMaterialMeshSubset,
++ CustomMaterialMeshSubset,
++ Particles
++ };
++
++ // Variables used for picking
++ const QSSGBounds3 &bounds;
++ QSSGBounds3 globalBounds;
++
++ // Used for shadow map bounds when model has instancing
++ QSSGBounds3 globalBoundsInstancing;
++
++ QSSGRenderableObjectFlags renderableFlags;
++ // For rough sorting for transparency and for depth
++ QVector3D worldCenterPoint;
++ float depthBiasSq; // Squared as our sorting is based on the square distance!
++ float camdistSq = 0.0f;
++ QSSGDepthDrawMode depthWriteMode = QSSGDepthDrawMode::OpaqueOnly;
++ const Type type;
++ float instancingLodMin = -1;
++ float instancingLodMax = -1;
++ bool isInstanced = false;
++
++ QSSGRenderableObject(Type ty,
++ QSSGRenderableObjectFlags inFlags,
++ const QVector3D &inWorldCenterPt,
++ const QSSGBounds3 &inBounds,
++ float inDepthBias,
++ float inMinThreshold = -1,
++ float inMaxThreshold = -1)
++
++ : bounds(inBounds)
++ , globalBounds(inBounds)
++ , renderableFlags(inFlags)
++ , worldCenterPoint(inWorldCenterPt)
++ , depthBiasSq(inDepthBias)
++ , type(ty)
++ , instancingLodMin(inMinThreshold)
++ , instancingLodMax(inMaxThreshold)
++ {
++ }
++ };
++
++ Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGRenderableObject>::value);
++
++ struct QSSGRenderCameraData
++ {
++ QMatrix4x4 viewProjection;
++ std::optional<QSSGClippingFrustum> clippingFrustum;
++ QVector3D direction { 0.0f, 0.0f, -1.0f };
++ QVector3D position;
++ };
++
++ using QSSGRenderCameraList = QVarLengthArray<QSSGRenderCamera *, 2>;
++ using QSSGRenderCameraDataList = QVarLengthArray<QSSGRenderCameraData, 2>;
++ using QSSGRenderMvpArray = std::array<QMatrix4x4, 2>; // cannot be dynamic due to QSSGModelContext, must stick with 2 for now
++
++ class QSSGSubsetRenderable;
++
++ // Different subsets from the same model will get the same
++ // model context so we can generate the MVP and normal matrix once
++ // and only once per subset.
++ class Q_AUTOTEST_EXPORT QSSGModelContext
++ {
++ Q_DISABLE_COPY_MOVE(QSSGModelContext)
++ public:
++ QSSGModelContext(const QSSGRenderModel &inModel,
++ const QMatrix4x4 &globalTransform,
++ const QMatrix3x3 &inNormalMatrix,
++ const QSSGRenderMvpArray &inModelViewProjections);
++
++ const QSSGRenderModel &model;
++ const QMatrix4x4 globalTransform;
++ const QMatrix3x3 normalMatrix;
++ QSSGRenderMvpArray modelViewProjections;
++ QSSGDataRef<QSSGSubsetRenderable> subsets;
++ };
++
++ Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGModelContext>::value);
++
++ class QSSGRenderer;
++ class QSSGLayerRenderData;
++ struct QSSGShadowMapEntry;
++
++ class Q_AUTOTEST_EXPORT QSSGSubsetRenderable : public QSSGRenderableObject
++ {
++ Q_DISABLE_COPY_MOVE(QSSGSubsetRenderable)
++ public:
++ int reflectionProbeIndex = -1;
++ float distanceFromReflectionProbe;
++ quint32 subsetLevelOfDetail = 0;
++ QSSGShaderReflectionProbe reflectionProbe;
++ QSSGRenderer *renderer = nullptr;
++ const QSSGModelContext &modelContext;
++ const QSSGRenderSubset ⊂
++ QRhiBuffer *instanceBuffer = nullptr;
++ float opacity;
++ const QSSGRenderGraphObject &material;
++ QSSGRenderableImage *firstImage;
++ QSSGShaderDefaultMaterialKey shaderDescription;
++ const QSSGShaderLightListView &lights;
++
++ struct RhiPassData {
++ QRhiGraphicsPipeline *pipeline = nullptr;
++ QRhiShaderResourceBindings *srb = nullptr;
++ };
++
++ struct {
++ // Transient (due to the subsetRenderable being allocated using a
++ // per-frame allocator on every frame), not owned refs from the
++ // rhi-prepare step, used by the rhi-render step.
++ struct {
++ QRhiGraphicsPipeline *pipeline = nullptr;
++ QRhiShaderResourceBindings *srb = nullptr;
++ } mainPass;
++ struct {
++ QRhiGraphicsPipeline *pipeline = nullptr;
++ QRhiShaderResourceBindings *srb = nullptr;
++ } depthPrePass;
++ struct {
++ QRhiGraphicsPipeline *pipeline = nullptr;
++ QRhiShaderResourceBindings *srb[6] = {};
++ } shadowPass;
++ struct {
++ QRhiGraphicsPipeline *pipeline = nullptr;
++ QRhiShaderResourceBindings *srb[6] = {};
++ } reflectionPass;
++ struct {
++ QRhiGraphicsPipeline *pipeline = nullptr;
++ QRhiShaderResourceBindings *srb = nullptr;
++ } normalPass;
++ struct {
++ QRhiGraphicsPipeline *pipeline = nullptr;
++ QRhiShaderResourceBindings *srb = nullptr;
++ } motionVectorPass;
++ RhiPassData userPassData[QSSGUserRenderPassManager::maxUserPassSlots()] {};
++ } rhiRenderData;
++
++ QSSGSubsetRenderable(Type type,
++ QSSGRenderableObjectFlags inFlags,
++ const QVector3D &inWorldCenterPt,
++ QSSGRenderer *rendr,
++ const QSSGRenderSubset &inSubset,
++ const QSSGModelContext &inModelContext,
++ float inOpacity,
++ quint32 inSubsetLevelOfDetail,
++ const QSSGRenderGraphObject &mat,
++ QSSGRenderableImage *inFirstImage,
++ QSSGShaderDefaultMaterialKey inShaderKey,
++ const QSSGShaderLightListView &inLights,
++ bool anyLightHasShadows);
++
++ [[nodiscard]] const QSSGRenderGraphObject &getMaterial() const { return material; }
++ };
++
++ Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGSubsetRenderable>::value);
++
++ /**
++ * A renderable that corresponds to a particles.
++ */
++ class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGParticlesRenderable : public QSSGRenderableObject
++ {
++ Q_DISABLE_COPY_MOVE(QSSGParticlesRenderable)
++ public:
++ QSSGRenderer *renderer = nullptr;
++ const QSSGRenderParticles &particles;
++ QSSGRenderableImage *firstImage;
++ QSSGRenderableImage *colorTable;
++ const QSSGShaderLightListView &lights;
++ QMatrix4x4 globalTransform;
++ float opacity;
++ QSSGShaderParticleMaterialKey shaderDescription;
++
++ struct {
++ // Transient (due to the subsetRenderable being allocated using a
++ // per-frame allocator on every frame), not owned refs from the
++ // rhi-prepare step, used by the rhi-render step.
++ struct {
++ QRhiGraphicsPipeline *pipeline = nullptr;
++ QRhiShaderResourceBindings *srb = nullptr;
++ } mainPass;
++ struct {
++ QRhiGraphicsPipeline *pipeline = nullptr;
++ QRhiShaderResourceBindings *srb = nullptr;
++ } depthPrePass;
++ struct {
++ QRhiGraphicsPipeline *pipeline = nullptr;
++ QRhiShaderResourceBindings *srb[6] = {};
++ } shadowPass;
++ struct {
++ QRhiGraphicsPipeline *pipeline = nullptr;
++ QRhiShaderResourceBindings *srb[6] = {};
++ } reflectionPass;
++ } rhiRenderData;
++
++ QSSGParticlesRenderable(QSSGRenderableObjectFlags inFlags,
++ const QVector3D &inWorldCenterPt,
++ QSSGRenderer *rendr,
++ const QMatrix4x4 &inGlobalTransform,
++ const QSSGRenderParticles &inParticles,
++ QSSGRenderableImage *inFirstImage,
++ QSSGRenderableImage *inColorTable,
++ const QSSGShaderLightListView &inLights,
++ float inOpacity,
++ QSSGShaderParticleMaterialKey inShaderKey);
++ };
++
++ Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGParticlesRenderable>::value);
++
++
++ using QSSGModelsView = QSSGDataView<QSSGRenderModel *>;
++ using QSSGParticlesView = QSSGDataView<QSSGRenderParticles *>;
++ using QSSGItem2DsView = QSSGDataView<QSSGRenderItem2D *>;
++ using QSSGCamerasView = QSSGDataView<QSSGRenderCamera *>;
++ using QSSGLightsView = QSSGDataView<QSSGRenderLight *>;
++ using QSSGReflectionProbesView = QSSGDataView<QSSGRenderReflectionProbe *>;
++ using QSSGNonCategorizedView = QSSGDataView<QSSGRenderNode *>;
++
++ QT_END_NAMESPACE
++
++ #endif