Revision control

Copy as Markdown

// 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_SHADER_CACHE_H
#define QSSG_RENDER_SHADER_CACHE_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 <QtQuick3DUtils/private/qssgdataref_p.h>
#include <QtQuick3DUtils/private/qqsbcollection_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrhicontext_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrendererimplshaders_p.h>
#include <QtCore/QString>
#include <QtCore/qcryptographichash.h>
#include <QtCore/QSharedPointer>
#include <QtCore/QVector>
QT_BEGIN_NAMESPACE
class QSSGRenderContextInterface;
class QSSGRhiShaderPipeline;
class QShaderBaker;
class QRhi;
class QSurfaceFormat;
using QSSGUserShaderFragmentOutputs = QVector<QByteArrayView>;
struct QSSGShaderDefine
{
QByteArray name;
QByteArray value;
};
using QSSGShaderDefineList = QList<QSSGShaderDefine>;
class QSSGUserShaderAugmentation
{
public:
QByteArray preamble;
QByteArray body;
QByteArray hash;
bool needsBaseColor = false;
bool needsRoughness = false;
bool needsMetalness = false;
bool needsDiffuseLight = false;
bool needsSpecularLight = false;
bool needsEmissiveLight = false;
bool needsWorldNormal = false;
bool needsWorldTangent = false;
bool needsWorldBinormal = false;
bool needsF0 = false;
bool needsF90 = false;
QSSGUserShaderFragmentOutputs outputs;
using Property = QSSGBaseTypeProperty;
using PropertyUniformsList = QVector<Property>;
PropertyUniformsList propertyUniforms;
QSSGShaderDefineList defines;
bool hasUserAugmentation() const
{
return (body.size() > 0);
}
bool hasPropertyUniforms() const
{
return propertyUniforms.size() > 0;
}
};
struct Q_QUICK3DRUNTIMERENDER_EXPORT QSSGShaderFeatures
{
// There are a number of macros used to turn on or off various features.
// This allows those features to be propagated into the shader cache's caching mechanism.
// They will be translated into #define name value where value is 1 or zero depending on
// if the feature is enabled or not.
//
// In snippets that use this feature the code would look something like this:
/*
#ifndef QSSG_ENABLE_<FEATURE>
#define QSSG_ENABLE_<FEATURE> 0
#endif
void func()
{
...
#if QSSG_ENABLE_<FEATURE>
...
#endif
...
}
*/
// NOTE: The order of these will affect generated keys, so re-ordering these
// will break already baked shaders (e.g. shadergen).
using FlagType = quint32;
enum class Feature : FlagType
{
LightProbe = (1 << 8),
IblOrientation = (1 << 9) + 1,
Ssm = (1 << 10) + 2,
Ssao = (1 << 11) + 3,
DepthPass = (1 << 12) + 4,
OrthoShadowPass = (1 << 13) + 5,
PerspectiveShadowPass = (1 << 14) + 6,
LinearTonemapping = (1 << 15) + 7,
AcesTonemapping = (1 << 16) + 8,
HejlDawsonTonemapping = (1 << 17) + 9,
FilmicTonemapping = (1 << 18) + 10,
RGBELightProbe = (1 << 19) + 11,
OpaqueDepthPrePass = (1 << 20) + 12,
ReflectionProbe = (1 << 21) + 13,
ReduceMaxNumLights = (1 << 22) + 14,
Lightmap = (1 << 23) + 15,
DisableMultiView = (1 << 24) + 16,
ForceIblExposure = (1 << 25) + 17,
NormalPass = (1 << 26) + 18,
UserRenderPass = (1 << 27) + 19,
MotionVector = (1 << 28) + 20,
LastFeature
};
static constexpr FlagType IndexMask = 0xff;
static constexpr quint32 Count = (static_cast<FlagType>(Feature::LastFeature) & IndexMask);
static const char *asDefineString(QSSGShaderFeatures::Feature feature);
static Feature fromIndex(quint32 idx);
constexpr bool isNull() const { return flags == 0; }
constexpr bool isSet(Feature feature) const { return (static_cast<FlagType>(feature) & flags); }
void set(Feature feature, bool val);
FlagType flags = 0;
inline friend bool operator==(QSSGShaderFeatures a, QSSGShaderFeatures b) { return a.flags == b.flags; }
void disableTonemapping()
{
set(Feature::LinearTonemapping, false);
set(Feature::AcesTonemapping, false);
set(Feature::FilmicTonemapping, false);
set(Feature::HejlDawsonTonemapping, false);
set(Feature::ForceIblExposure, false);
}
inline friend QDebug operator<<(QDebug stream, const QSSGShaderFeatures &features)
{
QVarLengthArray<const char *, Count> enabledFeatureStrings;
for (quint32 idx = 0; idx < Count; ++idx) {
const Feature feature = fromIndex(idx);
if (features.isSet(feature))
enabledFeatureStrings.append(asDefineString(feature));
}
stream.nospace() << "QSSGShaderFeatures(";
for (int i = 0; i < enabledFeatureStrings.size(); ++i)
stream.nospace() << (i > 0 ? ", " : "") << enabledFeatureStrings[i];
stream.nospace() << ")";
return stream;
}
};
Q_QUICK3DRUNTIMERENDER_EXPORT size_t qHash(QSSGShaderFeatures features) noexcept;
struct QSSGShaderCacheKey
{
QByteArray m_key;
QSSGShaderFeatures m_features;
size_t m_hashCode = 0;
explicit QSSGShaderCacheKey(const QByteArray &key = QByteArray()) : m_key(key), m_hashCode(0) {}
QSSGShaderCacheKey(const QSSGShaderCacheKey &other) = default;
QSSGShaderCacheKey &operator=(const QSSGShaderCacheKey &other) = default;
static inline size_t generateHashCode(const QByteArray &key, QSSGShaderFeatures features)
{
return qHash(key) ^ qHash(features);
}
void updateHashCode()
{
m_hashCode = generateHashCode(m_key, m_features);
}
bool operator==(const QSSGShaderCacheKey &inOther) const
{
return m_key == inOther.m_key && m_features == inOther.m_features;
}
};
inline size_t qHash(const QSSGShaderCacheKey &key)
{
return key.m_hashCode;
}
class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGShaderCache
{
Q_DISABLE_COPY(QSSGShaderCache)
public:
enum class ShaderType
{
Vertex = 0,
Fragment = 1
};
using InitBakerFunc = void (*)(QShaderBaker *baker, QRhi *rhi);
private:
friend class QSSGBuiltInRhiShaderCache;
typedef QHash<QSSGShaderCacheKey, QSSGRhiShaderPipelinePtr> TRhiShaderMap;
QSSGRhiContext &m_rhiContext; // Not own, the RCI owns us and the QSSGRhiContext.
TRhiShaderMap m_rhiShaders;
QByteArray m_insertStr; // member to potentially reuse the allocation after clear
QByteArray m_cacheKeyStr; // same here
InitBakerFunc m_initBaker;
QQsbInMemoryCollection m_persistentShaderBakingCache;
QString m_persistentShaderStorageFileName;
QSSGBuiltInRhiShaderCache m_builtInShaders;
QSSGRhiShaderPipelinePtr loadBuiltinUncached(const QByteArray &inKey, int viewCount,
QSSGRhiShaderPipeline::StageFlags vertexStageFlags);
void addShaderPreprocessor(QByteArray &str,
const QByteArray &inKey,
ShaderType shaderType,
const QSSGShaderFeatures &inFeatures,
const QSSGUserShaderAugmentation &shaderAugmentation,
int viewCount);
public:
QSSGShaderCache(QSSGRhiContext &ctx,
const InitBakerFunc initBakeFn = nullptr);
~QSSGShaderCache();
QSSGRhiContext &rhiContext() { return m_rhiContext; }
void releaseCachedResources();
QQsbInMemoryCollection &persistentShaderBakingCache() { return m_persistentShaderBakingCache; }
QSSGRhiShaderPipelinePtr tryGetRhiShaderPipeline(const QByteArray &inKey,
const QSSGShaderFeatures &inFeatures);
QSSGRhiShaderPipelinePtr tryNewPipelineFromPersistentCache(const QByteArray &qsbcKey,
const QByteArray &inKey,
const QSSGShaderFeatures &inFeatures,
QSSGRhiShaderPipeline::StageFlags stageFlags = {});
QSSGRhiShaderPipelinePtr newPipelineFromPregenerated(const QByteArray &inKey,
const QSSGShaderFeatures &inFeatures,
QQsbCollection::Entry entry,
const QSSGRenderGraphObject &obj,
QSSGRhiShaderPipeline::StageFlags stageFlags = {});
QSSGRhiShaderPipelinePtr compileForRhi(const QByteArray &inKey,
const QByteArray &inVert,
const QByteArray &inFrag,
const QSSGShaderFeatures &inFeatures,
QSSGRhiShaderPipeline::StageFlags stageFlags,
const QSSGUserShaderAugmentation &shaderAugmentation,
int viewCount,
bool perTargetCompilation,
const QByteArray &inCacheKey = {});
QSSGBuiltInRhiShaderCache &getBuiltInRhiShaders() { return m_builtInShaders; }
static QByteArray resourceFolder();
static QByteArray shaderCollectionFile();
static QByteArray particleShaderCollectionFile();
static void initBakerForPersistentUse(QShaderBaker *baker, QRhi *rhi);
static QList<QShaderVersion> glslTargetsForContext(const QSurfaceFormat &format, bool isGLESModule);
};
namespace QtQuick3DEditorHelpers {
namespace ShaderBaker
{
enum class Status : quint8
{
Success,
Error
};
using StatusCallback = void(*)(const QByteArray &descKey, Status status, const QString &err, QShader::Stage stage);
Q_QUICK3DRUNTIMERENDER_EXPORT void setStatusCallback(StatusCallback cb);
}
namespace ShaderCache
{
// Used by DS and the QML puppet!
// Note: Needs to be called before any QSSGShaderCache instance is created.
Q_QUICK3DRUNTIMERENDER_EXPORT void setAutomaticDiskCache(bool enable);
Q_QUICK3DRUNTIMERENDER_EXPORT bool isAutomaticDiskCacheEnabled();
}
}
QT_END_NAMESPACE
#endif