rhi: metal: Make base vertex and instance support optional

Like we do for OpenGL. Conveniently enough the QRhi feature flags are
readily available.

This should prevent errors such as:

MTLValidateFeatureSupport:3901: failed assertion `Base Vertex Instance
Drawing is not supported on this device'

on the iOS Simulator. It is not clear since which version or SDK this
became a fatal problem, but the base vertex/instance support is indeed
an optional feature according to the Metal Feature set tables, so not
calling the drawIndexedPrimitives variant taking baseVertex and
baseInstance when the reported iOS GPU family is too low is the right
thing to do regardless.

Fixes: QTBUG-95795
Change-Id: I47c54a77a66a0410b86b8d4e5a1863dc730490f4
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
(cherry picked from commit 213755a86622ae8b3ed3d7ad34a6aecd051b2b03)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Laszlo Agocs 2021-08-13 18:13:43 +02:00 committed by Qt Cherry-pick Bot
parent c9c545eb4c
commit 88373a370a
3 changed files with 34 additions and 14 deletions

View File

@ -574,13 +574,18 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
require the point size to be set in the shader explicitly whenever drawing require the point size to be set in the shader explicitly whenever drawing
points, even when the size is 1, as they do not automatically default to 1. points, even when the size is 1, as they do not automatically default to 1.
\value BaseVertex Indicates that \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()} \value BaseVertex Indicates that
supports the \c vertexOffset argument. When reported as not supported, the \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()} supports the \c
vertexOffset value in an indexed draw is ignored. vertexOffset argument. When reported as not supported, the vertexOffset
value in an indexed draw is ignored. In practice this feature will be
unsupported with OpenGL and OpenGL ES versions lower than 3.2, and with
Metal on older iOS devices, including the iOS Simulator.
\value BaseInstance Indicates that instanced draw commands support the \c \value BaseInstance Indicates that instanced draw commands support the \c
firstInstance argument. When reported as not supported, the firstInstance firstInstance argument. When reported as not supported, the firstInstance
value is ignored and the instance ID starts from 0. value is ignored and the instance ID starts from 0. In practice this feature
will be unsupported with OpenGL, and with Metal on older iOS devices,
including the iOS Simulator.
\value TriangleFanTopology Indicates that QRhiGraphicsPipeline::setTopology() \value TriangleFanTopology Indicates that QRhiGraphicsPipeline::setTopology()
supports QRhiGraphicsPipeline::TriangleFan. supports QRhiGraphicsPipeline::TriangleFan.

View File

@ -421,11 +421,13 @@ bool QRhiMetal::create(QRhi::Flags flags)
#if defined(Q_OS_MACOS) #if defined(Q_OS_MACOS)
caps.maxTextureSize = 16384; caps.maxTextureSize = 16384;
caps.baseVertexAndInstance = true;
#elif defined(Q_OS_TVOS) #elif defined(Q_OS_TVOS)
if ([d->dev supportsFeatureSet: MTLFeatureSet(30003)]) // MTLFeatureSet_tvOS_GPUFamily2_v1 if ([d->dev supportsFeatureSet: MTLFeatureSet(30003)]) // MTLFeatureSet_tvOS_GPUFamily2_v1
caps.maxTextureSize = 16384; caps.maxTextureSize = 16384;
else else
caps.maxTextureSize = 8192; caps.maxTextureSize = 8192;
caps.baseVertexAndInstance = false;
#elif defined(Q_OS_IOS) #elif defined(Q_OS_IOS)
// welcome to feature set hell // welcome to feature set hell
if ([d->dev supportsFeatureSet: MTLFeatureSet(16)] // MTLFeatureSet_iOS_GPUFamily5_v1 if ([d->dev supportsFeatureSet: MTLFeatureSet(16)] // MTLFeatureSet_iOS_GPUFamily5_v1
@ -433,12 +435,15 @@ bool QRhiMetal::create(QRhi::Flags flags)
|| [d->dev supportsFeatureSet: MTLFeatureSet(4)]) // MTLFeatureSet_iOS_GPUFamily3_v1 || [d->dev supportsFeatureSet: MTLFeatureSet(4)]) // MTLFeatureSet_iOS_GPUFamily3_v1
{ {
caps.maxTextureSize = 16384; caps.maxTextureSize = 16384;
caps.baseVertexAndInstance = true;
} else if ([d->dev supportsFeatureSet: MTLFeatureSet(3)] // MTLFeatureSet_iOS_GPUFamily2_v2 } else if ([d->dev supportsFeatureSet: MTLFeatureSet(3)] // MTLFeatureSet_iOS_GPUFamily2_v2
|| [d->dev supportsFeatureSet: MTLFeatureSet(2)]) // MTLFeatureSet_iOS_GPUFamily1_v2 || [d->dev supportsFeatureSet: MTLFeatureSet(2)]) // MTLFeatureSet_iOS_GPUFamily1_v2
{ {
caps.maxTextureSize = 8192; caps.maxTextureSize = 8192;
caps.baseVertexAndInstance = false;
} else { } else {
caps.maxTextureSize = 4096; caps.maxTextureSize = 4096;
caps.baseVertexAndInstance = false;
} }
#endif #endif
@ -582,9 +587,9 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
case QRhi::VertexShaderPointSize: case QRhi::VertexShaderPointSize:
return true; return true;
case QRhi::BaseVertex: case QRhi::BaseVertex:
return true; return caps.baseVertexAndInstance;
case QRhi::BaseInstance: case QRhi::BaseInstance:
return true; return caps.baseVertexAndInstance;
case QRhi::TriangleFanTopology: case QRhi::TriangleFanTopology:
return false; return false;
case QRhi::ReadBackNonUniformBuffer: case QRhi::ReadBackNonUniformBuffer:
@ -1333,14 +1338,23 @@ void QRhiMetal::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
QMetalBuffer *ibufD = QRHI_RES(QMetalBuffer, cbD->currentIndexBuffer); QMetalBuffer *ibufD = QRHI_RES(QMetalBuffer, cbD->currentIndexBuffer);
id<MTLBuffer> mtlbuf = ibufD->d->buf[ibufD->d->slotted ? currentFrameSlot : 0]; id<MTLBuffer> mtlbuf = ibufD->d->buf[ibufD->d->slotted ? currentFrameSlot : 0];
[cbD->d->currentRenderPassEncoder drawIndexedPrimitives: QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->d->primitiveType if (caps.baseVertexAndInstance) {
indexCount: indexCount [cbD->d->currentRenderPassEncoder drawIndexedPrimitives: QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->d->primitiveType
indexType: cbD->currentIndexFormat == QRhiCommandBuffer::IndexUInt16 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32 indexCount: indexCount
indexBuffer: mtlbuf indexType: cbD->currentIndexFormat == QRhiCommandBuffer::IndexUInt16 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
indexBufferOffset: indexOffset indexBuffer: mtlbuf
instanceCount: instanceCount indexBufferOffset: indexOffset
baseVertex: vertexOffset instanceCount: instanceCount
baseInstance: firstInstance]; baseVertex: vertexOffset
baseInstance: firstInstance];
} else {
[cbD->d->currentRenderPassEncoder drawIndexedPrimitives: QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->d->primitiveType
indexCount: indexCount
indexType: cbD->currentIndexFormat == QRhiCommandBuffer::IndexUInt16 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
indexBuffer: mtlbuf
indexBufferOffset: indexOffset
instanceCount: instanceCount];
}
} }
void QRhiMetal::debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) void QRhiMetal::debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name)

View File

@ -475,6 +475,7 @@ public:
struct { struct {
int maxTextureSize = 4096; int maxTextureSize = 4096;
bool baseVertexAndInstance = true;
} caps; } caps;
QRhiMetalData *d = nullptr; QRhiMetalData *d = nullptr;