diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2022-08-18 12:43:23 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2022-09-01 19:44:19 +0200 |
commit | c681c7c23f79e2f0d6dbb2ce8961edd216cefd91 (patch) | |
tree | 861706d22bb395ff5e1f86c4948a0cc7e8cab9ac /src/gui/rhi/qshaderdescription.cpp | |
parent | 855a9ca217ad3b9d8eb8f6544698a174323843fc (diff) |
rhi: metal: Add support for tessellation
Change-Id: Ie8d226a6a959aa5e78284ea72505fd26aec1e671
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src/gui/rhi/qshaderdescription.cpp')
-rw-r--r-- | src/gui/rhi/qshaderdescription.cpp | 364 |
1 files changed, 350 insertions, 14 deletions
diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp index d55caed210..2018a3bc13 100644 --- a/src/gui/rhi/qshaderdescription.cpp +++ b/src/gui/rhi/qshaderdescription.cpp @@ -302,7 +302,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(); } /*! @@ -514,7 +515,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 +548,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 IsolinesTessellationMode + */ + +/*! + \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; @@ -607,7 +722,7 @@ static const struct TypeTab { { "imageBuffer", QShaderDescription::ImageBuffer } }; -static QLatin1StringView typeStr(const QShaderDescription::VariableType &t) +static QLatin1StringView typeStr(QShaderDescription::VariableType t) { for (size_t i = 0; i < sizeof(typeTab) / sizeof(TypeTab); ++i) { if (typeTab[i].v == t) @@ -662,7 +777,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 +786,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 +903,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 +917,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) @@ -768,6 +987,13 @@ QDebug operator<<(QDebug dbg, const QShaderDescription::StorageBlock &blk) dbg.nospace() << ' ' << blk.members << ')'; return dbg; } + +QDebug operator<<(QDebug dbg, const QShaderDescription::BuiltinVariable &builtin) +{ + QDebugStateSaver saver(dbg); + dbg.nospace() << "BuiltinVariable(type=" << builtinTypeStr(builtin.type) << ")"; + return dbg; +} #endif #define JSON_KEY(key) static constexpr QLatin1StringView key ## Key() noexcept { return QLatin1StringView( #key ); } @@ -776,6 +1002,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,7 +1024,13 @@ 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) #undef JSON_KEY @@ -810,6 +1043,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) @@ -832,6 +1067,7 @@ static void serializeDecorations(QDataStream *stream, const QShaderDescription:: (*stream) << int(v.arrayDims.count()); for (int dim : v.arrayDims) (*stream) << dim; + (*stream) << quint8(v.perPatch); } static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v) @@ -985,10 +1221,42 @@ 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 : qAsConst(inBuiltins)) { + QJsonObject builtin; + builtin[typeKey()] = builtinTypeStr(v.type); + jinBuiltins.append(builtin); + } + if (!jinBuiltins.isEmpty()) + root[inBuiltinsKey()] = jinBuiltins; + + QJsonArray joutBuiltins; + for (const QShaderDescription::BuiltinVariable &v : qAsConst(outBuiltins)) { + QJsonObject builtin; + builtin[typeKey()] = builtinTypeStr(v.type); + joutBuiltins.append(builtin); + } + 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)) { @@ -1073,7 +1341,7 @@ void QShaderDescriptionPrivate::writeToStream(QDataStream *stream) } 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)) { @@ -1088,6 +1356,19 @@ void QShaderDescriptionPrivate::writeToStream(QDataStream *stream) (*stream) << int(v.type); serializeDecorations(stream, v); } + + (*stream) << quint32(tessOutVertCount); + (*stream) << quint32(tessMode); + (*stream) << quint32(tessWind); + (*stream) << quint32(tessPart); + + (*stream) << int(inBuiltins.count()); + for (const QShaderDescription::BuiltinVariable &v : qAsConst(inBuiltins)) + (*stream) << int(v.type); + + (*stream) << int(outBuiltins.count()); + for (const QShaderDescription::BuiltinVariable &v : qAsConst(outBuiltins)) + (*stream) << int(v.type); } static void deserializeDecorations(QDataStream *stream, int version, QShaderDescription::InOutVariable *v) @@ -1107,6 +1388,12 @@ 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) @@ -1237,8 +1524,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 +1555,34 @@ 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) { + int t; + (*stream) >> t; + inBuiltins[i].type = QShaderDescription::BuiltinType(t); + } + + (*stream) >> count; + outBuiltins.resize(count); + for (int i = 0; i < count; ++i) { + int t; + (*stream) >> t; + outBuiltins[i].type = QShaderDescription::BuiltinType(t); + } + } } /*! @@ -1287,7 +1605,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 +1629,8 @@ 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; } /*! @@ -1372,4 +1697,15 @@ bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescri && 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; +} + QT_END_NAMESPACE |