summaryrefslogtreecommitdiffstats
path: root/src/gui/rhi/qrhimetal.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/rhi/qrhimetal.mm')
-rw-r--r--src/gui/rhi/qrhimetal.mm502
1 files changed, 300 insertions, 202 deletions
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 07753c985c..0b1ab72c2c 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -138,6 +138,20 @@ QT_BEGIN_NAMESPACE
\l{QRhiCommandBuffer::endPass()}.
*/
+struct QMetalShader
+{
+ id<MTLLibrary> lib = nil;
+ id<MTLFunction> func = nil;
+ std::array<uint, 3> localSize;
+
+ void release() {
+ [lib release];
+ lib = nil;
+ [func release];
+ func = nil;
+ }
+};
+
struct QRhiMetalData
{
QRhiMetalData(QRhiImplementation *rhi) : ofr(rhi) { }
@@ -206,6 +220,8 @@ struct QRhiMetalData
API_AVAILABLE(macos(10.13), ios(11.0)) id<MTLCaptureScope> captureScope = nil;
static const int TEXBUF_ALIGN = 256; // probably not accurate
+
+ QHash<QRhiShaderStage, QMetalShader> shaderCache;
};
Q_DECLARE_TYPEINFO(QRhiMetalData::DeferredReleaseEntry, Q_MOVABLE_TYPE);
@@ -289,17 +305,14 @@ struct QMetalGraphicsPipelineData
MTLPrimitiveType primitiveType;
MTLWinding winding;
MTLCullMode cullMode;
- id<MTLLibrary> vsLib = nil;
- id<MTLFunction> vsFunc = nil;
- id<MTLLibrary> fsLib = nil;
- id<MTLFunction> fsFunc = nil;
+ QMetalShader vs;
+ QMetalShader fs;
};
struct QMetalComputePipelineData
{
id<MTLComputePipelineState> ps = nil;
- id<MTLLibrary> csLib = nil;
- id<MTLFunction> csFunc = nil;
+ QMetalShader cs;
MTLSize localSize;
};
@@ -339,7 +352,8 @@ QRhiMetal::~QRhiMetal()
delete d;
}
-static inline uint aligned(uint v, uint byteAlign)
+template <class Int>
+inline Int aligned(Int v, Int byteAlign)
{
return (v + byteAlign - 1) & ~(byteAlign - 1);
}
@@ -404,6 +418,10 @@ void QRhiMetal::destroy()
executeDeferredReleases(true);
finishActiveReadbacks(true);
+ for (QMetalShader &s : d->shaderCache)
+ s.release();
+ d->shaderCache.clear();
+
if (@available(macOS 10.13, iOS 11.0, *)) {
[d->captureScope release];
d->captureScope = nil;
@@ -565,9 +583,23 @@ void QRhiMetal::sendVMemStatsToProfiler()
// nothing to do here
}
-void QRhiMetal::makeThreadLocalNativeContextCurrent()
+bool QRhiMetal::makeThreadLocalNativeContextCurrent()
{
- // nothing to do here
+ // not applicable
+ return false;
+}
+
+void QRhiMetal::releaseCachedResources()
+{
+ for (QMetalShader &s : d->shaderCache)
+ s.release();
+
+ d->shaderCache.clear();
+}
+
+bool QRhiMetal::isDeviceLost() const
+{
+ return false;
}
QRhiRenderBuffer *QRhiMetal::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
@@ -630,7 +662,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
{
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.ubuf.buf);
id<MTLBuffer> mtlbuf = bufD->d->buf[bufD->d->slotted ? currentFrameSlot : 0];
- uint offset = b->u.ubuf.offset;
+ uint offset = uint(b->u.ubuf.offset);
for (int i = 0; i < dynamicOffsetCount; ++i) {
const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
if (dynOfs.first == b->binding) {
@@ -694,7 +726,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
{
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.sbuf.buf);
id<MTLBuffer> mtlbuf = bufD->d->buf[0];
- uint offset = b->u.sbuf.offset;
+ uint offset = uint(b->u.sbuf.offset);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
res[0].buffers.feed(b->binding, mtlbuf);
res[0].bufferOffsets.feed(b->binding, offset);
@@ -726,17 +758,17 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
case 0:
[cbD->d->currentRenderPassEncoder setVertexBuffers: bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
- withRange: NSMakeRange(bufferBatch.startBinding, bufferBatch.resources.count())];
+ withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
break;
case 1:
[cbD->d->currentRenderPassEncoder setFragmentBuffers: bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
- withRange: NSMakeRange(bufferBatch.startBinding, bufferBatch.resources.count())];
+ withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
break;
case 2:
[cbD->d->currentComputePassEncoder setBuffers: bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
- withRange: NSMakeRange(bufferBatch.startBinding, bufferBatch.resources.count())];
+ withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
break;
default:
Q_UNREACHABLE();
@@ -755,15 +787,15 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
switch (idx) {
case 0:
[cbD->d->currentRenderPassEncoder setVertexTextures: batch.resources.constData()
- withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
+ withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
case 1:
[cbD->d->currentRenderPassEncoder setFragmentTextures: batch.resources.constData()
- withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
+ withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
case 2:
[cbD->d->currentComputePassEncoder setTextures: batch.resources.constData()
- withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
+ withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
default:
Q_UNREACHABLE();
@@ -775,15 +807,15 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
switch (idx) {
case 0:
[cbD->d->currentRenderPassEncoder setVertexSamplerStates: batch.resources.constData()
- withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
+ withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
case 1:
[cbD->d->currentRenderPassEncoder setFragmentSamplerStates: batch.resources.constData()
- withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
+ withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
case 2:
[cbD->d->currentComputePassEncoder setSamplerStates: batch.resources.constData()
- withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
+ withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
default:
Q_UNREACHABLE();
@@ -981,7 +1013,7 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb,
[cbD->d->currentRenderPassEncoder setVertexBuffers:
bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
- withRange: NSMakeRange(firstVertexBinding + bufferBatch.startBinding, bufferBatch.resources.count())];
+ withRange: NSMakeRange(uint(firstVertexBinding) + bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
}
}
@@ -997,11 +1029,44 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb,
}
}
+QSize safeOutputSize(QRhiMetal *rhiD, QMetalCommandBuffer *cbD)
+{
+ QSize size = cbD->currentTarget->pixelSize();
+
+ // So now we have the issue that the texture (drawable) size may have
+ // changed again since swapchain buildOrResize() was called. This can
+ // happen for example when interactively resizing the window a lot in one
+ // go, and command buffer building happens on a dedicated thread (f.ex.
+ // using the threaded render loop of Qt Quick).
+ //
+ // This is only an issue when running in debug mode with XCode because Metal
+ // validation will fail when setting viewport or scissor with the real size
+ // being smaller than what we think it is. So query the drawable size right
+ // here, in debug mode at least.
+ //
+ // In addition, we have to take the smaller of the two widths and heights
+ // to be safe, apparently. In some cases validation seems to think that the
+ // "render pass width" (or height) is the old(?) value.
+
+#ifdef QT_DEBUG
+ if (cbD->currentTarget->resourceType() == QRhiResource::RenderTarget) {
+ Q_ASSERT(rhiD->currentSwapChain);
+ const QSize otherSize = rhiD->currentSwapChain->surfacePixelSize();
+ size.setWidth(qMin(size.width(), otherSize.width()));
+ size.setHeight(qMin(size.height(), otherSize.height()));
+ }
+#else
+ Q_UNUSED(rhiD);
+#endif
+
+ return size;
+}
+
void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
{
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
- const QSize outputSize = cbD->currentTarget->pixelSize();
+ const QSize outputSize = safeOutputSize(this, cbD);
// x,y is top-left in MTLViewportRect but bottom-left in QRhiViewport
float x, y, w, h;
@@ -1009,21 +1074,21 @@ void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
return;
MTLViewport vp;
- vp.originX = x;
- vp.originY = y;
- vp.width = w;
- vp.height = h;
- vp.znear = viewport.minDepth();
- vp.zfar = viewport.maxDepth();
+ vp.originX = double(x);
+ vp.originY = double(y);
+ vp.width = double(w);
+ vp.height = double(h);
+ vp.znear = double(viewport.minDepth());
+ vp.zfar = double(viewport.maxDepth());
[cbD->d->currentRenderPassEncoder setViewport: vp];
if (!QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) {
MTLScissorRect s;
- s.x = x;
- s.y = y;
- s.width = w;
- s.height = h;
+ s.x = NSUInteger(x);
+ s.y = NSUInteger(y);
+ s.width = NSUInteger(w);
+ s.height = NSUInteger(h);
[cbD->d->currentRenderPassEncoder setScissorRect: s];
}
}
@@ -1033,7 +1098,7 @@ void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
Q_ASSERT(QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
- const QSize outputSize = cbD->currentTarget->pixelSize();
+ const QSize outputSize = safeOutputSize(this, cbD);
// x,y is top-left in MTLScissorRect but bottom-left in QRhiScissor
int x, y, w, h;
@@ -1041,10 +1106,10 @@ void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
return;
MTLScissorRect s;
- s.x = x;
- s.y = y;
- s.width = w;
- s.height = h;
+ s.x = NSUInteger(x);
+ s.y = NSUInteger(y);
+ s.width = NSUInteger(w);
+ s.height = NSUInteger(h);
[cbD->d->currentRenderPassEncoder setScissorRect: s];
}
@@ -1054,7 +1119,8 @@ void QRhiMetal::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
- [cbD->d->currentRenderPassEncoder setBlendColorRed: c.redF() green: c.greenF() blue: c.blueF() alpha: c.alphaF()];
+ [cbD->d->currentRenderPassEncoder setBlendColorRed: float(c.redF())
+ green: float(c.greenF()) blue: float(c.blueF()) alpha: float(c.alphaF())];
}
void QRhiMetal::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
@@ -1086,7 +1152,7 @@ void QRhiMetal::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
return;
const quint32 indexOffset = cbD->currentIndexOffset + firstIndex * (cbD->currentIndexFormat == QRhiCommandBuffer::IndexUInt16 ? 2 : 4);
- Q_ASSERT(indexOffset == aligned(indexOffset, 4));
+ Q_ASSERT(indexOffset == aligned<quint32>(indexOffset, 4));
QMetalBuffer *ibufD = QRHI_RES(QMetalBuffer, cbD->currentIndexBuffer);
id<MTLBuffer> mtlbuf = ibufD->d->buf[ibufD->d->slotted ? currentFrameSlot : 0];
@@ -1344,7 +1410,7 @@ MTLRenderPassDescriptor *QRhiMetalData::createDefaultRenderPass(bool hasDepthSte
MTLClearColor c = MTLClearColorMake(colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
colorClearValue.alphaF());
- for (int i = 0; i < colorAttCount; ++i) {
+ for (uint i = 0; i < uint(colorAttCount); ++i) {
rp.colorAttachments[i].loadAction = MTLLoadActionClear;
rp.colorAttachments[i].storeAction = MTLStoreActionStore;
rp.colorAttachments[i].clearColor = c;
@@ -1355,7 +1421,7 @@ MTLRenderPassDescriptor *QRhiMetalData::createDefaultRenderPass(bool hasDepthSte
rp.depthAttachment.storeAction = MTLStoreActionDontCare;
rp.stencilAttachment.loadAction = MTLLoadActionClear;
rp.stencilAttachment.storeAction = MTLStoreActionDontCare;
- rp.depthAttachment.clearDepth = depthStencilClearValue.depthClearValue();
+ rp.depthAttachment.clearDepth = double(depthStencilClearValue.depthClearValue());
rp.stencilAttachment.clearStencil = depthStencilClearValue.stencilClearValue();
}
@@ -1368,7 +1434,7 @@ qsizetype QRhiMetal::subresUploadByteSize(const QRhiTextureSubresourceUploadDesc
const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
subresDesc.data().size() : subresDesc.image().sizeInBytes();
if (imageSizeBytes > 0)
- size += aligned(imageSizeBytes, QRhiMetalData::TEXBUF_ALIGN);
+ size += aligned<qsizetype>(imageSizeBytes, QRhiMetalData::TEXBUF_ALIGN);
return size;
}
@@ -1396,31 +1462,31 @@ void QRhiMetal::enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEnc
h = subresDesc.sourceSize().height();
}
if (img.depth() == 32) {
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), fullImageSizeBytes);
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), size_t(fullImageSizeBytes));
srcOffset = sy * bpl + sx * 4;
// bpl remains set to the original image's row stride
} else {
img = img.copy(sx, sy, w, h);
bpl = img.bytesPerLine();
Q_ASSERT(img.sizeInBytes() <= fullImageSizeBytes);
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), img.sizeInBytes());
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), size_t(img.sizeInBytes()));
}
} else {
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), fullImageSizeBytes);
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), size_t(fullImageSizeBytes));
}
[blitEnc copyFromBuffer: texD->d->stagingBuf[currentFrameSlot]
- sourceOffset: *curOfs + srcOffset
- sourceBytesPerRow: bpl
+ sourceOffset: NSUInteger(*curOfs + srcOffset)
+ sourceBytesPerRow: NSUInteger(bpl)
sourceBytesPerImage: 0
- sourceSize: MTLSizeMake(w, h, 1)
+ sourceSize: MTLSizeMake(NSUInteger(w), NSUInteger(h), 1)
toTexture: texD->d->tex
- destinationSlice: layer
- destinationLevel: level
- destinationOrigin: MTLOriginMake(dp.x(), dp.y(), 0)
+ destinationSlice: NSUInteger(layer)
+ destinationLevel: NSUInteger(level)
+ destinationOrigin: MTLOriginMake(NSUInteger(dp.x()), NSUInteger(dp.y()), 0)
options: MTLBlitOptionNone];
- *curOfs += aligned(fullImageSizeBytes, QRhiMetalData::TEXBUF_ALIGN);
+ *curOfs += aligned<qsizetype>(fullImageSizeBytes, QRhiMetalData::TEXBUF_ALIGN);
} else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
const QSize subresSize = q->sizeForMipLevel(level, texD->m_pixelSize);
const int subresw = subresSize.width();
@@ -1445,17 +1511,17 @@ void QRhiMetal::enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEnc
if (dy + h != subresh)
h = aligned(h, blockDim.height());
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, rawData.constData(), rawData.size());
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs, rawData.constData(), size_t(rawData.size()));
[blitEnc copyFromBuffer: texD->d->stagingBuf[currentFrameSlot]
- sourceOffset: *curOfs
+ sourceOffset: NSUInteger(*curOfs)
sourceBytesPerRow: bpl
sourceBytesPerImage: 0
- sourceSize: MTLSizeMake(w, h, 1)
+ sourceSize: MTLSizeMake(NSUInteger(w), NSUInteger(h), 1)
toTexture: texD->d->tex
- destinationSlice: layer
- destinationLevel: level
- destinationOrigin: MTLOriginMake(dx, dy, 0)
+ destinationSlice: NSUInteger(layer)
+ destinationLevel: NSUInteger(level)
+ destinationOrigin: MTLOriginMake(NSUInteger(dx), NSUInteger(dy), 0)
options: MTLBlitOptionNone];
*curOfs += aligned(rawData.size(), QRhiMetalData::TEXBUF_ALIGN);
@@ -1474,17 +1540,17 @@ void QRhiMetal::enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEnc
quint32 bpl = 0;
textureFormatInfo(texD->m_format, QSize(w, h), &bpl, nullptr);
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, rawData.constData(), rawData.size());
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs, rawData.constData(), size_t(rawData.size()));
[blitEnc copyFromBuffer: texD->d->stagingBuf[currentFrameSlot]
- sourceOffset: *curOfs
+ sourceOffset: NSUInteger(*curOfs)
sourceBytesPerRow: bpl
sourceBytesPerImage: 0
- sourceSize: MTLSizeMake(w, h, 1)
+ sourceSize: MTLSizeMake(NSUInteger(w), NSUInteger(h), 1)
toTexture: texD->d->tex
- destinationSlice: layer
- destinationLevel: level
- destinationOrigin: MTLOriginMake(dp.x(), dp.y(), 0)
+ destinationSlice: NSUInteger(layer)
+ destinationLevel: NSUInteger(level)
+ destinationOrigin: MTLOriginMake(NSUInteger(dp.x()), NSUInteger(dp.y()), 0)
options: MTLBlitOptionNone];
*curOfs += aligned(rawData.size(), QRhiMetalData::TEXBUF_ALIGN);
@@ -1538,9 +1604,9 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
ensureBlit();
Q_ASSERT(!utexD->d->stagingBuf[currentFrameSlot]);
- utexD->d->stagingBuf[currentFrameSlot] = [d->dev newBufferWithLength: stagingSize
+ utexD->d->stagingBuf[currentFrameSlot] = [d->dev newBufferWithLength: NSUInteger(stagingSize)
options: MTLResourceStorageModeShared];
- QRHI_PROF_F(newTextureStagingArea(utexD, currentFrameSlot, stagingSize));
+ QRHI_PROF_F(newTextureStagingArea(utexD, currentFrameSlot, quint32(stagingSize)));
void *mp = [utexD->d->stagingBuf[currentFrameSlot] contents];
qsizetype curOfs = 0;
@@ -1570,14 +1636,14 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
ensureBlit();
[blitEnc copyFromTexture: srcD->d->tex
- sourceSlice: u.copy.desc.sourceLayer()
- sourceLevel: u.copy.desc.sourceLevel()
- sourceOrigin: MTLOriginMake(sp.x(), sp.y(), 0)
- sourceSize: MTLSizeMake(size.width(), size.height(), 1)
+ sourceSlice: NSUInteger(u.copy.desc.sourceLayer())
+ sourceLevel: NSUInteger(u.copy.desc.sourceLevel())
+ sourceOrigin: MTLOriginMake(NSUInteger(sp.x()), NSUInteger(sp.y()), 0)
+ sourceSize: MTLSizeMake(NSUInteger(size.width()), NSUInteger(size.height()), 1)
toTexture: dstD->d->tex
- destinationSlice: u.copy.desc.destinationLayer()
- destinationLevel: u.copy.desc.destinationLevel()
- destinationOrigin: MTLOriginMake(dp.x(), dp.y(), 0)];
+ destinationSlice: NSUInteger(u.copy.desc.destinationLayer())
+ destinationLevel: NSUInteger(u.copy.desc.destinationLevel())
+ destinationOrigin: MTLOriginMake(NSUInteger(dp.x()), NSUInteger(dp.y()), 0)];
srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
@@ -1617,16 +1683,16 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
textureFormatInfo(aRb.format, aRb.pixelSize, &bpl, &aRb.bufSize);
aRb.buf = [d->dev newBufferWithLength: aRb.bufSize options: MTLResourceStorageModeShared];
- QRHI_PROF_F(newReadbackBuffer(quint64(quintptr(aRb.buf)),
+ QRHI_PROF_F(newReadbackBuffer(qint64(qintptr(aRb.buf)),
texD ? static_cast<QRhiResource *>(texD) : static_cast<QRhiResource *>(swapChainD),
aRb.bufSize));
ensureBlit();
[blitEnc copyFromTexture: src
- sourceSlice: u.read.rb.layer()
- sourceLevel: u.read.rb.level()
+ sourceSlice: NSUInteger(u.read.rb.layer())
+ sourceLevel: NSUInteger(u.read.rb.level())
sourceOrigin: MTLOriginMake(0, 0, 0)
- sourceSize: MTLSizeMake(srcSize.width(), srcSize.height(), 1)
+ sourceSize: MTLSizeMake(NSUInteger(srcSize.width()), NSUInteger(srcSize.height()), 1)
toBuffer: aRb.buf
destinationOffset: 0
destinationBytesPerRow: bpl
@@ -1664,14 +1730,14 @@ void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
int changeEnd = -1;
for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : updates) {
Q_ASSERT(bufD == QRHI_RES(QMetalBuffer, u.buf));
- memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), u.data.size());
+ memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
if (changeBegin == -1 || u.offset < changeBegin)
changeBegin = u.offset;
if (changeEnd == -1 || u.offset + u.data.size() > changeEnd)
changeEnd = u.offset + u.data.size();
}
if (changeBegin >= 0 && bufD->d->managed)
- [bufD->d->buf[idx] didModifyRange: NSMakeRange(changeBegin, changeEnd - changeBegin)];
+ [bufD->d->buf[idx] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))];
updates.clear();
}
@@ -1728,7 +1794,7 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
rtD = rtTex->d;
cbD->d->currentPassRpDesc = d->createDefaultRenderPass(rtD->dsAttCount, colorClearValue, depthStencilClearValue, rtD->colorAttCount);
if (rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents)) {
- for (int i = 0; i < rtD->colorAttCount; ++i)
+ for (uint i = 0; i < uint(rtD->colorAttCount); ++i)
cbD->d->currentPassRpDesc.colorAttachments[i].loadAction = MTLLoadActionLoad;
}
if (rtD->dsAttCount && rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents)) {
@@ -1755,15 +1821,15 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
break;
}
- for (int i = 0; i < rtD->colorAttCount; ++i) {
+ for (uint i = 0; i < uint(rtD->colorAttCount); ++i) {
cbD->d->currentPassRpDesc.colorAttachments[i].texture = rtD->fb.colorAtt[i].tex;
- cbD->d->currentPassRpDesc.colorAttachments[i].slice = rtD->fb.colorAtt[i].layer;
- cbD->d->currentPassRpDesc.colorAttachments[i].level = rtD->fb.colorAtt[i].level;
+ cbD->d->currentPassRpDesc.colorAttachments[i].slice = NSUInteger(rtD->fb.colorAtt[i].layer);
+ cbD->d->currentPassRpDesc.colorAttachments[i].level = NSUInteger(rtD->fb.colorAtt[i].level);
if (rtD->fb.colorAtt[i].resolveTex) {
cbD->d->currentPassRpDesc.colorAttachments[i].storeAction = MTLStoreActionMultisampleResolve;
cbD->d->currentPassRpDesc.colorAttachments[i].resolveTexture = rtD->fb.colorAtt[i].resolveTex;
- cbD->d->currentPassRpDesc.colorAttachments[i].resolveSlice = rtD->fb.colorAtt[i].resolveLayer;
- cbD->d->currentPassRpDesc.colorAttachments[i].resolveLevel = rtD->fb.colorAtt[i].resolveLevel;
+ cbD->d->currentPassRpDesc.colorAttachments[i].resolveSlice = NSUInteger(rtD->fb.colorAtt[i].resolveLayer);
+ cbD->d->currentPassRpDesc.colorAttachments[i].resolveLevel = NSUInteger(rtD->fb.colorAtt[i].resolveLevel);
}
}
@@ -1845,7 +1911,7 @@ void QRhiMetal::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::ComputePass);
QMetalComputePipeline *psD = QRHI_RES(QMetalComputePipeline, cbD->currentComputePipeline);
- [cbD->d->currentComputePassEncoder dispatchThreadgroups: MTLSizeMake(x, y, z)
+ [cbD->d->currentComputePassEncoder dispatchThreadgroups: MTLSizeMake(NSUInteger(x), NSUInteger(y), NSUInteger(z))
threadsPerThreadgroup: psD->d->localSize];
}
@@ -1913,12 +1979,12 @@ void QRhiMetal::finishActiveReadbacks(bool forced)
if (forced || currentFrameSlot == aRb.activeFrameSlot || aRb.activeFrameSlot < 0) {
aRb.result->format = aRb.format;
aRb.result->pixelSize = aRb.pixelSize;
- aRb.result->data.resize(aRb.bufSize);
+ aRb.result->data.resize(int(aRb.bufSize));
void *p = [aRb.buf contents];
memcpy(aRb.result->data.data(), p, aRb.bufSize);
[aRb.buf release];
- QRHI_PROF_F(releaseReadbackBuffer(quint64(quintptr(aRb.buf))));
+ QRHI_PROF_F(releaseReadbackBuffer(qint64(qintptr(aRb.buf))));
if (aRb.result->completed)
completedCallbacks.append(aRb.result->completed);
@@ -1977,8 +2043,8 @@ bool QMetalBuffer::build()
return false;
}
- const int nonZeroSize = m_size <= 0 ? 256 : m_size;
- const int roundedSize = m_usage.testFlag(QRhiBuffer::UniformBuffer) ? aligned(nonZeroSize, 256) : nonZeroSize;
+ const uint nonZeroSize = m_size <= 0 ? 256 : uint(m_size);
+ const uint roundedSize = m_usage.testFlag(QRhiBuffer::UniformBuffer) ? aligned<uint>(nonZeroSize, 256) : nonZeroSize;
d->managed = false;
MTLResourceOptions opts = MTLResourceStorageModeShared;
@@ -2065,10 +2131,10 @@ bool QMetalRenderBuffer::build()
MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc] init];
desc.textureType = samples > 1 ? MTLTextureType2DMultisample : MTLTextureType2D;
- desc.width = m_pixelSize.width();
- desc.height = m_pixelSize.height();
+ desc.width = NSUInteger(m_pixelSize.width());
+ desc.height = NSUInteger(m_pixelSize.height());
if (samples > 1)
- desc.sampleCount = samples;
+ desc.sampleCount = NSUInteger(samples);
desc.resourceOptions = MTLResourceStorageModePrivate;
desc.usage = MTLTextureUsageRenderTarget;
@@ -2335,11 +2401,11 @@ bool QMetalTexture::build()
else
desc.textureType = samples > 1 ? MTLTextureType2DMultisample : MTLTextureType2D;
desc.pixelFormat = d->format;
- desc.width = size.width();
- desc.height = size.height();
- desc.mipmapLevelCount = mipLevelCount;
+ desc.width = NSUInteger(size.width());
+ desc.height = NSUInteger(size.height());
+ desc.mipmapLevelCount = NSUInteger(mipLevelCount);
if (samples > 1)
- desc.sampleCount = samples;
+ desc.sampleCount = NSUInteger(samples);
desc.resourceOptions = MTLResourceStorageModePrivate;
desc.storageMode = MTLStorageModePrivate;
desc.usage = MTLTextureUsageShaderRead;
@@ -2405,7 +2471,7 @@ id<MTLTexture> QMetalTextureData::viewForLevel(int level)
const MTLTextureType type = [tex textureType];
const bool isCube = q->m_flags.testFlag(QRhiTexture::CubeMap);
id<MTLTexture> view = [tex newTextureViewWithPixelFormat: format textureType: type
- levels: NSMakeRange(level, 1) slices: NSMakeRange(0, isCube ? 6 : 1)];
+ levels: NSMakeRange(NSUInteger(level), 1) slices: NSMakeRange(0, isCube ? 6 : 1)];
perLevelViews[level] = view;
return view;
@@ -2615,13 +2681,13 @@ QRhiRenderPassDescriptor *QMetalTextureRenderTarget::newCompatibleRenderPassDesc
for (int i = 0, ie = colorAttachments.count(); i != ie; ++i) {
QMetalTexture *texD = QRHI_RES(QMetalTexture, colorAttachments[i].texture());
QMetalRenderBuffer *rbD = QRHI_RES(QMetalRenderBuffer, colorAttachments[i].renderBuffer());
- rpD->colorFormat[i] = texD ? texD->d->format : rbD->d->format;
+ rpD->colorFormat[i] = int(texD ? texD->d->format : rbD->d->format);
}
if (m_desc.depthTexture())
- rpD->dsFormat = QRHI_RES(QMetalTexture, m_desc.depthTexture())->d->format;
+ rpD->dsFormat = int(QRHI_RES(QMetalTexture, m_desc.depthTexture())->d->format);
else if (m_desc.depthStencilBuffer())
- rpD->dsFormat = QRHI_RES(QMetalRenderBuffer, m_desc.depthStencilBuffer())->d->format;
+ rpD->dsFormat = int(QRHI_RES(QMetalRenderBuffer, m_desc.depthStencilBuffer())->d->format);
return rpD;
}
@@ -2810,36 +2876,17 @@ void QMetalGraphicsPipeline::release()
{
QRHI_RES_RHI(QRhiMetal);
- if (!d->ps)
- return;
-
- if (d->ps) {
- [d->ps release];
- d->ps = nil;
- }
+ d->vs.release();
+ d->fs.release();
- if (d->ds) {
- [d->ds release];
- d->ds = nil;
- }
+ [d->ds release];
+ d->ds = nil;
- if (d->vsFunc) {
- [d->vsFunc release];
- d->vsFunc = nil;
- }
- if (d->vsLib) {
- [d->vsLib release];
- d->vsLib = nil;
- }
+ if (!d->ps)
+ return;
- if (d->fsFunc) {
- [d->fsFunc release];
- d->fsFunc = nil;
- }
- if (d->fsLib) {
- [d->fsLib release];
- d->fsLib = nil;
- }
+ [d->ps release];
+ d->ps = nil;
rhiD->unregisterResource(this);
}
@@ -3040,7 +3087,7 @@ id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var
QShaderCode mtllib = shader.shader({ QShader::MetalLibShader, 12, shaderVariant });
if (!mtllib.shader().isEmpty()) {
dispatch_data_t data = dispatch_data_create(mtllib.shader().constData(),
- mtllib.shader().size(),
+ size_t(mtllib.shader().size()),
dispatch_get_global_queue(0, 0),
DISPATCH_DATA_DESTRUCTOR_DEFAULT);
NSError *err = nil;
@@ -3100,19 +3147,19 @@ bool QMetalGraphicsPipeline::build()
MTLVertexDescriptor *inputLayout = [MTLVertexDescriptor vertexDescriptor];
const QVector<QRhiVertexInputAttribute> attributes = m_vertexInputLayout.attributes();
for (const QRhiVertexInputAttribute &attribute : attributes) {
- const int loc = attribute.location();
+ const uint loc = uint(attribute.location());
inputLayout.attributes[loc].format = toMetalAttributeFormat(attribute.format());
- inputLayout.attributes[loc].offset = attribute.offset();
- inputLayout.attributes[loc].bufferIndex = firstVertexBinding + attribute.binding();
+ inputLayout.attributes[loc].offset = NSUInteger(attribute.offset());
+ inputLayout.attributes[loc].bufferIndex = NSUInteger(firstVertexBinding + attribute.binding());
}
const QVector<QRhiVertexInputBinding> bindings = m_vertexInputLayout.bindings();
for (int i = 0, ie = bindings.count(); i != ie; ++i) {
const QRhiVertexInputBinding &binding(bindings[i]);
- const int layoutIdx = firstVertexBinding + i;
+ const uint layoutIdx = uint(firstVertexBinding + i);
inputLayout.layouts[layoutIdx].stepFunction =
binding.classification() == QRhiVertexInputBinding::PerInstance
? MTLVertexStepFunctionPerInstance : MTLVertexStepFunctionPerVertex;
- inputLayout.layouts[layoutIdx].stepRate = binding.instanceStepRate();
+ inputLayout.layouts[layoutIdx].stepRate = NSUInteger(binding.instanceStepRate());
inputLayout.layouts[layoutIdx].stride = binding.stride();
}
@@ -3126,34 +3173,66 @@ bool QMetalGraphicsPipeline::build()
// buffers not just the resource binding layout) so leave it at the default
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
- QString error;
- QByteArray entryPoint;
- id<MTLLibrary> lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint);
- if (!lib) {
- qWarning("MSL shader compilation failed: %s", qPrintable(error));
- return false;
- }
- id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
- if (!func) {
- qWarning("MSL function for entry point %s not found", entryPoint.constData());
- [lib release];
- return false;
- }
- switch (shaderStage.type()) {
- case QRhiShaderStage::Vertex:
- rpDesc.vertexFunction = func;
- d->vsLib = lib;
- d->vsFunc = func;
- break;
- case QRhiShaderStage::Fragment:
- rpDesc.fragmentFunction = func;
- d->fsLib = lib;
- d->fsFunc = func;
- break;
- default:
- [func release];
- [lib release];
- break;
+ auto cacheIt = rhiD->d->shaderCache.constFind(shaderStage);
+ if (cacheIt != rhiD->d->shaderCache.constEnd()) {
+ switch (shaderStage.type()) {
+ case QRhiShaderStage::Vertex:
+ d->vs = *cacheIt;
+ [d->vs.lib retain];
+ [d->vs.func retain];
+ rpDesc.vertexFunction = d->vs.func;
+ break;
+ case QRhiShaderStage::Fragment:
+ d->fs = *cacheIt;
+ [d->fs.lib retain];
+ [d->fs.func retain];
+ rpDesc.fragmentFunction = d->fs.func;
+ break;
+ default:
+ break;
+ }
+ } else {
+ QString error;
+ QByteArray entryPoint;
+ id<MTLLibrary> lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint);
+ if (!lib) {
+ qWarning("MSL shader compilation failed: %s", qPrintable(error));
+ return false;
+ }
+ id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
+ if (!func) {
+ qWarning("MSL function for entry point %s not found", entryPoint.constData());
+ [lib release];
+ return false;
+ }
+ if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) {
+ // Use the simplest strategy: too many cached shaders -> drop them all.
+ for (QMetalShader &s : rhiD->d->shaderCache)
+ s.release();
+ rhiD->d->shaderCache.clear();
+ }
+ switch (shaderStage.type()) {
+ case QRhiShaderStage::Vertex:
+ d->vs.lib = lib;
+ d->vs.func = func;
+ rhiD->d->shaderCache.insert(shaderStage, d->vs);
+ [d->vs.lib retain];
+ [d->vs.func retain];
+ rpDesc.vertexFunction = func;
+ break;
+ case QRhiShaderStage::Fragment:
+ d->fs.lib = lib;
+ d->fs.func = func;
+ rhiD->d->shaderCache.insert(shaderStage, d->fs);
+ [d->fs.lib retain];
+ [d->fs.func retain];
+ rpDesc.fragmentFunction = func;
+ break;
+ default:
+ [func release];
+ [lib release];
+ break;
+ }
}
}
@@ -3168,8 +3247,8 @@ bool QMetalGraphicsPipeline::build()
Q_ASSERT(m_targetBlends.count() == rpD->colorAttachmentCount
|| (m_targetBlends.isEmpty() && rpD->colorAttachmentCount == 1));
- for (int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
- const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
+ for (uint i = 0, ie = uint(m_targetBlends.count()); i != ie; ++i) {
+ const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[int(i)]);
rpDesc.colorAttachments[i].pixelFormat = MTLPixelFormat(rpD->colorFormat[i]);
rpDesc.colorAttachments[i].blendingEnabled = b.enable;
rpDesc.colorAttachments[i].sourceRGBBlendFactor = toMetalBlendFactor(b.srcColor);
@@ -3191,7 +3270,7 @@ bool QMetalGraphicsPipeline::build()
rpDesc.stencilAttachmentPixelFormat = fmt;
}
- rpDesc.sampleCount = rhiD->effectiveSampleCount(m_sampleCount);
+ rpDesc.sampleCount = NSUInteger(rhiD->effectiveSampleCount(m_sampleCount));
NSError *err = nil;
d->ps = [rhiD->d->dev newRenderPipelineStateWithDescriptor: rpDesc error: &err];
@@ -3253,22 +3332,13 @@ void QMetalComputePipeline::release()
{
QRHI_RES_RHI(QRhiMetal);
- if (d->csFunc) {
- [d->csFunc release];
- d->csFunc = nil;
- }
- if (d->csLib) {
- [d->csLib release];
- d->csLib = nil;
- }
+ d->cs.release();
if (!d->ps)
return;
- if (d->ps) {
- [d->ps release];
- d->ps = nil;
- }
+ [d->ps release];
+ d->ps = nil;
rhiD->unregisterResource(this);
}
@@ -3280,28 +3350,44 @@ bool QMetalComputePipeline::build()
QRHI_RES_RHI(QRhiMetal);
- const QShader shader = m_shaderStage.shader();
- QString error;
- QByteArray entryPoint;
- id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(),
- &error, &entryPoint);
- if (!lib) {
- qWarning("MSL shader compilation failed: %s", qPrintable(error));
- return false;
- }
- id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
- if (!func) {
- qWarning("MSL function for entry point %s not found", entryPoint.constData());
- [lib release];
- return false;
+ auto cacheIt = rhiD->d->shaderCache.constFind(m_shaderStage);
+ if (cacheIt != rhiD->d->shaderCache.constEnd()) {
+ d->cs = *cacheIt;
+ } else {
+ const QShader shader = m_shaderStage.shader();
+ QString error;
+ QByteArray entryPoint;
+ id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(),
+ &error, &entryPoint);
+ if (!lib) {
+ qWarning("MSL shader compilation failed: %s", qPrintable(error));
+ return false;
+ }
+ id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
+ if (!func) {
+ qWarning("MSL function for entry point %s not found", entryPoint.constData());
+ [lib release];
+ return false;
+ }
+ d->cs.lib = lib;
+ d->cs.func = func;
+ d->cs.localSize = shader.description().computeShaderLocalSize();
+
+ if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) {
+ for (QMetalShader &s : rhiD->d->shaderCache)
+ s.release();
+ rhiD->d->shaderCache.clear();
+ }
+ rhiD->d->shaderCache.insert(m_shaderStage, d->cs);
}
- d->csLib = lib;
- d->csFunc = func;
- std::array<uint, 3> localSize = shader.description().computeShaderLocalSize();
- d->localSize = MTLSizeMake(localSize[0], localSize[1], localSize[2]);
+
+ [d->cs.lib retain];
+ [d->cs.func retain];
+
+ d->localSize = MTLSizeMake(d->cs.localSize[0], d->cs.localSize[1], d->cs.localSize[2]);
NSError *err = nil;
- d->ps = [rhiD->d->dev newComputePipelineStateWithFunction: d->csFunc error: &err];
+ d->ps = [rhiD->d->dev newComputePipelineStateWithFunction: d->cs.func error: &err];
if (!d->ps) {
const QString msg = QString::fromNSString(err.localizedDescription);
qWarning("Failed to create render pipeline state: %s", qPrintable(msg));
@@ -3439,7 +3525,7 @@ QSize QMetalSwapChain::surfacePixelSize()
CAMetalLayer *layer = (CAMetalLayer *) [v layer];
if (layer) {
CGSize size = [layer drawableSize];
- return QSize(size.width, size.height);
+ return QSize(int(size.width), int(size.height));
}
}
return QSize();
@@ -3454,7 +3540,7 @@ QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
rpD->colorAttachmentCount = 1;
rpD->hasDepthStencil = m_depthStencil != nullptr;
- rpD->colorFormat[0] = d->colorFormat;
+ rpD->colorFormat[0] = int(d->colorFormat);
// m_depthStencil may not be built yet so cannot rely on computed fields in it
rpD->dsFormat = rhiD->d->dev.depth24Stencil8PixelFormatSupported
@@ -3511,6 +3597,18 @@ bool QMetalSwapChain::buildOrResize()
}
#endif
+ if (m_flags.testFlag(SurfaceHasPreMulAlpha)) {
+ d->layer.opaque = NO;
+ } else if (m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
+ // The CoreAnimation compositor is said to expect premultiplied alpha,
+ // so this is then wrong when it comes to the blending operations but
+ // there's nothing we can do. Fortunately Qt Quick always outputs
+ // premultiplied alpha so it is not a problem there.
+ d->layer.opaque = NO;
+ } else {
+ d->layer.opaque = YES;
+ }
+
m_currentPixelSize = surfacePixelSize();
pixelSize = m_currentPixelSize;
@@ -3538,7 +3636,7 @@ bool QMetalSwapChain::buildOrResize()
}
rtWrapper.d->pixelSize = pixelSize;
- rtWrapper.d->dpr = window->devicePixelRatio();
+ rtWrapper.d->dpr = float(window->devicePixelRatio());
rtWrapper.d->sampleCount = samples;
rtWrapper.d->colorAttCount = 1;
rtWrapper.d->dsAttCount = ds ? 1 : 0;
@@ -3549,9 +3647,9 @@ bool QMetalSwapChain::buildOrResize()
MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc] init];
desc.textureType = MTLTextureType2DMultisample;
desc.pixelFormat = d->colorFormat;
- desc.width = pixelSize.width();
- desc.height = pixelSize.height();
- desc.sampleCount = samples;
+ desc.width = NSUInteger(pixelSize.width());
+ desc.height = NSUInteger(pixelSize.height());
+ desc.sampleCount = NSUInteger(samples);
desc.resourceOptions = MTLResourceStorageModePrivate;
desc.storageMode = MTLStorageModePrivate;
desc.usage = MTLTextureUsageRenderTarget;