Enable QRhi Metal backend on iOS

While we are at it, remove the Border and MirrorOnce wrap modes that have
not been supported on OpenGL, because they are unsupported with Metal+iOS
as well.

Task-number: QTBUG-78580
Change-Id: I0db94b9d3a6125b3bb5d7b1db5d02a42cd94d2c2
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Laszlo Agocs 2019-11-12 17:13:58 +01:00
parent ce7447d88c
commit f3c37c839c
17 changed files with 119 additions and 60 deletions

View File

@ -48,8 +48,7 @@
#ifdef Q_OS_WIN
#include "qrhid3d11_p_p.h"
#endif
//#ifdef Q_OS_DARWIN
#ifdef Q_OS_MACOS
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#include "qrhimetal_p_p.h"
#endif
@ -2253,9 +2252,7 @@ bool QRhiTexture::buildFrom(const QRhiNativeHandles *src)
\value Repeat
\value ClampToEdge
\value Border
\value Mirror
\value MirrorOnce
*/
/*!
@ -4049,8 +4046,7 @@ QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRh
break;
#endif
case Metal:
//#ifdef Q_OS_DARWIN
#ifdef Q_OS_MACOS
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
r->d = new QRhiMetal(static_cast<QRhiMetalInitParams *>(params),
static_cast<QRhiMetalNativeHandles *>(importDevice));
break;

View File

@ -812,9 +812,7 @@ public:
enum AddressMode {
Repeat,
ClampToEdge,
Border,
Mirror,
MirrorOnce
};
enum CompareOp {

View File

@ -2862,12 +2862,8 @@ static inline D3D11_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMo
return D3D11_TEXTURE_ADDRESS_WRAP;
case QRhiSampler::ClampToEdge:
return D3D11_TEXTURE_ADDRESS_CLAMP;
case QRhiSampler::Border:
return D3D11_TEXTURE_ADDRESS_BORDER;
case QRhiSampler::Mirror:
return D3D11_TEXTURE_ADDRESS_MIRROR;
case QRhiSampler::MirrorOnce:
return D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
default:
Q_UNREACHABLE();
return D3D11_TEXTURE_ADDRESS_CLAMP;

View File

@ -1785,11 +1785,6 @@ static inline GLenum toGlWrapMode(QRhiSampler::AddressMode m)
return GL_CLAMP_TO_EDGE;
case QRhiSampler::Mirror:
return GL_MIRRORED_REPEAT;
case QRhiSampler::MirrorOnce:
Q_FALLTHROUGH();
case QRhiSampler::Border:
qWarning("Unsupported wrap mode %d", m);
return GL_CLAMP_TO_EDGE;
default:
Q_UNREACHABLE();
return GL_CLAMP_TO_EDGE;

View File

@ -41,6 +41,8 @@
#ifdef Q_OS_MACOS
#include <AppKit/AppKit.h>
#else
#include <UIKit/UIKit.h>
#endif
#include <Metal/Metal.h>
@ -318,7 +320,13 @@ struct QMetalComputePipelineData
struct QMetalSwapChainData
{
// The iOS simulator's headers mark CAMetalLayer as iOS 13.0+ only.
// (for real device SDKs it is 8.0+)
#ifdef TARGET_IPHONE_SIMULATOR
API_AVAILABLE(ios(13.0)) CAMetalLayer *layer = nullptr;
#else
CAMetalLayer *layer = nullptr;
#endif
id<CAMetalDrawable> curDrawable;
dispatch_semaphore_t sem[QMTL_FRAMES_IN_FLIGHT];
MTLRenderPassDescriptor *rp = nullptr;
@ -1763,8 +1771,10 @@ void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
if (changeEnd == -1 || u.offset + u.data.size() > changeEnd)
changeEnd = u.offset + u.data.size();
}
#ifdef Q_OS_MACOS
if (changeBegin >= 0 && bufD->d->managed)
[bufD->d->buf[idx] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))];
#endif
bufD->d->pendingUpdates[idx].clear();
}
@ -1798,8 +1808,12 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
if (color0.needsDrawableForTex || color0.needsDrawableForResolveTex) {
Q_ASSERT(currentSwapChain);
QMetalSwapChain *swapChainD = QRHI_RES(QMetalSwapChain, currentSwapChain);
if (!swapChainD->d->curDrawable)
swapChainD->d->curDrawable = [swapChainD->d->layer nextDrawable];
if (!swapChainD->d->curDrawable) {
#ifdef TARGET_IPHONE_SIMULATOR
if (@available(ios 13.0, *))
#endif
swapChainD->d->curDrawable = [swapChainD->d->layer nextDrawable];
}
if (!swapChainD->d->curDrawable) {
qWarning("No drawable");
return;
@ -2170,12 +2184,13 @@ bool QMetalRenderBuffer::build()
case DepthStencil:
#ifdef Q_OS_MACOS
desc.storageMode = MTLStorageModePrivate;
#else
desc.storageMode = MTLResourceStorageModeMemoryless;
transientBacking = true;
#endif
d->format = rhiD->d->dev.depth24Stencil8PixelFormatSupported
? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8;
#else
desc.storageMode = MTLStorageModeMemoryless;
transientBacking = true;
d->format = MTLPixelFormatDepth32Float_Stencil8;
#endif
desc.pixelFormat = d->format;
break;
case Color:
@ -2569,12 +2584,8 @@ static inline MTLSamplerAddressMode toMetalAddressMode(QRhiSampler::AddressMode
return MTLSamplerAddressModeRepeat;
case QRhiSampler::ClampToEdge:
return MTLSamplerAddressModeClampToEdge;
case QRhiSampler::Border:
return MTLSamplerAddressModeClampToBorderColor;
case QRhiSampler::Mirror:
return MTLSamplerAddressModeMirrorRepeat;
case QRhiSampler::MirrorOnce:
return MTLSamplerAddressModeMirrorClampToEdge;
default:
Q_UNREACHABLE();
return MTLSamplerAddressModeClampToEdge;
@ -3311,7 +3322,11 @@ bool QMetalGraphicsPipeline::build()
// validation blows up otherwise.
MTLPixelFormat fmt = MTLPixelFormat(rpD->dsFormat);
rpDesc.depthAttachmentPixelFormat = fmt;
#ifdef Q_OS_MACOS
if (fmt != MTLPixelFormatDepth16Unorm && fmt != MTLPixelFormatDepth32Float)
#else
if (fmt != MTLPixelFormatDepth32Float)
#endif
rpDesc.stencilAttachmentPixelFormat = fmt;
}
@ -3528,6 +3543,10 @@ QMetalSwapChain::~QMetalSwapChain()
void QMetalSwapChain::release()
{
#ifdef TARGET_IPHONE_SIMULATOR
if (@available(ios 13.0, *)) {
#endif
if (!d->layer)
return;
@ -3556,6 +3575,10 @@ void QMetalSwapChain::release()
QRHI_PROF_F(releaseSwapChain(this));
rhiD->unregisterResource(this);
#ifdef TARGET_IPHONE_SIMULATOR
}
#endif
}
QRhiCommandBuffer *QMetalSwapChain::currentFrameCommandBuffer()
@ -3578,16 +3601,20 @@ QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
{
chooseFormats(); // ensure colorFormat and similar are filled out
QRHI_RES_RHI(QRhiMetal);
QMetalRenderPassDescriptor *rpD = new QMetalRenderPassDescriptor(m_rhi);
rpD->colorAttachmentCount = 1;
rpD->hasDepthStencil = m_depthStencil != nullptr;
rpD->colorFormat[0] = int(d->colorFormat);
#ifdef Q_OS_MACOS
// m_depthStencil may not be built yet so cannot rely on computed fields in it
QRHI_RES_RHI(QRhiMetal);
rpD->dsFormat = rhiD->d->dev.depth24Stencil8PixelFormatSupported
? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8;
#else
rpD->dsFormat = MTLPixelFormatDepth32Float_Stencil8;
#endif
return rpD;
}
@ -3603,6 +3630,10 @@ void QMetalSwapChain::chooseFormats()
bool QMetalSwapChain::buildOrResize()
{
#ifdef TARGET_IPHONE_SIMULATOR
if (@available(ios 13.0, *)) {
#endif
Q_ASSERT(m_window);
const bool needsRegistration = !window || window != m_window;
@ -3622,7 +3653,11 @@ bool QMetalSwapChain::buildOrResize()
return false;
}
#ifdef Q_OS_MACOS
NSView *view = reinterpret_cast<NSView *>(window->winId());
#else
UIView *view = reinterpret_cast<UIView *>(window->winId());
#endif
Q_ASSERT(view);
d->layer = static_cast<CAMetalLayer *>(view.layer);
Q_ASSERT(d->layer);
@ -3726,6 +3761,15 @@ bool QMetalSwapChain::buildOrResize()
rhiD->registerResource(this);
return true;
#ifdef TARGET_IPHONE_SIMULATOR
} else {
// Won't ever get here in a normal app because MTLDevice creation would
// fail too. Print a warning, just in case.
qWarning("No CAMetalLayer support in this version of the iOS Simulator");
return false;
}
#endif
}
QT_END_NAMESPACE

View File

@ -4617,12 +4617,8 @@ static inline VkSamplerAddressMode toVkAddressMode(QRhiSampler::AddressMode m)
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
case QRhiSampler::ClampToEdge:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
case QRhiSampler::Border:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
case QRhiSampler::Mirror:
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
case QRhiSampler::MirrorOnce:
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
default:
Q_UNREACHABLE();
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;

View File

@ -43,15 +43,15 @@ win32 {
LIBS += -ld3d11 -ldxgi -ldxguid
}
# darwin {
macos {
macos|ios {
HEADERS += \
rhi/qrhimetal_p.h \
rhi/qrhimetal_p_p.h
SOURCES += \
rhi/qrhimetal.mm
LIBS += -framework AppKit -framework Metal
macos: LIBS += -framework AppKit
LIBS += -framework Metal
}
include($$PWD/../../3rdparty/VulkanMemoryAllocator.pri)

View File

@ -51,6 +51,9 @@
#include <qpa/qplatformintegration.h>
#import <QuartzCore/CAEAGLLayer.h>
#ifdef Q_OS_IOS
#import <QuartzCore/CAMetalLayer.h>
#endif
#include <QtDebug>
@ -58,9 +61,15 @@ QT_BEGIN_NAMESPACE
QIOSWindow::QIOSWindow(QWindow *window)
: QPlatformWindow(window)
, m_view([[QUIView alloc] initWithQIOSWindow:this])
, m_windowLevel(0)
{
#ifdef Q_OS_IOS
if (window->surfaceType() == QSurface::MetalSurface)
m_view = [[QUIMetalView alloc] initWithQIOSWindow:this];
else
#endif
m_view = [[QUIView alloc] initWithQIOSWindow:this];
connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QIOSWindow::applicationStateChanged);
setParent(QPlatformWindow::parent());

View File

@ -70,3 +70,7 @@ QT_END_NAMESPACE
@property (nonatomic, readonly) UIEdgeInsets qt_safeAreaInsets;
@end
#ifdef Q_OS_IOS
@interface QUIMetalView : QUIView
@end
#endif

View File

@ -100,13 +100,15 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
- (instancetype)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
// Set up EAGL layer
CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer);
eaglLayer.opaque = TRUE;
eaglLayer.drawableProperties = @{
kEAGLDrawablePropertyRetainedBacking: @(YES),
kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
};
if ([self.layer isKindOfClass:[CAEAGLLayer class]]) {
// Set up EAGL layer
CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer);
eaglLayer.opaque = TRUE;
eaglLayer.drawableProperties = @{
kEAGLDrawablePropertyRetainedBacking: @(YES),
kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
};
}
if (isQtApplication())
self.hidden = YES;
@ -675,6 +677,25 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
@end
#ifdef Q_OS_IOS
@implementation QUIMetalView
+ (Class)layerClass
{
#ifdef TARGET_IPHONE_SIMULATOR
if (@available(ios 13.0, *))
#endif
return [CAMetalLayer class];
#ifdef TARGET_IPHONE_SIMULATOR
return nil;
#endif
}
@end
#endif
#ifndef QT_NO_ACCESSIBILITY
// Include category as an alternative to using -ObjC (Apple QA1490)
#include "quiview_accessibility.mm"

View File

@ -52,7 +52,7 @@
# define TST_D3D11
#endif
#ifdef Q_OS_DARWIN
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
# include <QtGui/private/qrhimetal_p.h>
# define TST_MTL
#endif

View File

@ -77,7 +77,7 @@
#include <QtGui/private/qrhid3d11_p.h>
#endif
#ifdef Q_OS_DARWIN
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#include <QtGui/private/qrhimetal_p.h>
#endif
@ -283,7 +283,7 @@ void Window::init()
}
#endif
#ifdef Q_OS_DARWIN
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
if (graphicsApi == Metal) {
QRhiMetalInitParams params;
m_r = QRhi::create(QRhi::Metal, &params);
@ -483,7 +483,7 @@ int main(int argc, char **argv)
// Defaults.
#if defined(Q_OS_WIN)
graphicsApi = D3D11;
#elif defined(Q_OS_DARWIN)
#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
graphicsApi = Metal;
#elif QT_CONFIG(vulkan)
graphicsApi = Vulkan;

View File

@ -78,7 +78,7 @@
#include <QtGui/private/qrhid3d11_p.h>
#endif
#ifdef Q_OS_DARWIN
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#include <QtGui/private/qrhimetal_p.h>
#endif
@ -148,7 +148,7 @@ void createRhi()
}
#endif
#ifdef Q_OS_DARWIN
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
if (graphicsApi == Metal) {
QRhiMetalInitParams params;
r.r = QRhi::create(QRhi::Metal, &params);
@ -530,7 +530,7 @@ int main(int argc, char **argv)
#if defined(Q_OS_WIN)
graphicsApi = D3D11;
#elif defined(Q_OS_DARWIN)
#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
graphicsApi = Metal;
#elif QT_CONFIG(vulkan)
graphicsApi = Vulkan;

View File

@ -82,7 +82,7 @@
#include <QtGui/private/qrhid3d11_p.h>
#endif
#ifdef Q_OS_DARWIN
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#include <QtGui/private/qrhimetal_p.h>
#endif
@ -376,7 +376,7 @@ void Renderer::createRhi()
}
#endif
#ifdef Q_OS_DARWIN
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
if (graphicsApi == Metal) {
QRhiMetalInitParams params;
r = QRhi::create(QRhi::Metal, &params, rhiFlags);
@ -730,7 +730,7 @@ int main(int argc, char **argv)
#if defined(Q_OS_WIN)
graphicsApi = D3D11;
#elif defined(Q_OS_DARWIN)
#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
graphicsApi = Metal;
#elif QT_CONFIG(vulkan)
graphicsApi = Vulkan;

View File

@ -72,7 +72,7 @@
#include <QtGui/private/qrhid3d11_p.h>
#endif
#ifdef Q_OS_DARWIN
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#include <QtGui/private/qrhimetal_p.h>
#endif
@ -130,7 +130,7 @@ int main(int argc, char **argv)
#if defined(Q_OS_WIN)
graphicsApi = D3D11;
#elif defined(Q_OS_DARWIN)
#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
graphicsApi = Metal;
#elif QT_CONFIG(vulkan)
graphicsApi = Vulkan;
@ -217,7 +217,7 @@ int main(int argc, char **argv)
}
#endif
#ifdef Q_OS_DARWIN
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
if (graphicsApi == Metal) {
QRhiMetalInitParams params;
r = QRhi::create(QRhi::Metal, &params);

View File

@ -78,7 +78,7 @@
#include <QtGui/private/qrhid3d11_p.h>
#endif
#ifdef Q_OS_DARWIN
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#include <QtGui/private/qrhimetal_p.h>
#endif
@ -292,7 +292,7 @@ void Window::init()
}
#endif
#ifdef Q_OS_DARWIN
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
if (graphicsApi == Metal) {
QRhiMetalInitParams params;
m_r = QRhi::create(QRhi::Metal, &params, rhiFlags);
@ -445,7 +445,7 @@ int main(int argc, char **argv)
// Defaults.
#if defined(Q_OS_WIN)
graphicsApi = D3D11;
#elif defined(Q_OS_DARWIN)
#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
graphicsApi = Metal;
#elif QT_CONFIG(vulkan)
graphicsApi = Vulkan;

View File

@ -239,7 +239,7 @@ void Window::customRender()
if (d.testStage == 6) {
const QRhiNativeHandles *h = d.tex->nativeHandles();
if (h) {
#ifdef Q_OS_DARWIN
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
if (graphicsApi == Metal) {
qDebug() << "Metal texture: " << static_cast<const QRhiMetalTextureNativeHandles *>(h)->texture;
// Now could cast to id<MTLTexture> and do something with