rhi: Add the long-pending probe() helper, with backing for Metal

There is a TODO for this in Qt Quick from the 6.0 times. To decide
upfront if Metal can be expected to function, or if a fallback to
OpenGL needs to be triggered (especially important with macOS virtual
machines, where, unlike any real macOS system, Metal may not be
present at all), the scenegraph calls create() and then drops the
result. The idea to make this less wasteful was back then to add a
dedicated probing function which can, possibly, perform the checks in
a more lightweight manner than full initialization. Implement this
now, focusing on Metal.

Brought to attention by QTBUG-100441: printing warnings about not
having an MTLDevice is confusing in a Metal-less macOS VM, because it
is not an actual error, only part of the probing at scenegraph
initialization. We can now avoid printing confusing warnings there.

Change-Id: Ie52c36af9224bedc3f5e4c23edb486d961c9f216
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
bb10
Laszlo Agocs 2022-02-04 22:05:35 +01:00
parent 1f93ff529b
commit 178c1a6243
5 changed files with 64 additions and 0 deletions

View File

@ -5288,6 +5288,20 @@ QRhi::~QRhi()
subclasses of QRhiInitParams, such as, QRhiVulkanInitParams,
QRhiMetalInitParams, QRhiD3D11InitParams, QRhiGles2InitParams. See these
classes for examples on creating a QRhi.
QRhi by design does not implement any fallback logic: if the specified API
cannot be initialized, create() will fail, with warnings printed on the
debug output by the backends. The clients of QRhi, for example Qt Quick,
may however provide additional logic that allow falling back to an API
different than what was requested, depending on the platform. If the
intention is just to test if initialization would succeed when calling
create() at later point, it is preferable to use probe() instead of
create(), because with some backends probing can be implemented in a more
lightweight manner as opposed to create(), which performs full
initialization of the infrastructure and is wasteful if that QRhi instance
is then thrown immediately away.
\sa probe()
*/
QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRhiNativeHandles *importDevice)
{
@ -5357,6 +5371,40 @@ QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRh
return nullptr;
}
/*!
\return true if create() can be expected to succeed when called the given
\a impl and \a params.
For some backends this is equivalent to calling create(), checking its
return value, and then destroying the resulting QRhi.
For others, in particular with Metal, there may be a specific probing
implementation, which allows testing in a more lightweight manner without
polluting the debug output with warnings upon failures.
\sa create()
*/
bool QRhi::probe(QRhi::Implementation impl, QRhiInitParams *params)
{
bool ok = false;
// The only place currently where this makes sense is Metal, where the API
// is simple enough so that a special probing function - doing nothing but
// a MTLCreateSystemDefaultDevice - is reasonable. Elsewhere, just call
// create() and then drop the result.
if (impl == Metal) {
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
ok = QRhiMetal::probe(static_cast<QRhiMetalInitParams *>(params));
#endif
} else {
QRhi *rhi = create(impl, params);
ok = rhi != nullptr;
delete rhi;
}
return ok;
}
/*!
\return the backend type for this QRhi.
*/

View File

@ -1711,6 +1711,7 @@ public:
QRhiInitParams *params,
Flags flags = {},
QRhiNativeHandles *importDevice = nullptr);
static bool probe(Implementation impl, QRhiInitParams *params);
Implementation backend() const;
const char *backendName() const;

View File

@ -363,6 +363,17 @@ inline Int aligned(Int v, Int byteAlign)
return (v + byteAlign - 1) & ~(byteAlign - 1);
}
bool QRhiMetal::probe(QRhiMetalInitParams *params)
{
Q_UNUSED(params);
id<MTLDevice> dev = MTLCreateSystemDefaultDevice();
if (dev) {
[dev release];
return true;
}
return false;
}
bool QRhiMetal::create(QRhi::Flags flags)
{
Q_UNUSED(flags);

View File

@ -351,6 +351,8 @@ public:
QRhiMetal(QRhiMetalInitParams *params, QRhiMetalNativeHandles *importDevice = nullptr);
~QRhiMetal();
static bool probe(QRhiMetalInitParams *params);
bool create(QRhi::Flags flags) override;
void destroy() override;

View File

@ -271,6 +271,8 @@ void tst_QRhi::create()
QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr));
if (rhi) {
QVERIFY(QRhi::probe(impl, initParams));
qDebug() << rhi->driverInfo();
QCOMPARE(rhi->backend(), impl);