macOS: Experimental Vulkan support via MoltenVK
Add support for QSurface::VulkanSurface and QVulkanWindow. Usage: 1) Build MoltenVK according to instructions 2) Configure Qt: ./configure -I /path/to/MoltenVK/Package/Release/MoltenVK/include 3) export QT_VULKAN_LIB=/path/to/MoltenVK/Package/Release/MoltenVK/macOS/libMoltenVK. Implement support for QSurface::VulkanSurface by enabling layer mode for QNSView and then creating a CAMetalLayer, which the MoltenVK translation layer can run on. MoltenVK provides an implementation of the Vulcan API, which means that the platform integration is similar to other platforms: implement a QCocoaVulkanInstance where we pass the QNSView instance to the vkCreateMacOSSurfaceMVK Vulkan surface constructor function. Using Vulkan directly without QVulkanWindow is possible, but not tested. We currently load libMoltenVK at run-time and use the existing QT_VULKAN_LIB environment variable to set its path. For deployment purposes it would be better to link against MoltenVK.frameworkm, but this Task-number: QTBUG-66966 Change-Id: I04ec6289c40b199dca9fed32902b5d2ad4e9c030 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
parent
0b815aa2f8
commit
60457e6cd0
@ -11,4 +11,6 @@ device.dir_affix = $${device.sdk}
|
|||||||
device.CONFIG = $${device.sdk}
|
device.CONFIG = $${device.sdk}
|
||||||
device.deployment_identifier = $${device.sdk}
|
device.deployment_identifier = $${device.sdk}
|
||||||
|
|
||||||
|
QMAKE_LIBS_VULKAN =
|
||||||
|
|
||||||
include(mac.conf)
|
include(mac.conf)
|
||||||
|
@ -72,10 +72,14 @@ HEADERS += qcocoaintegration.h \
|
|||||||
|
|
||||||
qtConfig(opengl.*) {
|
qtConfig(opengl.*) {
|
||||||
SOURCES += qcocoaglcontext.mm
|
SOURCES += qcocoaglcontext.mm
|
||||||
|
|
||||||
HEADERS += qcocoaglcontext.h
|
HEADERS += qcocoaglcontext.h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qtConfig(vulkan) {
|
||||||
|
SOURCES += qcocoavulkaninstance.mm
|
||||||
|
HEADERS += qcocoavulkaninstance.h
|
||||||
|
}
|
||||||
|
|
||||||
RESOURCES += qcocoaresources.qrc
|
RESOURCES += qcocoaresources.qrc
|
||||||
|
|
||||||
LIBS += -framework AppKit -framework CoreServices -framework Carbon -framework IOKit -framework QuartzCore -framework Metal -lcups
|
LIBS += -framework AppKit -framework CoreServices -framework Carbon -framework IOKit -framework QuartzCore -framework Metal -lcups
|
||||||
@ -85,6 +89,8 @@ QT += \
|
|||||||
accessibility_support-private clipboard_support-private theme_support-private \
|
accessibility_support-private clipboard_support-private theme_support-private \
|
||||||
fontdatabase_support-private graphics_support-private
|
fontdatabase_support-private graphics_support-private
|
||||||
|
|
||||||
|
qtConfig(vulkan): QT += vulkan_support-private
|
||||||
|
|
||||||
CONFIG += no_app_extension_api_only
|
CONFIG += no_app_extension_api_only
|
||||||
|
|
||||||
qtHaveModule(widgets) {
|
qtHaveModule(widgets) {
|
||||||
|
@ -51,6 +51,9 @@
|
|||||||
#include "qcocoadrag.h"
|
#include "qcocoadrag.h"
|
||||||
#include "qcocoaservices.h"
|
#include "qcocoaservices.h"
|
||||||
#include "qcocoakeymapper.h"
|
#include "qcocoakeymapper.h"
|
||||||
|
#if QT_CONFIG(vulkan)
|
||||||
|
#include "qcocoavulkaninstance.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <QtCore/QScopedPointer>
|
#include <QtCore/QScopedPointer>
|
||||||
#include <qpa/qplatformintegration.h>
|
#include <qpa/qplatformintegration.h>
|
||||||
@ -86,6 +89,11 @@ public:
|
|||||||
|
|
||||||
QAbstractEventDispatcher *createEventDispatcher() const override;
|
QAbstractEventDispatcher *createEventDispatcher() const override;
|
||||||
|
|
||||||
|
#if QT_CONFIG(vulkan)
|
||||||
|
QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override;
|
||||||
|
QCocoaVulkanInstance *getCocoaVulkanInstance() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
QCoreTextFontDatabase *fontDatabase() const override;
|
QCoreTextFontDatabase *fontDatabase() const override;
|
||||||
QCocoaNativeInterface *nativeInterface() const override;
|
QCocoaNativeInterface *nativeInterface() const override;
|
||||||
QPlatformInputContext *inputContext() const override;
|
QPlatformInputContext *inputContext() const override;
|
||||||
@ -144,6 +152,9 @@ private:
|
|||||||
QScopedPointer<QCocoaServices> mServices;
|
QScopedPointer<QCocoaServices> mServices;
|
||||||
QScopedPointer<QCocoaKeyMapper> mKeyboardMapper;
|
QScopedPointer<QCocoaKeyMapper> mKeyboardMapper;
|
||||||
|
|
||||||
|
#if QT_CONFIG(vulkan)
|
||||||
|
mutable QCocoaVulkanInstance *mCocoaVulkanInstance = nullptr;
|
||||||
|
#endif
|
||||||
QHash<QWindow *, NSToolbar *> mToolbars;
|
QHash<QWindow *, NSToolbar *> mToolbars;
|
||||||
QList<QCocoaWindow *> m_popupWindowStack;
|
QList<QCocoaWindow *> m_popupWindowStack;
|
||||||
};
|
};
|
||||||
|
@ -379,6 +379,19 @@ QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const
|
|||||||
return new QCocoaEventDispatcher;
|
return new QCocoaEventDispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if QT_CONFIG(vulkan)
|
||||||
|
QPlatformVulkanInstance *QCocoaIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
|
||||||
|
{
|
||||||
|
mCocoaVulkanInstance = new QCocoaVulkanInstance(instance);
|
||||||
|
return mCocoaVulkanInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCocoaVulkanInstance *QCocoaIntegration::getCocoaVulkanInstance() const
|
||||||
|
{
|
||||||
|
return mCocoaVulkanInstance;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
QCoreTextFontDatabase *QCocoaIntegration::fontDatabase() const
|
QCoreTextFontDatabase *QCocoaIntegration::fontDatabase() const
|
||||||
{
|
{
|
||||||
return mFontDb.data();
|
return mFontDb.data();
|
||||||
|
@ -71,6 +71,10 @@
|
|||||||
|
|
||||||
#include <AppKit/AppKit.h>
|
#include <AppKit/AppKit.h>
|
||||||
|
|
||||||
|
#if QT_CONFIG(vulkan)
|
||||||
|
#include <MoltenVK/mvk_vulkan.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
QCocoaNativeInterface::QCocoaNativeInterface()
|
QCocoaNativeInterface::QCocoaNativeInterface()
|
||||||
@ -104,6 +108,11 @@ void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceS
|
|||||||
#endif
|
#endif
|
||||||
} else if (resourceString == "nswindow") {
|
} else if (resourceString == "nswindow") {
|
||||||
return static_cast<QCocoaWindow *>(window->handle())->nativeWindow();
|
return static_cast<QCocoaWindow *>(window->handle())->nativeWindow();
|
||||||
|
#if QT_CONFIG(vulkan)
|
||||||
|
} else if (resourceString == "vkSurface") {
|
||||||
|
if (QVulkanInstance *instance = window->vulkanInstance())
|
||||||
|
return static_cast<QCocoaVulkanInstance *>(instance->handle())->createSurface(window);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
74
src/plugins/platforms/cocoa/qcocoavulkaninstance.h
Normal file
74
src/plugins/platforms/cocoa/qcocoavulkaninstance.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2018 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of plugins of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 3 requirements
|
||||||
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 2.0 or (at your option) the GNU General
|
||||||
|
** Public license version 3 or any later version approved by the KDE Free
|
||||||
|
** Qt Foundation. The licenses are as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||||
|
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QCOCOAVULKANINSTANCE_H
|
||||||
|
#define QCOCOAVULKANINSTANCE_H
|
||||||
|
|
||||||
|
#include <QtCore/QLibrary>
|
||||||
|
#include <QtCore/QHash>
|
||||||
|
#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h>
|
||||||
|
|
||||||
|
#include <AppKit/AppKit.h>
|
||||||
|
|
||||||
|
#include <MoltenVK/mvk_vulkan.h>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
class QCocoaVulkanInstance : public QBasicPlatformVulkanInstance
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QCocoaVulkanInstance(QVulkanInstance *instance);
|
||||||
|
~QCocoaVulkanInstance();
|
||||||
|
|
||||||
|
void createOrAdoptInstance() override;
|
||||||
|
|
||||||
|
VkSurfaceKHR *createSurface(QWindow *window);
|
||||||
|
VkSurfaceKHR createSurface(NSView *view);
|
||||||
|
void destroySurface(VkSurfaceKHR surface);
|
||||||
|
private:
|
||||||
|
QVulkanInstance *m_instance = nullptr;
|
||||||
|
QLibrary m_lib;
|
||||||
|
VkSurfaceKHR m_nullSurface = nullptr;
|
||||||
|
PFN_vkCreateMacOSSurfaceMVK m_createSurface = nullptr;
|
||||||
|
PFN_vkDestroySurfaceKHR m_destroySurface = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // QXCBVULKANINSTANCE_H
|
119
src/plugins/platforms/cocoa/qcocoavulkaninstance.mm
Normal file
119
src/plugins/platforms/cocoa/qcocoavulkaninstance.mm
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2018 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of plugins of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 3 requirements
|
||||||
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 2.0 or (at your option) the GNU General
|
||||||
|
** Public license version 3 or any later version approved by the KDE Free
|
||||||
|
** Qt Foundation. The licenses are as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||||
|
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "qcocoavulkaninstance.h"
|
||||||
|
#include "qcocoawindow.h"
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
QCocoaVulkanInstance::QCocoaVulkanInstance(QVulkanInstance *instance)
|
||||||
|
: m_instance(instance)
|
||||||
|
{
|
||||||
|
if (qEnvironmentVariableIsSet("QT_VULKAN_LIB"))
|
||||||
|
m_lib.setFileName(QString::fromUtf8(qgetenv("QT_VULKAN_LIB")));
|
||||||
|
else
|
||||||
|
m_lib.setFileName(QStringLiteral("vulkan"));
|
||||||
|
|
||||||
|
if (!m_lib.load()) {
|
||||||
|
qWarning("Failed to load %s: %s", qPrintable(m_lib.fileName()), qPrintable(m_lib.errorString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
init(&m_lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCocoaVulkanInstance::~QCocoaVulkanInstance()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCocoaVulkanInstance::createOrAdoptInstance()
|
||||||
|
{
|
||||||
|
initInstance(m_instance, QByteArrayList());
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSurfaceKHR *QCocoaVulkanInstance::createSurface(QWindow *window)
|
||||||
|
{
|
||||||
|
QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
|
||||||
|
if (cocoaWindow->m_vulkanSurface)
|
||||||
|
destroySurface(cocoaWindow->m_vulkanSurface);
|
||||||
|
cocoaWindow->m_vulkanSurface = createSurface(cocoaWindow->m_view);
|
||||||
|
return &cocoaWindow->m_vulkanSurface;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSurfaceKHR QCocoaVulkanInstance::createSurface(NSView *view)
|
||||||
|
{
|
||||||
|
if (!m_createSurface) {
|
||||||
|
m_createSurface = reinterpret_cast<PFN_vkCreateMacOSSurfaceMVK>(
|
||||||
|
m_vkGetInstanceProcAddr(m_vkInst, "vkCreateMacOSSurfaceMVK"));
|
||||||
|
}
|
||||||
|
if (!m_createSurface) {
|
||||||
|
qWarning("Failed to find vkCreateMacOSSurfaceMVK");
|
||||||
|
return m_nullSurface;
|
||||||
|
}
|
||||||
|
if (!m_destroySurface) {
|
||||||
|
m_destroySurface = reinterpret_cast<PFN_vkDestroySurfaceKHR>(
|
||||||
|
m_vkGetInstanceProcAddr(m_vkInst, "vkDestroySurfaceKHR"));
|
||||||
|
}
|
||||||
|
if (!m_destroySurface) {
|
||||||
|
qWarning("Failed to find vkDestroySurfaceKHR");
|
||||||
|
return m_nullSurface;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkMacOSSurfaceCreateInfoMVK surfaceInfo;
|
||||||
|
surfaceInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
|
||||||
|
surfaceInfo.pNext = nullptr;
|
||||||
|
surfaceInfo.flags = 0;
|
||||||
|
surfaceInfo.pView = view;
|
||||||
|
|
||||||
|
VkSurfaceKHR surface = nullptr;
|
||||||
|
VkResult err = m_createSurface(m_vkInst, &surfaceInfo, nullptr, &surface);
|
||||||
|
if (err != VK_SUCCESS)
|
||||||
|
qWarning("Failed to create Vulkan surface: %d", err);
|
||||||
|
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCocoaVulkanInstance::destroySurface(VkSurfaceKHR surface)
|
||||||
|
{
|
||||||
|
if (m_destroySurface && surface)
|
||||||
|
m_destroySurface(m_vkInst, surface, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
@ -53,6 +53,10 @@
|
|||||||
#include "qnswindow.h"
|
#include "qnswindow.h"
|
||||||
#include "qt_mac_p.h"
|
#include "qt_mac_p.h"
|
||||||
|
|
||||||
|
#if QT_CONFIG(vulkan)
|
||||||
|
#include <MoltenVK/mvk_vulkan.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG_STREAM
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
@ -281,6 +285,10 @@ public: // for QNSView
|
|||||||
};
|
};
|
||||||
QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower
|
QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower
|
||||||
QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false)
|
QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false)
|
||||||
|
|
||||||
|
#if QT_CONFIG(vulkan)
|
||||||
|
VkSurfaceKHR m_vulkanSurface = nullptr;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG_STREAM
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
|
@ -222,10 +222,16 @@ QCocoaWindow::~QCocoaWindow()
|
|||||||
if (!isForeignWindow())
|
if (!isForeignWindow())
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:m_view];
|
[[NSNotificationCenter defaultCenter] removeObserver:m_view];
|
||||||
|
|
||||||
// While it is unlikely that this window will be in the popup stack
|
if (QCocoaIntegration *cocoaIntegration = QCocoaIntegration::instance()) {
|
||||||
// during deletetion we clear any pointers here to make sure.
|
// While it is unlikely that this window will be in the popup stack
|
||||||
if (QCocoaIntegration::instance()) {
|
// during deletetion we clear any pointers here to make sure.
|
||||||
QCocoaIntegration::instance()->popupWindowStack()->removeAll(this);
|
cocoaIntegration->popupWindowStack()->removeAll(this);
|
||||||
|
|
||||||
|
#if QT_CONFIG(vulkan)
|
||||||
|
auto vulcanInstance = cocoaIntegration->getCocoaVulkanInstance();
|
||||||
|
if (vulcanInstance)
|
||||||
|
vulcanInstance->destroySurface(m_vulkanSurface);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
[m_view release];
|
[m_view release];
|
||||||
|
@ -141,13 +141,19 @@
|
|||||||
// on and off is not a supported use-case, so this code is effectively
|
// on and off is not a supported use-case, so this code is effectively
|
||||||
// returning a constant for the lifetime of our QSNSView, which means
|
// returning a constant for the lifetime of our QSNSView, which means
|
||||||
// we don't care about emitting KVO signals for @"wantsLayer".
|
// we don't care about emitting KVO signals for @"wantsLayer".
|
||||||
return qt_mac_resolveOption(false, m_platformWindow->window(),
|
bool layerRequested = qt_mac_resolveOption(false, m_platformWindow->window(),
|
||||||
"_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER");
|
"_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER");
|
||||||
|
|
||||||
|
// Support Vulkan via MoltenVK, which requires a Metal layer
|
||||||
|
bool layerForVulkan = (m_platformWindow->window()->surfaceType() == QWindow::VulkanSurface);
|
||||||
|
|
||||||
|
return layerRequested || layerForVulkan;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CALayer *)makeBackingLayer
|
- (CALayer *)makeBackingLayer
|
||||||
{
|
{
|
||||||
bool makeMetalLayer = false; // TODO: Add/implement enabling API
|
// Support Vulkan via MoltenVK, which requires a Metal layer
|
||||||
|
bool makeMetalLayer = (m_platformWindow->window()->surfaceType() == QWindow::VulkanSurface);
|
||||||
if (makeMetalLayer) {
|
if (makeMetalLayer) {
|
||||||
// Check if Metal is supported. If it isn't then it's most likely
|
// Check if Metal is supported. If it isn't then it's most likely
|
||||||
// too late at this point and the QWindow will be non-functional,
|
// too late at this point and the QWindow will be non-functional,
|
||||||
|
Loading…
Reference in New Issue
Block a user