diff options
Diffstat (limited to 'src/gui/rhi/qshaderdescription.cpp')
-rw-r--r-- | src/gui/rhi/qshaderdescription.cpp | 917 |
1 files changed, 822 insertions, 95 deletions
diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp index d55caed210..f64daf02ef 100644 --- a/src/gui/rhi/qshaderdescription.cpp +++ b/src/gui/rhi/qshaderdescription.cpp @@ -1,8 +1,8 @@ -// Copyright (C) 2019 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -#include "qshaderdescription_p_p.h" -#include "qshader_p_p.h" +#include "qshaderdescription_p.h" +#include "qshader_p.h" #include <QDebug> #include <QDataStream> #include <QJsonObject> @@ -12,11 +12,22 @@ QT_BEGIN_NAMESPACE /*! \class QShaderDescription - \internal + \ingroup painting-3D \inmodule QtGui + \since 6.6 \brief Describes the interface of a shader. + \warning The QRhi family of classes in the Qt Gui module, including QShader + and QShaderDescription, offer limited compatibility guarantees. There are + no source or binary compatibility guarantees for these classes, meaning the + API is only guaranteed to work with the Qt version the application was + developed against. Source incompatible changes are however aimed to be kept + at a minimum and will only be made in minor releases (6.7, 6.8, and so on). + To use these classes in an application, link to + \c{Qt::GuiPrivate} (if using CMake), and include the headers with the \c + rhi prefix, for example \c{#include <rhi/qshaderdescription.h>}. + A shader typically has a set of inputs and outputs. A vertex shader for example has a number of input variables and may use one or more uniform buffers to access data (e.g. a modelview matrix) provided by the @@ -51,8 +62,6 @@ QT_BEGIN_NAMESPACE float opacity; } ubuf; - out gl_PerVertex { vec4 gl_Position; }; - void main() { v_color = color; @@ -200,28 +209,179 @@ QT_BEGIN_NAMESPACE \value ImageRect \value ImageBuffer \value Struct + \value Half + \value Half2 + \value Half3 + \value Half4 */ /*! - \class QShaderDescription::InOutVariable - \internal + \enum QShaderDescription::ImageFormat + Image format. + + \value ImageFormatUnknown + \value ImageFormatRgba32f + \value ImageFormatRgba16f + \value ImageFormatR32f + \value ImageFormatRgba8 + \value ImageFormatRgba8Snorm + \value ImageFormatRg32f + \value ImageFormatRg16f + \value ImageFormatR11fG11fB10f + \value ImageFormatR16f + \value ImageFormatRgba16 + \value ImageFormatRgb10A2 + \value ImageFormatRg16 + \value ImageFormatRg8 + \value ImageFormatR16 + \value ImageFormatR8 + \value ImageFormatRgba16Snorm + \value ImageFormatRg16Snorm + \value ImageFormatRg8Snorm + \value ImageFormatR16Snorm + \value ImageFormatR8Snorm + \value ImageFormatRgba32i + \value ImageFormatRgba16i + \value ImageFormatRgba8i + \value ImageFormatR32i + \value ImageFormatRg32i + \value ImageFormatRg16i + \value ImageFormatRg8i + \value ImageFormatR16i + \value ImageFormatR8i + \value ImageFormatRgba32ui + \value ImageFormatRgba16ui + \value ImageFormatRgba8ui + \value ImageFormatR32ui + \value ImageFormatRgb10a2ui + \value ImageFormatRg32ui + \value ImageFormatRg16ui + \value ImageFormatRg8ui + \value ImageFormatR16ui + \value ImageFormatR8ui + */ + +/*! + \enum QShaderDescription::ImageFlag + Image flags. + + \value ReadOnlyImage + \value WriteOnlyImage + */ + +/*! + \enum QShaderDescription::QualifierFlag + Qualifier flags. + + \value QualifierReadOnly + \value QualifierWriteOnly + \value QualifierCoherent + \value QualifierVolatile + \value QualifierRestrict + */ + +/*! + \struct QShaderDescription::InOutVariable \inmodule QtGui + \since 6.6 \brief Describes an input or output variable in the shader. + + \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription + for details. */ /*! - \class QShaderDescription::BlockVariable - \internal + \variable QShaderDescription::InOutVariable::name + */ + +/*! + \variable QShaderDescription::InOutVariable::type + */ + +/*! + \variable QShaderDescription::InOutVariable::location + */ + +/*! + \variable QShaderDescription::InOutVariable::binding + */ + +/*! + \variable QShaderDescription::InOutVariable::descriptorSet + */ + +/*! + \variable QShaderDescription::InOutVariable::imageFormat + */ + +/*! + \variable QShaderDescription::InOutVariable::imageFlags + */ + +/*! + \variable QShaderDescription::InOutVariable::arrayDims + */ + +/*! + \variable QShaderDescription::InOutVariable::perPatch + */ + +/*! + \variable QShaderDescription::InOutVariable::structMembers + */ + +/*! + \struct QShaderDescription::BlockVariable \inmodule QtGui + \since 6.6 \brief Describes a member of a uniform or push constant block. + + \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription + for details. */ /*! - \class QShaderDescription::UniformBlock - \internal + \variable QShaderDescription::BlockVariable::name + */ + +/*! + \variable QShaderDescription::BlockVariable::type + */ + +/*! + \variable QShaderDescription::BlockVariable::offset + */ + +/*! + \variable QShaderDescription::BlockVariable::size + */ + +/*! + \variable QShaderDescription::BlockVariable::arrayDims + */ + +/*! + \variable QShaderDescription::BlockVariable::arrayStride + */ + +/*! + \variable QShaderDescription::BlockVariable::matrixStride + */ + +/*! + \variable QShaderDescription::BlockVariable::matrixIsRowMajor + */ + +/*! + \variable QShaderDescription::BlockVariable::structMembers + */ + +/*! + \struct QShaderDescription::UniformBlock \inmodule QtGui + \since 6.6 \brief Describes a uniform block. @@ -229,22 +389,157 @@ QT_BEGIN_NAMESPACE (like GLSL 120 or GLSL/ES 100), uniform blocks are replaced with ordinary uniforms in a struct. The name of the struct, and so the prefix for the uniforms generated from the block members, is given by structName. + + \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription + for details. */ /*! - \class QShaderDescription::PushConstantBlock - \internal + \variable QShaderDescription::UniformBlock::blockName + */ + +/*! + \variable QShaderDescription::UniformBlock::structName + */ + +/*! + \variable QShaderDescription::UniformBlock::size + */ + +/*! + \variable QShaderDescription::UniformBlock::binding + */ + +/*! + \variable QShaderDescription::UniformBlock::descriptorSet + */ + +/*! + \variable QShaderDescription::UniformBlock::members + */ + +/*! + \struct QShaderDescription::PushConstantBlock \inmodule QtGui + \since 6.6 \brief Describes a push constant block. + + \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription + for details. */ /*! - \class QShaderDescription::StorageBlock - \internal + \variable QShaderDescription::PushConstantBlock::name + */ + +/*! + \variable QShaderDescription::PushConstantBlock::size + */ + +/*! + \variable QShaderDescription::PushConstantBlock::members + */ + +/*! + \struct QShaderDescription::StorageBlock \inmodule QtGui + \since 6.6 \brief Describes a shader storage block. + + \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription + for details. + */ + +/*! + \variable QShaderDescription::StorageBlock::blockName + */ + +/*! + \variable QShaderDescription::StorageBlock::instanceName + */ + +/*! + \variable QShaderDescription::StorageBlock::knownSize + */ + +/*! + \variable QShaderDescription::StorageBlock::binding + */ + +/*! + \variable QShaderDescription::StorageBlock::descriptorSet + */ + +/*! + \variable QShaderDescription::StorageBlock::members + */ + +/*! + \variable QShaderDescription::StorageBlock::runtimeArrayStride + */ + +/*! + \variable QShaderDescription::StorageBlock::qualifierFlags + */ + +/*! + \struct QShaderDescription::BuiltinVariable + \inmodule QtGui + \since 6.6 + + \brief Describes a built-in variable. + + \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription + for details. + */ + +/*! + \variable QShaderDescription::BuiltinVariable::type + */ + +/*! + \variable QShaderDescription::BuiltinVariable::varType + */ + +/*! + \variable QShaderDescription::BuiltinVariable::arrayDims + */ + +/*! + \enum QShaderDescription::BuiltinType + Built-in variable type. + + \value PositionBuiltin + \value PointSizeBuiltin + \value ClipDistanceBuiltin + \value CullDistanceBuiltin + \value VertexIdBuiltin + \value InstanceIdBuiltin + \value PrimitiveIdBuiltin + \value InvocationIdBuiltin + \value LayerBuiltin + \value ViewportIndexBuiltin + \value TessLevelOuterBuiltin + \value TessLevelInnerBuiltin + \value TessCoordBuiltin + \value PatchVerticesBuiltin + \value FragCoordBuiltin + \value PointCoordBuiltin + \value FrontFacingBuiltin + \value SampleIdBuiltin + \value SamplePositionBuiltin + \value SampleMaskBuiltin + \value FragDepthBuiltin + \value NumWorkGroupsBuiltin + \value WorkgroupSizeBuiltin + \value WorkgroupIdBuiltin + \value LocalInvocationIdBuiltin + \value GlobalInvocationIdBuiltin + \value LocalInvocationIndexBuiltin + \value VertexIndexBuiltin + \value InstanceIndexBuiltin */ /*! @@ -267,7 +562,7 @@ void QShaderDescription::detach() } /*! - \internal + Constructs a copy of \a other. */ QShaderDescription::QShaderDescription(const QShaderDescription &other) : d(other.d) @@ -276,7 +571,7 @@ QShaderDescription::QShaderDescription(const QShaderDescription &other) } /*! - \internal + Assigns \a other to this object. */ QShaderDescription &QShaderDescription::operator=(const QShaderDescription &other) { @@ -302,7 +597,8 @@ bool QShaderDescription::isValid() const return !d->inVars.isEmpty() || !d->outVars.isEmpty() || !d->uniformBlocks.isEmpty() || !d->pushConstantBlocks.isEmpty() || !d->storageBlocks.isEmpty() || !d->combinedImageSamplers.isEmpty() || !d->storageImages.isEmpty() - || !d->separateImages.isEmpty() || !d->separateSamplers.isEmpty(); + || !d->separateImages.isEmpty() || !d->separateSamplers.isEmpty() + || !d->inBuiltins.isEmpty() || !d->outBuiltins.isEmpty(); } /*! @@ -318,13 +614,14 @@ QByteArray QShaderDescription::toJson() const } /*! - Serializes this QShaderDescription to \a stream. + Serializes this QShaderDescription to \a stream. \a version specifies + the qsb version. \sa deserialize(), toJson() */ -void QShaderDescription::serialize(QDataStream *stream) const +void QShaderDescription::serialize(QDataStream *stream, int version) const { - d->writeToStream(stream); + d->writeToStream(stream, version); } /*! @@ -402,6 +699,7 @@ QList<QShaderDescription::PushConstantBlock> QShaderDescription::pushConstantBlo "blockName": "StuffSsbo", "instanceName": "buf", "knownSize": 16, + "runtimeArrayStride": 16 "members": [ { "name": "whatever", @@ -439,7 +737,10 @@ QList<QShaderDescription::PushConstantBlock> QShaderDescription::pushConstantBlo \note The size of the last member in the storage block is undefined. This shows up as \c size 0 and an array dimension of \c{[0]}. The storage block's \c knownSize - excludes the size of the last member since that will only be known at run time. + excludes the size of the last member since that will only be known at run time. The + stride in bytes between array items for a last member with undefined array size is + \c runtimeArrayStride. This value is determined according to the specified buffer + memory layout standard (std140, std430) rules. \note SSBOs are not available with some graphics APIs, such as, OpenGL 2.x or OpenGL ES older than 3.1. @@ -514,7 +815,26 @@ QList<QShaderDescription::InOutVariable> QShaderDescription::storageImages() con } /*! - Returns the local size of a compute shader. + \return the list of active builtins used as input. For example, a + tessellation evaluation shader reading the value of gl_TessCoord and + gl_Position will have TessCoordBuiltin and PositionBuiltin listed here. + */ +QVector<QShaderDescription::BuiltinVariable> QShaderDescription::inputBuiltinVariables() const +{ + return d->inBuiltins; +} + +/*! + \return the list of active built-in variables used as input. For example, a + vertex shader will very often have PositionBuiltin as an output built-in. + */ +QVector<QShaderDescription::BuiltinVariable> QShaderDescription::outputBuiltinVariables() const +{ + return d->outBuiltins; +} + +/*! + \return the local size of a compute shader. For example, for a compute shader with the following declaration the function returns { 256, 16, 1}. @@ -528,6 +848,101 @@ std::array<uint, 3> QShaderDescription::computeShaderLocalSize() const return d->localSize; } +/*! + \return the number of output vertices. + + For example, for a tessellation control shader with the following + declaration the function returns 3. + + \badcode + layout(vertices = 3) out; + \endcode + */ +uint QShaderDescription::tessellationOutputVertexCount() const +{ + return d->tessOutVertCount; +} + +/*! + \enum QShaderDescription::TessellationMode + + \value UnknownTessellationMode + \value TrianglesTessellationMode + \value QuadTessellationMode + \value IsolineTessellationMode + */ + +/*! + \return the tessellation execution mode for a tessellation control or + evaluation shader. + + When not set, the returned value is UnknownTessellationMode. + + For example, for a tessellation evaluation shader with the following + declaration the function returns TrianglesTessellationMode. + + \badcode + layout(triangles) in; + \endcode + */ +QShaderDescription::TessellationMode QShaderDescription::tessellationMode() const +{ + return d->tessMode; +} + +/*! + \enum QShaderDescription::TessellationWindingOrder + + \value UnknownTessellationWindingOrder + \value CwTessellationWindingOrder + \value CcwTessellationWindingOrder + */ + +/*! + \return the tessellation winding order for a tessellation control or + evaluation shader. + + When not set, the returned value is UnknownTessellationWindingOrder. + + For example, for a tessellation evaluation shader with the following + declaration the function returns CcwTessellationWindingOrder. + + \badcode + layout(triangles, fractional_odd_spacing, ccw) in; + \endcode + */ +QShaderDescription::TessellationWindingOrder QShaderDescription::tessellationWindingOrder() const +{ + return d->tessWind; +} + +/*! + \enum QShaderDescription::TessellationPartitioning + + \value UnknownTessellationPartitioning + \value EqualTessellationPartitioning + \value FractionalEvenTessellationPartitioning + \value FractionalOddTessellationPartitioning + */ + +/*! + \return the tessellation partitioning mode for a tessellation control or + evaluation shader. + + When not set, the returned value is UnknownTessellationPartitioning. + + For example, for a tessellation evaluation shader with the following + declaration the function returns FractionalOddTessellationPartitioning. + + \badcode + layout(triangles, fractional_odd_spacing, ccw) in; + \endcode + */ +QShaderDescription::TessellationPartitioning QShaderDescription::tessellationPartitioning() const +{ + return d->tessPart; +} + static const struct TypeTab { const char k[20]; QShaderDescription::VariableType v; @@ -604,10 +1019,14 @@ static const struct TypeTab { { "image3DArray", QShaderDescription::Image3DArray }, { "imageCubeArray", QShaderDescription::ImageCubeArray }, { "imageRect", QShaderDescription::ImageRect }, - { "imageBuffer", QShaderDescription::ImageBuffer } -}; + { "imageBuffer", QShaderDescription::ImageBuffer }, -static QLatin1StringView typeStr(const QShaderDescription::VariableType &t) + { "half", QShaderDescription::Half }, + { "half2", QShaderDescription::Half2 }, + { "half3", QShaderDescription::Half3 }, + { "half4", QShaderDescription::Half4 } }; + +static QLatin1StringView typeStr(QShaderDescription::VariableType t) { for (size_t i = 0; i < sizeof(typeTab) / sizeof(TypeTab); ++i) { if (typeTab[i].v == t) @@ -662,7 +1081,7 @@ static const struct ImageFormatTab { { "r8ui", QShaderDescription::ImageFormatR8ui } }; -static QLatin1StringView imageFormatStr(const QShaderDescription::ImageFormat &f) +static QLatin1StringView imageFormatStr(QShaderDescription::ImageFormat f) { for (size_t i = 0; i < sizeof(imageFormatTab) / sizeof(ImageFormatTab); ++i) { if (imageFormatTab[i].v == f) @@ -671,6 +1090,106 @@ static QLatin1StringView imageFormatStr(const QShaderDescription::ImageFormat &f return {}; } +static const struct BuiltinTypeTab { + const char k[21]; + QShaderDescription::BuiltinType v; +} builtinTypeTab[] = { + { "Position", QShaderDescription::PositionBuiltin }, + { "PointSize", QShaderDescription::PointSizeBuiltin }, + { "ClipDistance", QShaderDescription::ClipDistanceBuiltin }, + { "CullDistance", QShaderDescription::CullDistanceBuiltin }, + { "VertexId", QShaderDescription::VertexIdBuiltin }, + { "InstanceId", QShaderDescription::InstanceIdBuiltin }, + { "PrimitiveId", QShaderDescription::PrimitiveIdBuiltin }, + { "InvocationId", QShaderDescription::InvocationIdBuiltin }, + { "Layer", QShaderDescription::LayerBuiltin }, + { "ViewportIndex", QShaderDescription::ViewportIndexBuiltin }, + { "TessLevelOuter", QShaderDescription::TessLevelOuterBuiltin }, + { "TessLevelInner", QShaderDescription::TessLevelInnerBuiltin }, + { "TessCoord", QShaderDescription::TessCoordBuiltin }, + { "PatchVertices", QShaderDescription::PatchVerticesBuiltin }, + { "FragCoord", QShaderDescription::FragCoordBuiltin }, + { "PointCoord", QShaderDescription::PointCoordBuiltin }, + { "FrontFacing", QShaderDescription::FrontFacingBuiltin }, + { "SampleId", QShaderDescription::SampleIdBuiltin }, + { "SamplePosition", QShaderDescription::SamplePositionBuiltin }, + { "SampleMask", QShaderDescription::SampleMaskBuiltin }, + { "FragDepth", QShaderDescription::FragDepthBuiltin }, + { "NumWorkGroups", QShaderDescription::NumWorkGroupsBuiltin }, + { "WorkgroupSize", QShaderDescription::WorkgroupSizeBuiltin }, + { "WorkgroupId", QShaderDescription::WorkgroupIdBuiltin }, + { "LocalInvocationId", QShaderDescription::LocalInvocationIdBuiltin }, + { "GlobalInvocationId", QShaderDescription::GlobalInvocationIdBuiltin }, + { "LocalInvocationIndex", QShaderDescription::LocalInvocationIndexBuiltin }, + { "VertexIndex", QShaderDescription::VertexIndexBuiltin }, + { "InstanceIndex", QShaderDescription::InstanceIndexBuiltin } +}; + +static QLatin1StringView builtinTypeStr(QShaderDescription::BuiltinType t) +{ + for (size_t i = 0; i < sizeof(builtinTypeTab) / sizeof(BuiltinTypeTab); ++i) { + if (builtinTypeTab[i].v == t) + return QLatin1StringView(builtinTypeTab[i].k); + } + return {}; +} + +static const struct TessellationModeTab { + const char k[10]; + QShaderDescription::TessellationMode v; +} tessellationModeTab[] { + { "unknown", QShaderDescription::UnknownTessellationMode }, + { "triangles", QShaderDescription::TrianglesTessellationMode }, + { "quad", QShaderDescription::QuadTessellationMode }, + { "isoline", QShaderDescription::IsolineTessellationMode } +}; + +static QLatin1StringView tessModeStr(QShaderDescription::TessellationMode mode) +{ + for (size_t i = 0; i < sizeof(tessellationModeTab) / sizeof(TessellationModeTab); ++i) { + if (tessellationModeTab[i].v == mode) + return QLatin1StringView(tessellationModeTab[i].k); + } + return {}; +} + +static const struct TessellationWindingOrderTab { + const char k[8]; + QShaderDescription::TessellationWindingOrder v; +} tessellationWindingOrderTab[] { + { "unknown", QShaderDescription::UnknownTessellationWindingOrder }, + { "cw", QShaderDescription::CwTessellationWindingOrder }, + { "ccw", QShaderDescription::CcwTessellationWindingOrder } +}; + +static QLatin1StringView tessWindStr(QShaderDescription::TessellationWindingOrder w) +{ + for (size_t i = 0; i < sizeof(tessellationWindingOrderTab) / sizeof(TessellationWindingOrderTab); ++i) { + if (tessellationWindingOrderTab[i].v == w) + return QLatin1StringView(tessellationWindingOrderTab[i].k); + } + return {}; +} + +static const struct TessellationPartitioningTab { + const char k[24]; + QShaderDescription::TessellationPartitioning v; +} tessellationPartitioningTab[] { + { "unknown", QShaderDescription::UnknownTessellationPartitioning }, + { "equal_spacing", QShaderDescription::EqualTessellationPartitioning }, + { "fractional_even_spacing", QShaderDescription::FractionalEvenTessellationPartitioning }, + { "fractional_odd_spacing", QShaderDescription::FractionalOddTessellationPartitioning } +}; + +static QLatin1StringView tessPartStr(QShaderDescription::TessellationPartitioning p) +{ + for (size_t i = 0; i < sizeof(tessellationPartitioningTab) / sizeof(TessellationPartitioningTab); ++i) { + if (tessellationPartitioningTab[i].v == p) + return QLatin1StringView(tessellationPartitioningTab[i].k); + } + return {}; +} + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug dbg, const QShaderDescription &sd) { @@ -688,6 +1207,8 @@ QDebug operator<<(QDebug dbg, const QShaderDescription &sd) << " storageImages " << d->storageImages << " separateImages " << d->separateImages << " separateSamplers " << d->separateSamplers + << " inBuiltins " << d->inBuiltins + << " outBuiltins " << d->outBuiltins << ')'; } else { dbg.nospace() << "QShaderDescription(null)"; @@ -700,6 +1221,8 @@ QDebug operator<<(QDebug dbg, const QShaderDescription::InOutVariable &var) { QDebugStateSaver saver(dbg); dbg.nospace() << "InOutVariable(" << typeStr(var.type) << ' ' << var.name; + if (var.perPatch) + dbg.nospace() << " per-patch"; if (var.location >= 0) dbg.nospace() << " location=" << var.location; if (var.binding >= 0) @@ -712,6 +1235,8 @@ QDebug operator<<(QDebug dbg, const QShaderDescription::InOutVariable &var) dbg.nospace() << " imageFlags=" << var.imageFlags; if (!var.arrayDims.isEmpty()) dbg.nospace() << " array=" << var.arrayDims; + if (!var.structMembers.isEmpty()) + dbg.nospace() << " structMembers=" << var.structMembers; dbg.nospace() << ')'; return dbg; } @@ -719,8 +1244,10 @@ QDebug operator<<(QDebug dbg, const QShaderDescription::InOutVariable &var) QDebug operator<<(QDebug dbg, const QShaderDescription::BlockVariable &var) { QDebugStateSaver saver(dbg); - dbg.nospace() << "BlockVariable(" << typeStr(var.type) << ' ' << var.name - << " offset=" << var.offset << " size=" << var.size; + dbg.nospace() << "BlockVariable(" << typeStr(var.type) << ' ' << var.name; + if (var.offset != -1) + dbg.nospace() << " offset=" << var.offset; + dbg.nospace() << " size=" << var.size; if (!var.arrayDims.isEmpty()) dbg.nospace() << " array=" << var.arrayDims; if (var.arrayStride) @@ -765,9 +1292,24 @@ QDebug operator<<(QDebug dbg, const QShaderDescription::StorageBlock &blk) dbg.nospace() << " binding=" << blk.binding; if (blk.descriptorSet >= 0) dbg.nospace() << " set=" << blk.descriptorSet; + if (blk.runtimeArrayStride) + dbg.nospace() << " runtimeArrayStride=" << blk.runtimeArrayStride; + if (blk.qualifierFlags) + dbg.nospace() << " qualifierFlags=" << blk.qualifierFlags; dbg.nospace() << ' ' << blk.members << ')'; return dbg; } + +QDebug operator<<(QDebug dbg, const QShaderDescription::BuiltinVariable &builtin) +{ + QDebugStateSaver saver(dbg); + dbg.nospace() << "BuiltinVariable(type=" << builtinTypeStr(builtin.type); + dbg.nospace() << " varType=" << typeStr(builtin.varType); + if (!builtin.arrayDims.isEmpty()) + dbg.nospace() << " array=" << builtin.arrayDims; + dbg.nospace() << ")"; + return dbg; +} #endif #define JSON_KEY(key) static constexpr QLatin1StringView key ## Key() noexcept { return QLatin1StringView( #key ); } @@ -776,6 +1318,7 @@ JSON_KEY(type) JSON_KEY(location) JSON_KEY(binding) JSON_KEY(set) +JSON_KEY(perPatch) JSON_KEY(imageFormat) JSON_KEY(imageFlags) JSON_KEY(offset) @@ -797,9 +1340,17 @@ JSON_KEY(pushConstantBlocks) JSON_KEY(storageBlocks) JSON_KEY(combinedImageSamplers) JSON_KEY(storageImages) -JSON_KEY(localSize) +JSON_KEY(inBuiltins) +JSON_KEY(outBuiltins) +JSON_KEY(computeLocalSize) +JSON_KEY(tessellationOutputVertexCount) +JSON_KEY(tessellationMode) +JSON_KEY(tessellationWindingOrder) +JSON_KEY(tessellationPartitioning) JSON_KEY(separateImages) JSON_KEY(separateSamplers) +JSON_KEY(runtimeArrayStride) +JSON_KEY(qualifierFlags) #undef JSON_KEY static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v) @@ -810,6 +1361,8 @@ static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v (*obj)[bindingKey()] = v.binding; if (v.descriptorSet >= 0) (*obj)[setKey()] = v.descriptorSet; + if (v.perPatch) + (*obj)[perPatchKey()] = v.perPatch; if (v.imageFormat != QShaderDescription::ImageFormatUnknown) (*obj)[imageFormatKey()] = imageFormatStr(v.imageFormat); if (v.imageFlags) @@ -822,32 +1375,29 @@ static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v } } -static void serializeDecorations(QDataStream *stream, const QShaderDescription::InOutVariable &v) +static void serializeDecorations(QDataStream *stream, const QShaderDescription::InOutVariable &v, int version) { (*stream) << v.location; (*stream) << v.binding; (*stream) << v.descriptorSet; (*stream) << int(v.imageFormat); (*stream) << int(v.imageFlags); - (*stream) << int(v.arrayDims.count()); + (*stream) << int(v.arrayDims.size()); for (int dim : v.arrayDims) (*stream) << dim; + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO) + (*stream) << quint8(v.perPatch); } -static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v) -{ - QJsonObject obj; - obj[nameKey()] = QString::fromUtf8(v.name); - obj[typeKey()] = typeStr(v.type); - addDeco(&obj, v); - return obj; -} - -static void serializeInOutVar(QDataStream *stream, const QShaderDescription::InOutVariable &v) +static void serializeBuiltinVar(QDataStream *stream, const QShaderDescription::BuiltinVariable &v, int version) { - (*stream) << QString::fromUtf8(v.name); (*stream) << int(v.type); - serializeDecorations(stream, v); + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_INPUT_OUTPUT_INTERFACE_BLOCKS) { + (*stream) << int(v.varType); + (*stream) << int(v.arrayDims.size()); + for (int dim : v.arrayDims) + (*stream) << dim; + } } static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v) @@ -855,7 +1405,8 @@ static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v) QJsonObject obj; obj[nameKey()] = QString::fromUtf8(v.name); obj[typeKey()] = typeStr(v.type); - obj[offsetKey()] = v.offset; + if (v.offset != -1) + obj[offsetKey()] = v.offset; obj[sizeKey()] = v.size; if (!v.arrayDims.isEmpty()) { QJsonArray dimArr; @@ -878,35 +1429,78 @@ static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v) return obj; } +static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v) +{ + QJsonObject obj; + obj[nameKey()] = QString::fromUtf8(v.name); + obj[typeKey()] = typeStr(v.type); + addDeco(&obj, v); + if (!v.structMembers.isEmpty()) { + QJsonArray arr; + for (const QShaderDescription::BlockVariable &sv : v.structMembers) + arr.append(blockMemberObject(sv)); + obj[structMembersKey()] = arr; + } + return obj; +} + +static QJsonObject builtinObject(const QShaderDescription::BuiltinVariable &v) +{ + QJsonObject obj; + + obj[nameKey()] = builtinTypeStr(v.type); + obj[typeKey()] = typeStr(v.varType); + if (!v.arrayDims.isEmpty()) { + QJsonArray dimArr; + for (int dim : v.arrayDims) + dimArr.append(dim); + obj[arrayDimsKey()] = dimArr; + } + return obj; +} + static void serializeBlockMemberVar(QDataStream *stream, const QShaderDescription::BlockVariable &v) { (*stream) << QString::fromUtf8(v.name); (*stream) << int(v.type); (*stream) << v.offset; (*stream) << v.size; - (*stream) << int(v.arrayDims.count()); + (*stream) << int(v.arrayDims.size()); for (int dim : v.arrayDims) (*stream) << dim; (*stream) << v.arrayStride; (*stream) << v.matrixStride; (*stream) << v.matrixIsRowMajor; - (*stream) << int(v.structMembers.count()); + (*stream) << int(v.structMembers.size()); for (const QShaderDescription::BlockVariable &sv : v.structMembers) serializeBlockMemberVar(stream, sv); } +static void serializeInOutVar(QDataStream *stream, const QShaderDescription::InOutVariable &v, + int version) +{ + (*stream) << QString::fromUtf8(v.name); + (*stream) << int(v.type); + serializeDecorations(stream, v, version); + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_INPUT_OUTPUT_INTERFACE_BLOCKS) { + (*stream) << int(v.structMembers.size()); + for (const QShaderDescription::BlockVariable &sv : v.structMembers) + serializeBlockMemberVar(stream, sv); + } +} + QJsonDocument QShaderDescriptionPrivate::makeDoc() { QJsonObject root; QJsonArray jinputs; - for (const QShaderDescription::InOutVariable &v : qAsConst(inVars)) + for (const QShaderDescription::InOutVariable &v : std::as_const(inVars)) jinputs.append(inOutObject(v)); if (!jinputs.isEmpty()) root[inputsKey()] = jinputs; QJsonArray joutputs; - for (const QShaderDescription::InOutVariable &v : qAsConst(outVars)) + for (const QShaderDescription::InOutVariable &v : std::as_const(outVars)) joutputs.append(inOutObject(v)); if (!joutputs.isEmpty()) root[outputsKey()] = joutputs; @@ -954,6 +1548,10 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc() jstorageBlock[bindingKey()] = b.binding; if (b.descriptorSet >= 0) jstorageBlock[setKey()] = b.descriptorSet; + if (b.runtimeArrayStride) + jstorageBlock[runtimeArrayStrideKey()] = b.runtimeArrayStride; + if (b.qualifierFlags) + jstorageBlock[qualifierFlagsKey()] = int(b.qualifierFlags); QJsonArray members; for (const QShaderDescription::BlockVariable &v : b.members) members.append(blockMemberObject(v)); @@ -964,7 +1562,7 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc() root[storageBlocksKey()] = jstorageBlocks; QJsonArray jcombinedSamplers; - for (const QShaderDescription::InOutVariable &v : qAsConst(combinedImageSamplers)) { + for (const QShaderDescription::InOutVariable &v : std::as_const(combinedImageSamplers)) { QJsonObject sampler; sampler[nameKey()] = QString::fromUtf8(v.name); sampler[typeKey()] = typeStr(v.type); @@ -975,7 +1573,7 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc() root[combinedImageSamplersKey()] = jcombinedSamplers; QJsonArray jstorageImages; - for (const QShaderDescription::InOutVariable &v : qAsConst(storageImages)) { + for (const QShaderDescription::InOutVariable &v : std::as_const(storageImages)) { QJsonObject image; image[nameKey()] = QString::fromUtf8(v.name); image[typeKey()] = typeStr(v.type); @@ -985,13 +1583,39 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc() if (!jstorageImages.isEmpty()) root[storageImagesKey()] = jstorageImages; - QJsonArray jlocalSize; - for (int i = 0; i < 3; ++i) - jlocalSize.append(QJsonValue(int(localSize[i]))); - root[localSizeKey()] = jlocalSize; + QJsonArray jinBuiltins; + for (const QShaderDescription::BuiltinVariable &v : std::as_const(inBuiltins)) + jinBuiltins.append(builtinObject(v)); + if (!jinBuiltins.isEmpty()) + root[inBuiltinsKey()] = jinBuiltins; + + QJsonArray joutBuiltins; + for (const QShaderDescription::BuiltinVariable &v : std::as_const(outBuiltins)) + joutBuiltins.append(builtinObject(v)); + if (!joutBuiltins.isEmpty()) + root[outBuiltinsKey()] = joutBuiltins; + + if (localSize[0] || localSize[1] || localSize[2]) { + QJsonArray jlocalSize; + for (size_t i = 0; i < 3; ++i) + jlocalSize.append(QJsonValue(int(localSize[i]))); + root[computeLocalSizeKey()] = jlocalSize; + } + + if (tessOutVertCount) + root[tessellationOutputVertexCountKey()] = int(tessOutVertCount); + + if (tessMode != QShaderDescription::UnknownTessellationMode) + root[tessellationModeKey()] = tessModeStr(tessMode); + + if (tessWind != QShaderDescription::UnknownTessellationWindingOrder) + root[tessellationWindingOrderKey()] = tessWindStr(tessWind); + + if (tessPart != QShaderDescription::UnknownTessellationPartitioning) + root[tessellationPartitioningKey()] = tessPartStr(tessPart); QJsonArray jseparateImages; - for (const QShaderDescription::InOutVariable &v : qAsConst(separateImages)) { + for (const QShaderDescription::InOutVariable &v : std::as_const(separateImages)) { QJsonObject image; image[nameKey()] = QString::fromUtf8(v.name); image[typeKey()] = typeStr(v.type); @@ -1002,7 +1626,7 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc() root[separateImagesKey()] = jseparateImages; QJsonArray jseparateSamplers; - for (const QShaderDescription::InOutVariable &v : qAsConst(separateSamplers)) { + for (const QShaderDescription::InOutVariable &v : std::as_const(separateSamplers)) { QJsonObject sampler; sampler[nameKey()] = QString::fromUtf8(v.name); sampler[typeKey()] = typeStr(v.type); @@ -1015,78 +1639,97 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc() return QJsonDocument(root); } -void QShaderDescriptionPrivate::writeToStream(QDataStream *stream) +void QShaderDescriptionPrivate::writeToStream(QDataStream *stream, int version) { - (*stream) << int(inVars.count()); - for (const QShaderDescription::InOutVariable &v : qAsConst(inVars)) - serializeInOutVar(stream, v); + (*stream) << int(inVars.size()); + for (const QShaderDescription::InOutVariable &v : std::as_const(inVars)) + serializeInOutVar(stream, v, version); - (*stream) << int(outVars.count()); - for (const QShaderDescription::InOutVariable &v : qAsConst(outVars)) - serializeInOutVar(stream, v); + (*stream) << int(outVars.size()); + for (const QShaderDescription::InOutVariable &v : std::as_const(outVars)) + serializeInOutVar(stream, v, version); - (*stream) << int(uniformBlocks.count()); + (*stream) << int(uniformBlocks.size()); for (const QShaderDescription::UniformBlock &b : uniformBlocks) { (*stream) << QString::fromUtf8(b.blockName); (*stream) << QString::fromUtf8(b.structName); (*stream) << b.size; (*stream) << b.binding; (*stream) << b.descriptorSet; - (*stream) << int(b.members.count()); + (*stream) << int(b.members.size()); for (const QShaderDescription::BlockVariable &v : b.members) serializeBlockMemberVar(stream, v); } - (*stream) << int(pushConstantBlocks.count()); + (*stream) << int(pushConstantBlocks.size()); for (const QShaderDescription::PushConstantBlock &b : pushConstantBlocks) { (*stream) << QString::fromUtf8(b.name); (*stream) << b.size; - (*stream) << int(b.members.count()); + (*stream) << int(b.members.size()); for (const QShaderDescription::BlockVariable &v : b.members) serializeBlockMemberVar(stream, v); } - (*stream) << int(storageBlocks.count()); + (*stream) << int(storageBlocks.size()); for (const QShaderDescription::StorageBlock &b : storageBlocks) { (*stream) << QString::fromUtf8(b.blockName); (*stream) << QString::fromUtf8(b.instanceName); (*stream) << b.knownSize; (*stream) << b.binding; (*stream) << b.descriptorSet; - (*stream) << int(b.members.count()); + (*stream) << int(b.members.size()); for (const QShaderDescription::BlockVariable &v : b.members) serializeBlockMemberVar(stream, v); + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO) { + (*stream) << b.runtimeArrayStride; + (*stream) << b.qualifierFlags; + } } - (*stream) << int(combinedImageSamplers.count()); - for (const QShaderDescription::InOutVariable &v : qAsConst(combinedImageSamplers)) { + (*stream) << int(combinedImageSamplers.size()); + for (const QShaderDescription::InOutVariable &v : std::as_const(combinedImageSamplers)) { (*stream) << QString::fromUtf8(v.name); (*stream) << int(v.type); - serializeDecorations(stream, v); + serializeDecorations(stream, v, version); } - (*stream) << int(storageImages.count()); - for (const QShaderDescription::InOutVariable &v : qAsConst(storageImages)) { + (*stream) << int(storageImages.size()); + for (const QShaderDescription::InOutVariable &v : std::as_const(storageImages)) { (*stream) << QString::fromUtf8(v.name); (*stream) << int(v.type); - serializeDecorations(stream, v); + serializeDecorations(stream, v, version); } for (size_t i = 0; i < 3; ++i) - (*stream) << localSize[i]; + (*stream) << quint32(localSize[i]); - (*stream) << int(separateImages.count()); - for (const QShaderDescription::InOutVariable &v : qAsConst(separateImages)) { + (*stream) << int(separateImages.size()); + for (const QShaderDescription::InOutVariable &v : std::as_const(separateImages)) { (*stream) << QString::fromUtf8(v.name); (*stream) << int(v.type); - serializeDecorations(stream, v); + serializeDecorations(stream, v, version); } - (*stream) << int(separateSamplers.count()); - for (const QShaderDescription::InOutVariable &v : qAsConst(separateSamplers)) { + (*stream) << int(separateSamplers.size()); + for (const QShaderDescription::InOutVariable &v : std::as_const(separateSamplers)) { (*stream) << QString::fromUtf8(v.name); (*stream) << int(v.type); - serializeDecorations(stream, v); + serializeDecorations(stream, v, version); + } + + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO) { + (*stream) << quint32(tessOutVertCount); + (*stream) << quint32(tessMode); + (*stream) << quint32(tessWind); + (*stream) << quint32(tessPart); + + (*stream) << int(inBuiltins.size()); + for (const QShaderDescription::BuiltinVariable &v : std::as_const(inBuiltins)) + serializeBuiltinVar(stream, v, version); + + (*stream) << int(outBuiltins.size()); + for (const QShaderDescription::BuiltinVariable &v : std::as_const(outBuiltins)) + serializeBuiltinVar(stream, v, version); } } @@ -1107,18 +1750,29 @@ static void deserializeDecorations(QDataStream *stream, int version, QShaderDesc for (int i = 0; i < f; ++i) (*stream) >> v->arrayDims[i]; } + + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO) { + quint8 b; + (*stream) >> b; + v->perPatch = b; + } } -static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream, int version) +static QShaderDescription::BuiltinVariable deserializeBuiltinVar(QDataStream *stream, int version) { - QShaderDescription::InOutVariable var; - QString tmp; - (*stream) >> tmp; - var.name = tmp.toUtf8(); + QShaderDescription::BuiltinVariable var; int t; (*stream) >> t; - var.type = QShaderDescription::VariableType(t); - deserializeDecorations(stream, version, &var); + var.type = QShaderDescription::BuiltinType(t); + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_INPUT_OUTPUT_INTERFACE_BLOCKS) { + (*stream) >> t; + var.varType = QShaderDescription::VariableType(t); + int count; + (*stream) >> count; + var.arrayDims.resize(count); + for (int i = 0; i < count; ++i) + (*stream) >> var.arrayDims[i]; + } return var; } @@ -1148,6 +1802,26 @@ static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream * return var; } +static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream, int version) +{ + QShaderDescription::InOutVariable var; + QString tmp; + (*stream) >> tmp; + var.name = tmp.toUtf8(); + int t; + (*stream) >> t; + var.type = QShaderDescription::VariableType(t); + deserializeDecorations(stream, version, &var); + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_INPUT_OUTPUT_INTERFACE_BLOCKS) { + int count; + (*stream) >> count; + var.structMembers.resize(count); + for (int i = 0; i < count; ++i) + var.structMembers[i] = deserializeBlockMemberVar(stream, version); + } + return var; +} + void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream, int version) { Q_ASSERT(ref.loadRelaxed() == 1); // must be detached @@ -1211,6 +1885,11 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream, int version) storageBlocks[i].members.resize(memberCount); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version); + + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO) { + (*stream) >> storageBlocks[i].runtimeArrayStride; + (*stream) >> storageBlocks[i].qualifierFlags; + } } (*stream) >> count; @@ -1237,8 +1916,11 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream, int version) deserializeDecorations(stream, version, &storageImages[i]); } - for (size_t i = 0; i < 3; ++i) - (*stream) >> localSize[i]; + for (size_t i = 0; i < 3; ++i) { + quint32 v; + (*stream) >> v; + localSize[i] = v; + } if (version > QShaderPrivate::QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS) { (*stream) >> count; @@ -1265,6 +1947,28 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream, int version) deserializeDecorations(stream, version, &separateSamplers[i]); } } + + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO) { + quint32 v; + (*stream) >> v; + tessOutVertCount = v; + (*stream) >> v; + tessMode = QShaderDescription::TessellationMode(v); + (*stream) >> v; + tessWind = QShaderDescription::TessellationWindingOrder(v); + (*stream) >> v; + tessPart = QShaderDescription::TessellationPartitioning(v); + + (*stream) >> count; + inBuiltins.resize(count); + for (int i = 0; i < count; ++i) + inBuiltins[i] = deserializeBuiltinVar(stream, version); + + (*stream) >> count; + outBuiltins.resize(count); + for (int i = 0; i < count; ++i) + outBuiltins[i] = deserializeBuiltinVar(stream, version); + } } /*! @@ -1287,7 +1991,13 @@ bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) no && lhs.d->separateImages == rhs.d->separateImages && lhs.d->separateSamplers == rhs.d->separateSamplers && lhs.d->storageImages == rhs.d->storageImages - && lhs.d->localSize == rhs.d->localSize; + && lhs.d->inBuiltins == rhs.d->inBuiltins + && lhs.d->outBuiltins == rhs.d->outBuiltins + && lhs.d->localSize == rhs.d->localSize + && lhs.d->tessOutVertCount == rhs.d->tessOutVertCount + && lhs.d->tessMode == rhs.d->tessMode + && lhs.d->tessWind == rhs.d->tessWind + && lhs.d->tessPart == rhs.d->tessPart; } /*! @@ -1305,7 +2015,9 @@ bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescr && lhs.descriptorSet == rhs.descriptorSet && lhs.imageFormat == rhs.imageFormat && lhs.imageFlags == rhs.imageFlags - && lhs.arrayDims == rhs.arrayDims; + && lhs.arrayDims == rhs.arrayDims + && lhs.perPatch == rhs.perPatch + && lhs.structMembers == rhs.structMembers; } /*! @@ -1369,7 +2081,22 @@ bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescri && lhs.knownSize == rhs.knownSize && lhs.binding == rhs.binding && lhs.descriptorSet == rhs.descriptorSet + && lhs.runtimeArrayStride == rhs.runtimeArrayStride + && lhs.qualifierFlags == rhs.qualifierFlags && lhs.members == rhs.members; } +/*! + Returns \c true if the two BuiltinVariable objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription::BuiltinVariable + */ +bool operator==(const QShaderDescription::BuiltinVariable &lhs, const QShaderDescription::BuiltinVariable &rhs) noexcept +{ + return lhs.type == rhs.type + && lhs.varType == rhs.varType + && lhs.arrayDims == rhs.arrayDims; +} + QT_END_NAMESPACE |