summaryrefslogtreecommitdiffstats
path: root/src/gui/rhi/qshaderdescription.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2022-08-18 12:43:23 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2022-09-01 19:44:19 +0200
commitc681c7c23f79e2f0d6dbb2ce8961edd216cefd91 (patch)
tree861706d22bb395ff5e1f86c4948a0cc7e8cab9ac /src/gui/rhi/qshaderdescription.cpp
parent855a9ca217ad3b9d8eb8f6544698a174323843fc (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.cpp364
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