6#include <QGuiApplication>
10#include <QTemporaryFile>
13#include <QOperatingSystemVersion>
15#include <QtCore/private/qcore_mac_p.h>
20#include <UIKit/UIKit.h>
23#include <Metal/Metal.h>
24#include <QuartzCore/CAMetalLayer.h>
39#if __has_feature(objc_arc)
40#error ARC not supported
49#define QRHI_METAL_DISABLE_BINARY_ARCHIVE
54#define QRHI_METAL_COMMAND_BUFFERS_WITH_UNRETAINED_REFERENCES
175 const
QColor &colorClearValue,
335 id<MTLCommandBuffer>
cb;
384 id<MTLRenderPipelineState>
ps = nil;
385 id<MTLDepthStencilState>
ds = nil;
417 return vertexOrIndexCount *
instanceCount *
sizeof(float) * 60;
426 return patchCount *
sizeof(float) * 128;
446 id<MTLComputePipelineState>
ps = nil;
460 MTLRenderPassDescriptor *
rp =
nullptr;
465 bool liveResizeObserverSet =
false;
479 if (importDevice->dev) {
480 d->
dev = (id<MTLDevice>) importDevice->dev;
483 d->
cmdQueue = (id<MTLCommandQueue>) importDevice->cmdQueue;
485 qWarning(
"No MTLDevice given, cannot import");
499 return (
v + byteAlign - 1) & ~(byteAlign - 1);
505 id<MTLDevice> dev = MTLCreateSystemDefaultDevice();
515#ifdef QRHI_METAL_COMMAND_BUFFERS_WITH_UNRETAINED_REFERENCES
519 return [
cmdQueue commandBufferWithUnretainedReferences];
527#ifdef QRHI_METAL_DISABLE_BINARY_ARCHIVE
531 if (@available(macOS 11.0,
iOS 14.0, *)) {
533 MTLBinaryArchiveDescriptor *binArchDesc = [MTLBinaryArchiveDescriptor
new];
534 binArchDesc.url = sourceFileUrl;
536 binArch = [
dev newBinaryArchiveWithDescriptor: binArchDesc
error: &err];
539 const QString msg = QString::fromNSString(err.localizedDescription);
555 d->
dev = MTLCreateSystemDefaultDevice();
571 if (@available(macOS 10.15, *)) {
572 const MTLDeviceLocation deviceLocation = [
d->
dev location];
573 switch (deviceLocation) {
574 case MTLDeviceLocationBuiltIn:
577 case MTLDeviceLocationSlot:
580 case MTLDeviceLocationExternal:
600 d->
captureMgr = [MTLCaptureManager sharedCaptureManager];
608#if defined(Q_OS_MACOS)
609 caps.maxTextureSize = 16384;
610 caps.baseVertexAndInstance =
true;
611 if (@available(macOS 10.15, *))
612 caps.isAppleGPU = [
d->
dev supportsFamily:MTLGPUFamilyApple7];
613 caps.maxThreadGroupSize = 1024;
614 caps.multiView =
true;
615#elif defined(Q_OS_TVOS)
616 if ([
d->
dev supportsFeatureSet: MTLFeatureSet(30003)])
617 caps.maxTextureSize = 16384;
619 caps.maxTextureSize = 8192;
620 caps.baseVertexAndInstance =
false;
621 caps.isAppleGPU =
true;
622#elif defined(Q_OS_IOS)
624 if ([
d->
dev supportsFeatureSet: MTLFeatureSet(16)]
625 || [
d->
dev supportsFeatureSet: MTLFeatureSet(11)]
626 || [
d->
dev supportsFeatureSet: MTLFeatureSet(4)])
628 caps.maxTextureSize = 16384;
629 caps.baseVertexAndInstance =
true;
630 }
else if ([
d->
dev supportsFeatureSet: MTLFeatureSet(3)]
631 || [
d->
dev supportsFeatureSet: MTLFeatureSet(2)])
633 caps.maxTextureSize = 8192;
634 caps.baseVertexAndInstance =
false;
636 caps.maxTextureSize = 4096;
637 caps.baseVertexAndInstance =
false;
639 caps.isAppleGPU =
true;
640 if (@available(
iOS 13, *)) {
641 if ([
d->
dev supportsFamily: MTLGPUFamilyApple4])
642 caps.maxThreadGroupSize = 1024;
643 if ([
d->
dev supportsFamily: MTLGPUFamilyApple5])
644 caps.multiView =
true;
648 caps.supportedSampleCounts = { 1 };
649 for (
int sampleCount : { 2, 4, 8 }) {
650 if ([
d->
dev supportsTextureSampleCount: sampleCount])
651 caps.supportedSampleCounts.append(sampleCount);
675 if (@available(macOS 11.0,
iOS 14.0, *)) {
691 return caps.supportedSampleCounts;
728 if (
m.isIdentity()) {
731 0.0f, 1.0f, 0.0f, 0.0f,
732 0.0f, 0.0f, 0.5f, 0.5f,
733 0.0f, 0.0f, 0.0f, 1.0f);
742 bool supportsFamilyMac2 =
false;
743 bool supportsFamilyApple3 =
false;
746 supportsFamilyMac2 =
true;
748 supportsFamilyApple3 =
true;
750 supportsFamilyApple3 =
true;
757 if (!supportsFamilyApple3) {
764 if (!supportsFamilyMac2)
805 return caps.baseVertexAndInstance;
807 return caps.baseVertexAndInstance;
826 if (@available(macOS 11.0,
iOS 14.0, *))
860 return caps.multiView;
877 return caps.maxTextureSize;
893 return caps.maxThreadGroupSize;
958 if (@available(macOS 11.0,
iOS 14.0, *)) {
964 qCDebug(QRHI_LOG_INFO,
"pipelineCacheData: Failed to create temporary file for Metal");
972 if (![
d->binArch serializeToURL:
url error: &err]) {
973 const QString msg = QString::fromNSString(err.localizedDescription);
975 qCDebug(QRHI_LOG_INFO,
"Failed to serialize MTLBinaryArchive: %s",
qPrintable(msg));
981 qCDebug(QRHI_LOG_INFO,
"pipelineCacheData: Failed to reopen temporary file");
1001 header.driver[driverStrLen] =
'\0';
1016 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size (header incomplete)");
1025 if (
header.rhiId != rhiId) {
1026 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
1032 if (
header.arch != arch) {
1033 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
1039 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: OS version does not match (%u.%u, %u.%u)",
1046 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Metal device name does not match");
1051 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size (data incomplete)");
1055 if (@available(macOS 11.0,
iOS 14.0, *)) {
1056 const char *
p =
data.constData() + dataOffset;
1060 qCDebug(QRHI_LOG_INFO,
"pipelineCacheData: Failed to create temporary file for Metal");
1063 tmp.write(
p,
header.dataSize);
1069 qCDebug(QRHI_LOG_INFO,
"Created MTLBinaryArchive with initial data of %u bytes",
header.dataSize);
1074 int sampleCount, QRhiRenderBuffer::Flags
flags,
1081 const QSize &pixelSize,
int depth,
int arraySize,
1082 int sampleCount, QRhiTexture::Flags
flags)
1091 return new QMetalSampler(
this, magFilter, minFilter, mipmapMode, u,
v,
w);
1095 QRhiTextureRenderTarget::Flags
flags)
1148 offsets: offsetBatch.resources.constData()
1149 withRange: NSMakeRange(bufferBatch.startBinding,
NSUInteger(bufferBatch.resources.count()))];
1153 offsets: offsetBatch.resources.constData()
1154 withRange: NSMakeRange(bufferBatch.startBinding,
NSUInteger(bufferBatch.resources.count()))];
1158 offsets: offsetBatch.resources.constData()
1159 withRange: NSMakeRange(bufferBatch.startBinding,
NSUInteger(bufferBatch.resources.count()))];
1178 withRange: NSMakeRange(textureBatch.startBinding,
NSUInteger(textureBatch.resources.count()))];
1182 withRange: NSMakeRange(textureBatch.startBinding,
NSUInteger(textureBatch.resources.count()))];
1186 withRange: NSMakeRange(textureBatch.startBinding,
NSUInteger(textureBatch.resources.count()))];
1202 switch (encoderStage) {
1205 withRange: NSMakeRange(samplerBatch.startBinding,
NSUInteger(samplerBatch.resources.count()))];
1209 withRange: NSMakeRange(samplerBatch.startBinding,
NSUInteger(samplerBatch.resources.count()))];
1213 withRange: NSMakeRange(samplerBatch.startBinding,
NSUInteger(samplerBatch.resources.count()))];
1235 for (
int i = 0, ie = bindingData->
res[resourceStage].bufferBatches.batches.count();
i != ie; ++
i) {
1236 const auto &bufferBatch(bindingData->
res[resourceStage].bufferBatches.batches[
i]);
1237 const auto &offsetBatch(bindingData->
res[resourceStage].bufferOffsetBatches.batches[
i]);
1241 for (
int i = 0, ie = bindingData->
res[resourceStage].textureBatches.batches.count();
i != ie; ++
i) {
1242 const auto &batch(bindingData->
res[resourceStage].textureBatches.batches[
i]);
1246 for (
int i = 0, ie = bindingData->
res[resourceStage].samplerBatches.batches.count();
i != ie; ++
i) {
1247 const auto &batch(bindingData->
res[resourceStage].samplerBatches.batches[
i]);
1272 int dynamicOffsetCount,
1274 bool offsetOnlyChange,
1285 id<MTLBuffer> mtlbuf = bufD->d->buf[bufD->d->slotted ?
currentFrameSlot : 0];
1287 for (
int i = 0;
i < dynamicOffsetCount; ++
i) {
1289 if (dynOfs.first ==
b->binding) {
1298 if (nativeBinding >= 0)
1299 bindingData.
res[stage].buffers.append({ nativeBinding, mtlbuf,
offset });
1309 for (
int elem = 0; elem <
data->count; ++elem) {
1322 if (textureBinding >= 0 && texD)
1323 bindingData.
res[stage].textures.append({ textureBinding + elem, texD->d->tex });
1324 if (samplerBinding >= 0)
1325 bindingData.
res[stage].samplers.append({ samplerBinding + elem, samplerD->d->samplerState });
1336 id<MTLTexture>
t = texD->d->viewForLevel(
b->u.simage.level);
1341 if (nativeBinding >= 0)
1342 bindingData.
res[stage].textures.append({ nativeBinding,
t });
1352 id<MTLBuffer> mtlbuf = bufD->d->buf[0];
1357 if (nativeBinding >= 0)
1358 bindingData.
res[stage].buffers.append({ nativeBinding, mtlbuf,
offset });
1382 return a.nativeBinding < b.nativeBinding;
1386 bindingData.
res[stage].bufferBatches.feed(
buf.nativeBinding,
buf.mtlbuf);
1387 bindingData.
res[stage].bufferOffsetBatches.feed(
buf.nativeBinding,
buf.offset);
1390 bindingData.
res[stage].bufferBatches.finish();
1391 bindingData.
res[stage].bufferOffsetBatches.finish();
1393 for (
int i = 0, ie = bindingData.
res[stage].bufferBatches.batches.count();
i != ie; ++
i) {
1394 const auto &bufferBatch(bindingData.
res[stage].bufferBatches.batches[
i]);
1395 const auto &offsetBatch(bindingData.
res[stage].bufferOffsetBatches.batches[
i]);
1407 if (offsetOnlyChange)
1411 return a.nativeBinding < b.nativeBinding;
1415 return a.nativeBinding < b.nativeBinding;
1419 bindingData.
res[stage].textureBatches.feed(
t.nativeBinding,
t.mtltex);
1422 bindingData.
res[stage].samplerBatches.feed(
s.nativeBinding,
s.mtlsampler);
1424 bindingData.
res[stage].textureBatches.finish();
1425 bindingData.
res[stage].samplerBatches.finish();
1427 for (
int i = 0, ie = bindingData.
res[stage].textureBatches.batches.count();
i != ie; ++
i) {
1428 const auto &batch(bindingData.
res[stage].textureBatches.batches[
i]);
1438 for (
int i = 0, ie = bindingData.
res[stage].samplerBatches.batches.count();
i != ie; ++
i) {
1439 const auto &batch(bindingData.
res[stage].samplerBatches.batches[
i]);
1497 if (!psD->d->tess.enabled && !psD->d->tess.failed) {
1498 psD->makeActiveForCurrentRenderPassEncoder(cbD);
1501 for (
QMetalBuffer *workBuf : psD->d->extraBufMgr.deviceLocalWorkBuffers) {
1503 workBuf->lastActiveFrameSlot = -1;
1505 for (
QMetalBuffer *workBuf : psD->d->extraBufMgr.hostVisibleWorkBuffers) {
1507 workBuf->lastActiveFrameSlot = -1;
1515 int dynamicOffsetCount,
1525 srb = gfxPsD->m_shaderResourceBindings;
1527 srb = compPsD->m_shaderResourceBindings;
1531 bool hasSlottedResourceInSrb =
false;
1532 bool hasDynamicOffsetInSrb =
false;
1533 bool resNeedsRebind =
false;
1538 const bool needsBufferSizeBuffer = (compPsD && compPsD->d->bufferSizeBuffer) || (gfxPsD && gfxPsD->d->bufferSizeBuffer);
1539 QMap<QRhiShaderResourceBinding::StageFlag, QMap<int, quint32>> storageBufferSizes;
1542 for (
int i = 0, ie = srbD->sortedBindings.count();
i != ie; ++
i) {
1551 if (bufD->d->slotted)
1552 hasSlottedResourceInSrb =
true;
1553 if (
b->u.ubuf.hasDynamicOffset)
1554 hasDynamicOffsetInSrb =
true;
1555 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
1556 resNeedsRebind =
true;
1557 bd.ubuf.id = bufD->m_id;
1558 bd.ubuf.generation = bufD->generation;
1568 if (bd.stex.count !=
data->count) {
1570 resNeedsRebind =
true;
1572 for (
int elem = 0; elem <
data->count; ++elem) {
1576 const quint64 texId = texD ? texD->m_id : 0;
1577 const uint texGen = texD ? texD->generation : 0;
1578 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
1579 const uint samplerGen = samplerD ? samplerD->generation : 0;
1580 if (texGen != bd.stex.d[elem].texGeneration
1581 || texId != bd.stex.d[elem].texId
1582 || samplerGen != bd.stex.d[elem].samplerGeneration
1583 || samplerId != bd.stex.d[elem].samplerId)
1585 resNeedsRebind =
true;
1586 bd.stex.d[elem].texId = texId;
1587 bd.stex.d[elem].texGeneration = texGen;
1588 bd.stex.d[elem].samplerId = samplerId;
1589 bd.stex.d[elem].samplerGeneration = samplerGen;
1603 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
1604 resNeedsRebind =
true;
1605 bd.simage.id = texD->m_id;
1606 bd.simage.generation = texD->generation;
1618 if (needsBufferSizeBuffer) {
1619 for (
int i = 0;
i < 6; ++
i) {
1622 if (
b->stage.testFlag(stage)) {
1623 storageBufferSizes[stage][
b->binding] =
b->u.sbuf.maybeSize ?
b->u.sbuf.maybeSize : bufD->size();
1629 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
1630 resNeedsRebind =
true;
1631 bd.sbuf.id = bufD->m_id;
1632 bd.sbuf.generation = bufD->generation;
1643 if (needsBufferSizeBuffer) {
1645 QVarLengthArray<QPair<QMetalShader *, QRhiShaderResourceBinding::StageFlag>, 4>
shaders;
1648 bufD = compPsD->
d->bufferSizeBuffer;
1652 bufD = gfxPsD->d->bufferSizeBuffer;
1653 if (gfxPsD->d->tess.enabled) {
1663 Q_ASSERT(gfxPsD->d->tess.compVs[0].desc.storageBlocks() == gfxPsD->d->tess.compVs[1].desc.storageBlocks());
1664 Q_ASSERT(gfxPsD->d->tess.compVs[0].desc.storageBlocks() == gfxPsD->d->tess.compVs[2].desc.storageBlocks());
1665 Q_ASSERT(gfxPsD->d->tess.compVs[0].nativeResourceBindingMap == gfxPsD->d->tess.compVs[1].nativeResourceBindingMap);
1666 Q_ASSERT(gfxPsD->d->tess.compVs[0].nativeResourceBindingMap == gfxPsD->d->tess.compVs[2].nativeResourceBindingMap);
1694 for (
const QPair<QMetalShader *, QRhiShaderResourceBinding::StageFlag> &
shader :
shaders) {
1699 if (!(storageBufferSizes.contains(
shader.second) && storageBufferSizes[
shader.second].contains(binding))) {
1701 int maxNativeBinding = 0;
1703 maxNativeBinding =
qMax(maxNativeBinding,
shader.first->nativeResourceBindingMap[block.binding].first);
1705 const int size = (maxNativeBinding + 1) *
sizeof(
int);
1712 bd.sbuf.generation = bufD->generation;
1713 srbD->boundResourceData.append(bd);
1717 QVarLengthArray<int, 8> bufferSizeBufferData;
1719 const QMap<int, quint32> &
sizes(storageBufferSizes[
shader.second]);
1721 const int index =
shader.first->nativeResourceBindingMap[block.binding].first;
1727 if (bufferSizeBufferData.size() <=
index)
1728 bufferSizeBufferData.resize(
index + 1);
1731 bufferSizeBufferData[
index] =
sizes[block.binding];
1736 data.assign(
reinterpret_cast<const char *
>(bufferSizeBufferData.constData()),
size);
1751 resNeedsRebind =
true;
1757 if (hasDynamicOffsetInSrb || resNeedsRebind || srbChanged || srbRebuilt) {
1762 if (gfxPsD->d->tess.enabled) {
1765 Q_ASSERT(gfxPsD->d->tess.compVs[0].nativeResourceBindingMap == gfxPsD->d->tess.compVs[1].nativeResourceBindingMap);
1766 Q_ASSERT(gfxPsD->d->tess.compVs[0].nativeResourceBindingMap == gfxPsD->d->tess.compVs[2].nativeResourceBindingMap);
1782 const bool offsetOnlyChange = hasDynamicOffsetInSrb && !resNeedsRebind && !srbChanged && !srbRebuilt;
1794 QRhiBatchedBindings<id<MTLBuffer> >
buffers;
1795 QRhiBatchedBindings<NSUInteger>
offsets;
1796 for (
int i = 0;
i < bindingCount; ++
i) {
1800 id<MTLBuffer> mtlbuf = bufD->d->buf[bufD->d->slotted ?
currentFrameSlot : 0];
1801 buffers.feed(startBinding +
i, mtlbuf);
1802 offsets.feed(startBinding +
i, bindings[
i].second);
1814 const int firstVertexBinding = srbD->maxBinding + 1;
1824 for (
int i = 0, ie =
buffers.batches.count();
i != ie; ++
i) {
1825 const auto &bufferBatch(
buffers.batches[
i]);
1826 const auto &offsetBatch(
offsets.batches[
i]);
1828 bufferBatch.resources.constData()
1829 offsets: offsetBatch.resources.constData()
1830 withRange: NSMakeRange(
uint(firstVertexBinding) + bufferBatch.startBinding,
NSUInteger(bufferBatch.resources.count()))];
1854 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize,
viewport.viewport(), &
x, &
y, &
w, &
h))
1858 vp.originX = double(
x);
1859 vp.originY = double(
y);
1860 vp.width = double(
w);
1861 vp.height = double(
h);
1862 vp.znear = double(
viewport.minDepth());
1863 vp.zfar = double(
viewport.maxDepth());
1870 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize,
viewport.viewport(), &
x, &
y, &
w, &
h);
1888 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.
scissor(), &
x, &
y, &
w, &
h))
1952 QVarLengthArray<MTLLoadAction, 4> oldColorLoad;
1953 for (
uint i = 0;
i <
uint(rtD->colorAttCount); ++
i) {
1959 MTLLoadAction oldDepthLoad;
1960 MTLLoadAction oldStencilLoad;
1961 if (rtD->dsAttCount) {
1967 if (cbD->
d->
currentPassRpDesc.stencilAttachment.storeAction != MTLStoreActionDontCare)
1974 for (
uint i = 0;
i <
uint(rtD->colorAttCount); ++
i) {
1978 if (rtD->dsAttCount) {
1989 if (graphicsPipeline->
d->
tess.failed)
1994 const quint32 vertexOrIndexCount = indexed ?
args.drawIndexed.indexCount :
args.draw.vertexCount;
2008 id<MTLComputeCommandEncoder> computeEncoder = vertTescComputeEncoder;
2015 id<MTLComputePipelineState> computePipelineState = tess.
vsCompPipeline(
this, shaderVariant);
2016 [computeEncoder setComputePipelineState: computePipelineState];
2029 if (outputBufferBinding >= 0) {
2034 [computeEncoder setBuffer: vertOutBuf->d->buf[0]
offset: 0 atIndex: outputBufferBinding];
2037 if (indexBufferBinding >= 0)
2038 [computeEncoder setBuffer: (id<MTLBuffer>)
args.drawIndexed.indexBuffer
offset: 0 atIndex: indexBufferBinding];
2043 [computeEncoder setBuffers: bufferBatch.resources.constData()
2044 offsets: offsetBatch.resources.constData()
2049 [computeEncoder setStageInRegion: MTLRegionMake2D(
args.drawIndexed.vertexOffset,
args.drawIndexed.firstInstance,
2050 args.drawIndexed.indexCount,
args.drawIndexed.instanceCount)];
2052 [computeEncoder setStageInRegion: MTLRegionMake2D(
args.draw.firstVertex,
args.draw.firstInstance,
2053 args.draw.vertexCount,
args.draw.instanceCount)];
2056 [computeEncoder dispatchThreads: MTLSizeMake(vertexOrIndexCount,
instanceCount, 1)
2057 threadsPerThreadgroup: MTLSizeMake(computePipelineState.threadExecutionWidth, 1, 1)];
2062 id<MTLComputeCommandEncoder> computeEncoder = vertTescComputeEncoder;
2063 id<MTLComputePipelineState> computePipelineState = tess.
tescCompPipeline(
this);
2064 [computeEncoder setComputePipelineState: computePipelineState];
2077 if (outputBufferBinding >= 0) {
2082 [computeEncoder setBuffer: tescOutBuf->d->buf[0]
offset: 0 atIndex: outputBufferBinding];
2085 if (patchOutputBufferBinding >= 0) {
2088 if (!tescPatchOutBuf)
2090 [computeEncoder setBuffer: tescPatchOutBuf->d->buf[0]
offset: 0 atIndex: patchOutputBufferBinding];
2093 if (tessFactorBufferBinding >= 0) {
2094 tescFactorBuf = extraBufMgr.
acquireWorkBuffer(
this, patchCount *
sizeof(MTLQuadTessellationFactorsHalf));
2095 [computeEncoder setBuffer: tescFactorBuf->d->buf[0]
offset: 0 atIndex: tessFactorBufferBinding];
2098 if (paramsBufferBinding >= 0) {
2107 params.patchCount = patchCount;
2108 id<MTLBuffer> paramsBuf = tescParamsBuf->d->buf[0];
2109 char *
p =
reinterpret_cast<char *
>([paramsBuf
contents]);
2111 [computeEncoder setBuffer: paramsBuf
offset: 0 atIndex: paramsBufferBinding];
2114 if (vertOutBuf && inputBufferBinding >= 0)
2115 [computeEncoder setBuffer: vertOutBuf->d->buf[0]
offset: 0 atIndex: inputBufferBinding];
2117 int sgSize = int(computePipelineState.threadExecutionWidth);
2119 while (wgSize >
caps.maxThreadGroupSize) {
2124 threadsPerThreadgroup: MTLSizeMake(wgSize, 1, 1)];
2151 if (outputBufferBinding >= 0 && tescOutBuf)
2152 [renderEncoder setVertexBuffer: tescOutBuf->d->buf[0]
offset: 0 atIndex: outputBufferBinding];
2154 if (patchOutputBufferBinding >= 0 && tescPatchOutBuf)
2155 [renderEncoder setVertexBuffer: tescPatchOutBuf->d->buf[0]
offset: 0 atIndex: patchOutputBufferBinding];
2157 if (tessFactorBufferBinding >= 0 && tescFactorBuf) {
2158 [renderEncoder setTessellationFactorBuffer: tescFactorBuf->d->buf[0]
offset: 0 instanceStride: 0];
2159 [renderEncoder setVertexBuffer: tescFactorBuf->d->buf[0]
offset: 0 atIndex: tessFactorBufferBinding];
2164 patchCount: patchCount
2165 patchIndexBuffer: nil
2166 patchIndexBufferOffset: 0
2176 if (multiViewCount <= 1)
2181 if (viewMaskBufBinding == -1) {
2182 qWarning(
"No extra buffer for multiview in the vertex shader; was it built with --view-count specified?");
2189 multiViewInfo.viewOffset = 0;
2190 multiViewInfo.viewCount =
quint32(multiViewCount);
2194 id<MTLBuffer> mtlbuf =
buf->d->buf[0];
2195 char *
p =
reinterpret_cast<char *
>([mtlbuf
contents]);
2196 memcpy(
p, &multiViewInfo,
sizeof(multiViewInfo));
2215 a.
draw.vertexCount = vertexCount;
2217 a.draw.firstVertex = firstVertex;
2218 a.draw.firstInstance = firstInstance;
2225 if (
caps.baseVertexAndInstance) {
2253 a.drawIndexed.indexCount = indexCount;
2255 a.drawIndexed.firstIndex = firstIndex;
2256 a.drawIndexed.vertexOffset = vertexOffset;
2257 a.drawIndexed.firstInstance = firstInstance;
2258 a.drawIndexed.indexBuffer = mtlibuf;
2265 if (
caps.baseVertexAndInstance) {
2267 indexCount: indexCount
2269 indexBuffer: mtlibuf
2270 indexBufferOffset: indexOffset
2272 baseVertex: vertexOffset
2273 baseInstance: firstInstance];
2276 indexCount: indexCount
2278 indexBuffer: mtlibuf
2279 indexBufferOffset: indexOffset
2289 NSString *
str = [NSString stringWithUTF8String:
name.constData()];
2294 [cbD->
d->
cb pushDebugGroup:
str];
2306 [cbD->
d->
cb popDebugGroup];
2352 dispatch_semaphore_wait(swapChainD->d->sem[
currentFrameSlot], DISPATCH_TIME_FOREVER);
2361 if (sc != swapChainD)
2370 if (swapChainD->samples > 1) {
2377 swapChainD->rtWrapper.d->fb.colorAtt[0] = colorAtt;
2378 swapChainD->rtWrapper.d->fb.dsTex = swapChainD->ds ? swapChainD->ds->d->
tex : nil;
2379 swapChainD->rtWrapper.d->fb.dsResolveTex = nil;
2380 swapChainD->rtWrapper.d->fb.hasStencil = swapChainD->ds ? true :
false;
2381 swapChainD->rtWrapper.d->fb.depthNeedsStore =
false;
2387 swapChainD->cbWrapper.resetState(swapChainD->d->lastGpuTime[
currentFrameSlot]);
2400 [swapChainD->cbWrapper.d->cb addCompletedHandler: ^(id<MTLCommandBuffer>
cb) {
2401 swapChainD->d->lastGpuTime[thisFrameSlot] +=
cb.GPUEndTime -
cb.GPUStartTime;
2402 dispatch_semaphore_signal(swapChainD->d->sem[thisFrameSlot]);
2405#ifdef QRHI_METAL_COMMAND_BUFFERS_WITH_UNRETAINED_REFERENCES
2409 id<MTLTexture> drawableTexture = [swapChainD->d->curDrawable.texture retain];
2410 [swapChainD->cbWrapper.d->cb addCompletedHandler:^(id<MTLCommandBuffer>) {
2416 const bool presentsWithTransaction = swapChainD->d->layer.presentsWithTransaction;
2417 if (!presentsWithTransaction && needsPresent) {
2419 if (id<CAMetalDrawable> drawable = swapChainD->d->curDrawable)
2420 [swapChainD->cbWrapper.d->cb presentDrawable: drawable];
2423 [swapChainD->cbWrapper.d->cb
commit];
2425 if (presentsWithTransaction && needsPresent) {
2427 if (id<CAMetalDrawable> drawable = swapChainD->d->curDrawable) {
2431 [swapChainD->cbWrapper.d->cb waitUntilScheduled];
2437 [swapChainD->d->curDrawable
release];
2438 swapChainD->d->curDrawable = nil;
2445 swapChainD->frameCount += 1;
2459 d->
ofr.active =
true;
2464 d->
ofr.cbWrapper.resetState(
d->
ofr.lastGpuTime);
2465 d->
ofr.lastGpuTime = 0;
2475 d->
ofr.active =
false;
2477 id<MTLCommandBuffer>
cb =
d->
ofr.cbWrapper.d->cb;
2481 [
cb waitUntilCompleted];
2483 d->
ofr.lastGpuTime +=
cb.GPUEndTime -
cb.GPUStartTime;
2492 id<MTLCommandBuffer>
cb = nil;
2495 if (
d->
ofr.active) {
2498 cb =
d->
ofr.cbWrapper.d->cb;
2503 cb = swapChainD->cbWrapper.d->cb;
2514 sc->waitUntilCompleted(
i);
2520 [
cb waitUntilCompleted];
2524 if (
d->
ofr.active) {
2525 d->
ofr.lastGpuTime +=
cb.GPUEndTime -
cb.GPUStartTime;
2541 const QColor &colorClearValue,
2545 MTLRenderPassDescriptor *rp = [MTLRenderPassDescriptor renderPassDescriptor];
2546 MTLClearColor
c = MTLClearColorMake(colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
2547 colorClearValue.alphaF());
2550 rp.colorAttachments[
i].loadAction = MTLLoadActionClear;
2551 rp.colorAttachments[
i].storeAction = MTLStoreActionStore;
2552 rp.colorAttachments[
i].clearColor =
c;
2555 if (hasDepthStencil) {
2556 rp.depthAttachment.loadAction = MTLLoadActionClear;
2557 rp.depthAttachment.storeAction = MTLStoreActionDontCare;
2558 rp.stencilAttachment.loadAction = MTLLoadActionClear;
2559 rp.stencilAttachment.storeAction = MTLStoreActionDontCare;
2560 rp.depthAttachment.clearDepth = double(depthStencilClearValue.depthClearValue());
2561 rp.stencilAttachment.clearStencil = depthStencilClearValue.stencilClearValue();
2572 if (imageSizeBytes > 0)
2585 id<MTLBlitCommandEncoder> blitEnc = (id<MTLBlitCommandEncoder>) blitEncPtr;
2587 if (!
img.isNull()) {
2589 int w =
img.width();
2590 int h =
img.height();
2591 int bpl =
img.bytesPerLine();
2600 if (
w ==
img.width()) {
2601 const int bpc =
qMax(1,
img.depth() / 8);
2602 Q_ASSERT(
h *
img.bytesPerLine() <= fullImageSizeBytes);
2603 memcpy(
reinterpret_cast<char *
>(mp) + *curOfs,
2604 img.constBits() + sy *
img.bytesPerLine() + sx * bpc,
2605 h *
img.bytesPerLine());
2608 bpl =
img.bytesPerLine();
2609 Q_ASSERT(
img.sizeInBytes() <= fullImageSizeBytes);
2610 memcpy(
reinterpret_cast<char *
>(mp) + *curOfs,
img.constBits(),
size_t(
img.sizeInBytes()));
2613 memcpy(
reinterpret_cast<char *
>(mp) + *curOfs,
img.constBits(),
size_t(fullImageSizeBytes));
2619 sourceBytesPerImage: 0
2621 toTexture: texD->d->tex
2625 options: MTLBlitOptionNone];
2629 const QSize subresSize =
q->sizeForMipLevel(
level, texD->m_pixelSize);
2630 const int subresw = subresSize.
width();
2631 const int subresh = subresSize.height();
2645 const int dx =
aligned(dp.x(), blockDim.width());
2646 const int dy =
aligned(dp.y(), blockDim.height());
2647 if (dx +
w != subresw)
2649 if (dy +
h != subresh)
2652 memcpy(
reinterpret_cast<char *
>(mp) + *curOfs, rawData.
constData(),
size_t(rawData.
size()));
2656 sourceBytesPerRow: bpl
2657 sourceBytesPerImage: 0
2659 toTexture: texD->d->tex
2663 options: MTLBlitOptionNone];
2666 }
else if (!rawData.
isEmpty()) {
2667 const QSize subresSize =
q->sizeForMipLevel(
level, texD->m_pixelSize);
2668 const int subresw = subresSize.
width();
2669 const int subresh = subresSize.height();
2685 memcpy(
reinterpret_cast<char *
>(mp) + *curOfs, rawData.
constData(),
size_t(rawData.
size()));
2689 sourceBytesPerRow: bpl
2690 sourceBytesPerImage: 0
2692 toTexture: texD->d->tex
2696 options: MTLBlitOptionNone];
2709 id<MTLBlitCommandEncoder> blitEnc = nil;
2710 auto ensureBlit = [&blitEnc, cbD,
this]() {
2712 blitEnc = [cbD->
d->
cb blitCommandEncoder];
2714 [blitEnc pushDebugGroup:
@"Texture upload/copy"];
2718 for (
int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
2725 bufD->d->pendingUpdates[
i].clear();
2726 bufD->d->pendingUpdates[
i].append({ u.
offset, u.
data });
2735 bufD->d->pendingUpdates[
i].append({ u.
offset, u.
data });
2741 char *
p =
reinterpret_cast<char *
>([bufD->d->buf[idx]
contents]);
2743 u.result->data.resize(u.readSize);
2744 memcpy(u.result->data.data(),
p + u.offset,
size_t(u.readSize));
2746 if (u.result->completed)
2747 u.result->completed();
2751 readback.buf = bufD->d->buf[idx];
2752 readback.offset = u.offset;
2753 readback.readSize = u.readSize;
2754 readback.result = u.result;
2757 if (bufD->d->managed) {
2760 [blitEnc synchronizeResource:readback.buf];
2767 for (
int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
2772 for (
int layer = 0, maxLayer = u.subresDesc.count();
layer < maxLayer; ++
layer) {
2775 stagingSize += subresUploadByteSize(subresDesc);
2780 Q_ASSERT(!utexD->d->stagingBuf[currentFrameSlot]);
2781 utexD->d->stagingBuf[currentFrameSlot] = [
d->dev newBufferWithLength:
NSUInteger(stagingSize)
2782 options: MTLResourceStorageModeShared];
2784 void *mp = [utexD->d->stagingBuf[currentFrameSlot]
contents];
2786 for (
int layer = 0, maxLayer = u.subresDesc.count();
layer < maxLayer; ++
layer) {
2789 enqueueSubresUpload(utexD, mp, blitEnc,
layer,
level, subresDesc, &curOfs);
2793 utexD->lastActiveFrameSlot = currentFrameSlot;
2798 e.
stagingBuffer.buffer = utexD->d->stagingBuf[currentFrameSlot];
2799 utexD->d->stagingBuf[currentFrameSlot] = nil;
2800 d->releaseQueue.append(e);
2807 const QPoint dp = u.desc.destinationTopLeft();
2808 const QSize mipSize =
q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
2809 const QSize copySize = u.desc.pixelSize().
isEmpty() ? mipSize : u.desc.pixelSize();
2810 const QPoint sp = u.desc.sourceTopLeft();
2813 [blitEnc copyFromTexture: srcD->d->tex
2818 toTexture: dstD->
d->tex
2819 destinationSlice:
NSUInteger(dstIs3D ? 0 : u.
desc.destinationLayer())
2823 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
2827 readback.desc = u.rb;
2828 readback.result = u.result;
2836 if (texD->samples > 1) {
2837 qWarning(
"Multisample texture cannot be read back");
2841 readback.pixelSize =
q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
2842 readback.format = texD->m_format;
2844 srcSize = readback.pixelSize;
2845 texD->lastActiveFrameSlot = currentFrameSlot;
2849 readback.pixelSize = swapChainD->pixelSize;
2850 readback.format = swapChainD->d->rhiColorFormat;
2854 src = colorAtt.resolveTex ? colorAtt.resolveTex : colorAtt.tex;
2855 srcSize = swapChainD->rtWrapper.d->pixelSize;
2859 textureFormatInfo(readback.format, readback.pixelSize, &bpl, &readback.bufSize,
nullptr);
2860 readback.buf = [
d->dev newBufferWithLength: readback.bufSize options: MTLResourceStorageModeShared];
2863 [blitEnc copyFromTexture:
src
2866 sourceOrigin: MTLOriginMake(0, 0, is3D ? u.rb.
layer() : 0)
2868 toBuffer: readback.
buf
2869 destinationOffset: 0
2870 destinationBytesPerRow: bpl
2871 destinationBytesPerImage: 0
2872 options: MTLBlitOptionNone];
2874 d->activeTextureReadbacks.append(readback);
2878 [blitEnc generateMipmapsForTexture: utexD->d->tex];
2879 utexD->lastActiveFrameSlot = currentFrameSlot;
2885 [blitEnc popDebugGroup];
2886 [blitEnc endEncoding];
2895 if (bufD->d->pendingUpdates[slot].isEmpty())
2898 void *
p = [bufD->d->buf[slot]
contents];
2899 quint32 changeBegin = UINT32_MAX;
2902 memcpy(
static_cast<char *
>(
p) + u.offset, u.data.constData(),
size_t(u.data.size()));
2903 if (u.offset < changeBegin)
2904 changeBegin = u.offset;
2905 if (u.offset + u.data.size() > changeEnd)
2906 changeEnd = u.offset + u.data.size();
2909 if (changeBegin < UINT32_MAX && changeBegin < changeEnd && bufD->
d->managed)
2910 [bufD->d->buf[slot] didModifyRange: NSMakeRange(
NSUInteger(changeBegin),
NSUInteger(changeEnd - changeBegin))];
2913 bufD->d->pendingUpdates[slot].clear();
2930 const QColor &colorClearValue,
2933 QRhiCommandBuffer::BeginPassFlags)
2938 if (resourceUpdates)
2946 if (rtD->colorAttCount) {
2948 if (color0.needsDrawableForTex || color0.needsDrawableForResolveTex) {
2951 if (!swapChainD->d->curDrawable) {
2953 swapChainD->d->curDrawable = [[swapChainD->d->layer nextDrawable] retain];
2955 if (!swapChainD->d->curDrawable) {
2959 id<MTLTexture> scTex = swapChainD->d->curDrawable.texture;
2960 if (color0.needsDrawableForTex) {
2962 color0.needsDrawableForTex =
false;
2964 color0.resolveTex = scTex;
2965 color0.needsDrawableForResolveTex =
false;
2974 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QMetalTexture, QMetalRenderBuffer>(rtTex->description(), rtD->currentResIdList))
2977 if (rtD->fb.preserveColor) {
2978 for (
uint i = 0;
i <
uint(rtD->colorAttCount); ++
i)
2981 if (rtD->dsAttCount && rtD->fb.preserveDs) {
2985 int colorAttCount = 0;
2986 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2990 if (
it->texture()) {
2992 if (
it->multiViewCount() >= 2)
2994 }
else if (
it->renderBuffer()) {
2997 if (
it->resolveTexture())
3000 if (rtTex->m_desc.depthStencilBuffer())
3002 if (rtTex->m_desc.depthTexture()) {
3005 if (colorAttCount == 0 && depthTexture->
arraySize() >= 2)
3008 if (rtTex->m_desc.depthResolveTexture())
3017 for (
uint i = 0;
i <
uint(rtD->colorAttCount); ++
i) {
3022 if (rtD->fb.colorAtt[
i].resolveTex) {
3023 cbD->
d->
currentPassRpDesc.colorAttachments[
i].storeAction = rtD->fb.preserveColor ? MTLStoreActionStoreAndMultisampleResolve
3024 : MTLStoreActionMultisampleResolve;
3031 if (rtD->dsAttCount) {
3034 cbD->
d->
currentPassRpDesc.stencilAttachment.texture = rtD->fb.hasStencil ? rtD->fb.dsTex : nil;
3035 if (rtD->fb.depthNeedsStore)
3037 if (rtD->fb.dsResolveTex) {
3038 cbD->
d->
currentPassRpDesc.depthAttachment.storeAction = rtD->fb.depthNeedsStore ? MTLStoreActionStoreAndMultisampleResolve
3039 : MTLStoreActionMultisampleResolve;
3041 if (rtD->fb.hasStencil) {
3066 if (resourceUpdates)
3072 QRhiCommandBuffer::BeginPassFlags)
3077 if (resourceUpdates)
3093 if (resourceUpdates)
3121 threadsPerThreadgroup: psD->d->localSize];
3195 if (forced ||
currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
3196 readback.result->format = readback.format;
3197 readback.result->pixelSize = readback.pixelSize;
3198 readback.result->data.resize(
int(readback.bufSize));
3200 memcpy(readback.result->data.data(),
p, readback.bufSize);
3203 if (readback.result->completed)
3204 completedCallbacks.append(readback.result->completed);
3213 || readback.activeFrameSlot < 0) {
3214 readback.result->data.resize(readback.readSize);
3215 char *
p =
reinterpret_cast<char *
>([readback.buf
contents]);
3217 memcpy(readback.result->data.data(),
p + readback.offset,
size_t(readback.readSize));
3219 if (readback.result->completed)
3220 completedCallbacks.append(readback.result->completed);
3226 for (
auto f : completedCallbacks)
3261 rhiD->d->releaseQueue.append(e);
3262 rhiD->unregisterResource(
this);
3272 qWarning(
"StorageBuffer cannot be combined with Dynamic");
3280 MTLResourceOptions opts = MTLResourceStorageModeShared;
3285 opts = MTLResourceStorageModeManaged;
3301 d->
buf[
i] = [rhiD->d->dev newBufferWithLength: roundedSize options: opts];
3307 d->
buf[
i].label = [NSString stringWithUTF8String:
name.constData()];
3315 rhiD->registerResource(
this);
3326 rhiD->executeBufferHostWritesForSlot(
this,
i);
3332 return { { &
d->
buf[0] }, 1 };
3345 const int slot = rhiD->currentFrameSlot;
3347 return static_cast<char *
>(
p);
3355 const int slot = rhiD->currentFrameSlot;
3370 return srgb ? MTLPixelFormatRGBA8Unorm_sRGB : MTLPixelFormatRGBA8Unorm;
3372 return srgb ? MTLPixelFormatBGRA8Unorm_sRGB : MTLPixelFormatBGRA8Unorm;
3375 return MTLPixelFormatR8Unorm;
3377 return srgb ? MTLPixelFormatR8Unorm_sRGB : MTLPixelFormatR8Unorm;
3381 return MTLPixelFormatRG8Unorm;
3383 return srgb ? MTLPixelFormatRG8Unorm_sRGB : MTLPixelFormatRG8Unorm;
3386 return MTLPixelFormatR16Unorm;
3388 return MTLPixelFormatRG16Unorm;
3390 return MTLPixelFormatR8Unorm;
3393 return MTLPixelFormatRGBA16Float;
3395 return MTLPixelFormatRGBA32Float;
3397 return MTLPixelFormatR16Float;
3399 return MTLPixelFormatR32Float;
3402 return MTLPixelFormatRGB10A2Unorm;
3406 return MTLPixelFormatDepth16Unorm;
3408 return [
d->d->dev isDepth24Stencil8PixelFormatSupported] ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float;
3410 return [
d->d->dev isDepth24Stencil8PixelFormatSupported] ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8;
3413 return MTLPixelFormatDepth32Float;
3415 return MTLPixelFormatDepth32Float;
3417 return MTLPixelFormatDepth32Float_Stencil8;
3420 return MTLPixelFormatDepth32Float;
3424 return srgb ? MTLPixelFormatBC1_RGBA_sRGB : MTLPixelFormatBC1_RGBA;
3426 return srgb ? MTLPixelFormatBC2_RGBA_sRGB : MTLPixelFormatBC2_RGBA;
3428 return srgb ? MTLPixelFormatBC3_RGBA_sRGB : MTLPixelFormatBC3_RGBA;
3430 return MTLPixelFormatBC4_RUnorm;
3432 qWarning(
"QRhiMetal does not support BC5");
3433 return MTLPixelFormatInvalid;
3435 return MTLPixelFormatBC6H_RGBUfloat;
3437 return srgb ? MTLPixelFormatBC7_RGBAUnorm_sRGB : MTLPixelFormatBC7_RGBAUnorm;
3446 qWarning(
"QRhiMetal: BCx compression not supported on this platform");
3447 return MTLPixelFormatInvalid;
3452 return srgb ? MTLPixelFormatETC2_RGB8_sRGB : MTLPixelFormatETC2_RGB8;
3454 return srgb ? MTLPixelFormatETC2_RGB8A1_sRGB : MTLPixelFormatETC2_RGB8A1;
3456 return srgb ? MTLPixelFormatEAC_RGBA8_sRGB : MTLPixelFormatEAC_RGBA8;
3459 return srgb ? MTLPixelFormatASTC_4x4_sRGB : MTLPixelFormatASTC_4x4_LDR;
3461 return srgb ? MTLPixelFormatASTC_5x4_sRGB : MTLPixelFormatASTC_5x4_LDR;
3463 return srgb ? MTLPixelFormatASTC_5x5_sRGB : MTLPixelFormatASTC_5x5_LDR;
3465 return srgb ? MTLPixelFormatASTC_6x5_sRGB : MTLPixelFormatASTC_6x5_LDR;
3467 return srgb ? MTLPixelFormatASTC_6x6_sRGB : MTLPixelFormatASTC_6x6_LDR;
3469 return srgb ? MTLPixelFormatASTC_8x5_sRGB : MTLPixelFormatASTC_8x5_LDR;
3471 return srgb ? MTLPixelFormatASTC_8x6_sRGB : MTLPixelFormatASTC_8x6_LDR;
3473 return srgb ? MTLPixelFormatASTC_8x8_sRGB : MTLPixelFormatASTC_8x8_LDR;
3475 return srgb ? MTLPixelFormatASTC_10x5_sRGB : MTLPixelFormatASTC_10x5_LDR;
3477 return srgb ? MTLPixelFormatASTC_10x6_sRGB : MTLPixelFormatASTC_10x6_LDR;
3479 return srgb ? MTLPixelFormatASTC_10x8_sRGB : MTLPixelFormatASTC_10x8_LDR;
3481 return srgb ? MTLPixelFormatASTC_10x10_sRGB : MTLPixelFormatASTC_10x10_LDR;
3483 return srgb ? MTLPixelFormatASTC_12x10_sRGB : MTLPixelFormatASTC_12x10_LDR;
3485 return srgb ? MTLPixelFormatASTC_12x12_sRGB : MTLPixelFormatASTC_12x12_LDR;
3488 if (
d->caps.isAppleGPU) {
3489 if (@available(macOS 11.0, *))
3490 return srgb ? MTLPixelFormatETC2_RGB8_sRGB : MTLPixelFormatETC2_RGB8;
3492 qWarning(
"QRhiMetal: ETC2 compression not supported on this platform");
3493 return MTLPixelFormatInvalid;
3495 if (
d->caps.isAppleGPU) {
3496 if (@available(macOS 11.0, *))
3497 return srgb ? MTLPixelFormatETC2_RGB8A1_sRGB : MTLPixelFormatETC2_RGB8A1;
3499 qWarning(
"QRhiMetal: ETC2 compression not supported on this platform");
3500 return MTLPixelFormatInvalid;
3502 if (
d->caps.isAppleGPU) {
3503 if (@available(macOS 11.0, *))
3504 return srgb ? MTLPixelFormatEAC_RGBA8_sRGB : MTLPixelFormatEAC_RGBA8;
3506 qWarning(
"QRhiMetal: ETC2 compression not supported on this platform");
3507 return MTLPixelFormatInvalid;
3509 if (
d->caps.isAppleGPU) {
3510 if (@available(macOS 11.0, *))
3511 return srgb ? MTLPixelFormatASTC_4x4_sRGB : MTLPixelFormatASTC_4x4_LDR;
3513 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3514 return MTLPixelFormatInvalid;
3516 if (
d->caps.isAppleGPU) {
3517 if (@available(macOS 11.0, *))
3518 return srgb ? MTLPixelFormatASTC_5x4_sRGB : MTLPixelFormatASTC_5x4_LDR;
3520 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3521 return MTLPixelFormatInvalid;
3523 if (
d->caps.isAppleGPU) {
3524 if (@available(macOS 11.0, *))
3525 return srgb ? MTLPixelFormatASTC_5x5_sRGB : MTLPixelFormatASTC_5x5_LDR;
3527 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3528 return MTLPixelFormatInvalid;
3530 if (
d->caps.isAppleGPU) {
3531 if (@available(macOS 11.0, *))
3532 return srgb ? MTLPixelFormatASTC_6x5_sRGB : MTLPixelFormatASTC_6x5_LDR;
3534 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3535 return MTLPixelFormatInvalid;
3537 if (
d->caps.isAppleGPU) {
3538 if (@available(macOS 11.0, *))
3539 return srgb ? MTLPixelFormatASTC_6x6_sRGB : MTLPixelFormatASTC_6x6_LDR;
3541 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3542 return MTLPixelFormatInvalid;
3544 if (
d->caps.isAppleGPU) {
3545 if (@available(macOS 11.0, *))
3546 return srgb ? MTLPixelFormatASTC_8x5_sRGB : MTLPixelFormatASTC_8x5_LDR;
3548 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3549 return MTLPixelFormatInvalid;
3551 if (
d->caps.isAppleGPU) {
3552 if (@available(macOS 11.0, *))
3553 return srgb ? MTLPixelFormatASTC_8x6_sRGB : MTLPixelFormatASTC_8x6_LDR;
3555 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3556 return MTLPixelFormatInvalid;
3558 if (
d->caps.isAppleGPU) {
3559 if (@available(macOS 11.0, *))
3560 return srgb ? MTLPixelFormatASTC_8x8_sRGB : MTLPixelFormatASTC_8x8_LDR;
3562 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3563 return MTLPixelFormatInvalid;
3565 if (
d->caps.isAppleGPU) {
3566 if (@available(macOS 11.0, *))
3567 return srgb ? MTLPixelFormatASTC_10x5_sRGB : MTLPixelFormatASTC_10x5_LDR;
3569 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3570 return MTLPixelFormatInvalid;
3572 if (
d->caps.isAppleGPU) {
3573 if (@available(macOS 11.0, *))
3574 return srgb ? MTLPixelFormatASTC_10x6_sRGB : MTLPixelFormatASTC_10x6_LDR;
3576 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3577 return MTLPixelFormatInvalid;
3579 if (
d->caps.isAppleGPU) {
3580 if (@available(macOS 11.0, *))
3581 return srgb ? MTLPixelFormatASTC_10x8_sRGB : MTLPixelFormatASTC_10x8_LDR;
3583 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3584 return MTLPixelFormatInvalid;
3586 if (
d->caps.isAppleGPU) {
3587 if (@available(macOS 11.0, *))
3588 return srgb ? MTLPixelFormatASTC_10x10_sRGB : MTLPixelFormatASTC_10x10_LDR;
3590 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3591 return MTLPixelFormatInvalid;
3593 if (
d->caps.isAppleGPU) {
3594 if (@available(macOS 11.0, *))
3595 return srgb ? MTLPixelFormatASTC_12x10_sRGB : MTLPixelFormatASTC_12x10_LDR;
3597 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3598 return MTLPixelFormatInvalid;
3600 if (
d->caps.isAppleGPU) {
3601 if (@available(macOS 11.0, *))
3602 return srgb ? MTLPixelFormatASTC_12x12_sRGB : MTLPixelFormatASTC_12x12_LDR;
3604 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3605 return MTLPixelFormatInvalid;
3610 return MTLPixelFormatInvalid;
3615 int sampleCount, QRhiRenderBuffer::Flags
flags,
3642 rhiD->d->releaseQueue.append(e);
3643 rhiD->unregisterResource(
this);
3658 MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc]
init];
3659 desc.textureType =
samples > 1 ? MTLTextureType2DMultisample : MTLTextureType2D;
3664 desc.resourceOptions = MTLResourceStorageModePrivate;
3665 desc.usage = MTLTextureUsageRenderTarget;
3670 if (rhiD->caps.isAppleGPU) {
3671 if (@available(macOS 11.0, *)) {
3672 desc.storageMode = MTLStorageModeMemoryless;
3673 d->
format = MTLPixelFormatDepth32Float_Stencil8;
3678 desc.storageMode = MTLStorageModePrivate;
3679 d->
format = rhiD->d->dev.depth24Stencil8PixelFormatSupported
3680 ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8;
3683 desc.storageMode = MTLStorageModeMemoryless;
3684 d->
format = MTLPixelFormatDepth32Float_Stencil8;
3689 desc.storageMode = MTLStorageModePrivate;
3693 d->
format = MTLPixelFormatRGBA8Unorm;
3701 d->
tex = [rhiD->d->dev newTextureWithDescriptor: desc];
3709 rhiD->registerResource(
this);
3763 rhiD->d->releaseQueue.append(e);
3764 rhiD->unregisterResource(
this);
3788 qWarning(
"Cubemap texture cannot be multisample");
3792 qWarning(
"3D texture cannot be multisample");
3796 qWarning(
"Multisample texture cannot have mipmaps");
3800 if (isCube && is3D) {
3801 qWarning(
"Texture cannot be both cube and 3D");
3804 if (isArray && is3D) {
3805 qWarning(
"Texture cannot be both array and 3D");
3809 qWarning(
"Texture cannot be both 1D and 3D");
3812 if (is1D && isCube) {
3813 qWarning(
"Texture cannot be both 1D and cube");
3817 qWarning(
"Texture cannot have a depth of %d when it is not 3D",
m_depth);
3830 *adjustedSize =
size;
3841 MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc]
init];
3848 desc.textureType = MTLTextureTypeCube;
3850 desc.textureType = MTLTextureType3D;
3852 desc.textureType = isArray ? MTLTextureType1DArray : MTLTextureType1D;
3853 }
else if (isArray) {
3855 if (@available(
iOS 14, *)) {
3856 desc.textureType =
samples > 1 ? MTLTextureType2DMultisampleArray : MTLTextureType2DArray;
3858 desc.textureType = MTLTextureType2DArray;
3861 desc.textureType =
samples > 1 ? MTLTextureType2DMultisampleArray : MTLTextureType2DArray;
3864 desc.textureType =
samples > 1 ? MTLTextureType2DMultisample : MTLTextureType2D;
3875 desc.resourceOptions = MTLResourceStorageModePrivate;
3876 desc.storageMode = MTLStorageModePrivate;
3877 desc.usage = MTLTextureUsageShaderRead;
3879 desc.usage |= MTLTextureUsageRenderTarget;
3881 desc.usage |= MTLTextureUsageShaderWrite;
3884 d->
tex = [rhiD->d->dev newTextureWithDescriptor: desc];
3894 rhiD->registerResource(
this);
3900 id<MTLTexture> tex = id<MTLTexture>(
src.object);
3914 rhiD->registerResource(
this);
3929 const MTLTextureType
type = [
tex textureType];
3932 id<MTLTexture>
view = [
tex newTextureViewWithPixelFormat:
format textureType:
type
3934 slices: NSMakeRange(0, isCube ? 6 : (isArray ?
qMax(0,
q->m_arraySize) : 1))];
3942 :
QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u,
v,
w),
3967 rhiD->d->releaseQueue.append(e);
3968 rhiD->unregisterResource(
this);
3976 return MTLSamplerMinMagFilterNearest;
3978 return MTLSamplerMinMagFilterLinear;
3981 return MTLSamplerMinMagFilterNearest;
3989 return MTLSamplerMipFilterNotMipmapped;
3991 return MTLSamplerMipFilterNearest;
3993 return MTLSamplerMipFilterLinear;
3996 return MTLSamplerMipFilterNotMipmapped;
4004 return MTLSamplerAddressModeRepeat;
4006 return MTLSamplerAddressModeClampToEdge;
4008 return MTLSamplerAddressModeMirrorRepeat;
4011 return MTLSamplerAddressModeClampToEdge;
4019 return MTLCompareFunctionNever;
4021 return MTLCompareFunctionLess;
4023 return MTLCompareFunctionEqual;
4025 return MTLCompareFunctionLessEqual;
4027 return MTLCompareFunctionGreater;
4029 return MTLCompareFunctionNotEqual;
4031 return MTLCompareFunctionGreaterEqual;
4033 return MTLCompareFunctionAlways;
4036 return MTLCompareFunctionNever;
4045 MTLSamplerDescriptor *desc = [[MTLSamplerDescriptor alloc]
init];
4055 d->
samplerState = [rhiD->d->dev newSamplerStateWithDescriptor: desc];
4060 rhiD->registerResource(
this);
4081 rhiD->unregisterResource(
this);
4130 rpD->updateSerializedFormat();
4133 rhiD->registerResource(rpD,
false);
4192 rhiD->unregisterResource(
this);
4199 rpD->colorAttachmentCount = colorAttachmentCount;
4202 for (
int i = 0;
i < colorAttachmentCount; ++
i) {
4206 rpD->colorFormat[
i] = int(texD ? texD->d->format : rbD->d->format);
4214 rpD->updateSerializedFormat();
4217 rhiD->registerResource(rpD,
false);
4235 id<MTLTexture>
dst = nil;
4239 if (attIndex == 0) {
4240 d->
pixelSize = rhiD->q->sizeForMipLevel(
it->level(), texD->pixelSize());
4246 if (attIndex == 0) {
4254 colorAtt.
slice = is3D ?
it->layer() : 0;
4257 colorAtt.
resolveTex = resTexD ? resTexD->d->tex : nil;
4260 d->
fb.colorAtt[attIndex] = colorAtt;
4264 if (hasDepthStencil) {
4267 d->
fb.dsTex = depthTexD->d->tex;
4268 d->
fb.hasStencil = rhiD->isStencilSupportingFormat(depthTexD->format());
4277 d->
fb.dsTex = depthRbD->d->tex;
4278 d->
fb.hasStencil =
true;
4279 d->
fb.depthNeedsStore =
false;
4280 d->
fb.preserveDs =
false;
4288 d->
fb.dsResolveTex = depthResolveTexD->d->tex;
4298 QRhiRenderTargetAttachmentTracker::updateResIdList<QMetalTexture, QMetalRenderBuffer>(
m_desc, &
d->
currentResIdList);
4300 rhiD->registerResource(
this,
false);
4306 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QMetalTexture, QMetalRenderBuffer>(
m_desc,
d->
currentResIdList))
4339 rhiD->unregisterResource(
this);
4348 if (!rhiD->sanityCheckShaderResourceBindings(
this))
4351 rhiD->updateLayoutDesc(
this);
4366 rhiD->registerResource(
this,
false);
4402 d->
tess.compVs[0].destroy();
4403 d->
tess.compVs[1].destroy();
4404 d->
tess.compVs[2].destroy();
4406 d->
tess.compTesc.destroy();
4407 d->
tess.vertTese.destroy();
4418 && !
d->
tess.vertexComputeState[0] && !
d->
tess.vertexComputeState[1] && !
d->
tess.vertexComputeState[2]
4419 && !
d->
tess.tessControlComputeState)
4433 d->
tess.vertexComputeState = {};
4434 d->
tess.tessControlComputeState = nil;
4438 rhiD->d->releaseQueue.append(e);
4439 rhiD->unregisterResource(
this);
4447 return MTLVertexFormatFloat4;
4449 return MTLVertexFormatFloat3;
4451 return MTLVertexFormatFloat2;
4453 return MTLVertexFormatFloat;
4455 return MTLVertexFormatUChar4Normalized;
4457 return MTLVertexFormatUChar2Normalized;
4459 return MTLVertexFormatUCharNormalized;
4461 return MTLVertexFormatUInt4;
4463 return MTLVertexFormatUInt3;
4465 return MTLVertexFormatUInt2;
4467 return MTLVertexFormatUInt;
4469 return MTLVertexFormatInt4;
4471 return MTLVertexFormatInt3;
4473 return MTLVertexFormatInt2;
4475 return MTLVertexFormatInt;
4477 return MTLVertexFormatHalf4;
4479 return MTLVertexFormatHalf3;
4481 return MTLVertexFormatHalf2;
4483 return MTLVertexFormatHalf;
4485 return MTLVertexFormatUShort4;
4487 return MTLVertexFormatUShort3;
4489 return MTLVertexFormatUShort2;
4491 return MTLVertexFormatUShort;
4493 return MTLVertexFormatShort4;
4495 return MTLVertexFormatShort3;
4497 return MTLVertexFormatShort2;
4499 return MTLVertexFormatShort;
4502 return MTLVertexFormatFloat4;
4510 return MTLBlendFactorZero;
4512 return MTLBlendFactorOne;
4514 return MTLBlendFactorSourceColor;
4516 return MTLBlendFactorOneMinusSourceColor;
4518 return MTLBlendFactorDestinationColor;
4520 return MTLBlendFactorOneMinusDestinationColor;
4522 return MTLBlendFactorSourceAlpha;
4524 return MTLBlendFactorOneMinusSourceAlpha;
4526 return MTLBlendFactorDestinationAlpha;
4528 return MTLBlendFactorOneMinusDestinationAlpha;
4530 return MTLBlendFactorBlendColor;
4532 return MTLBlendFactorBlendAlpha;
4534 return MTLBlendFactorOneMinusBlendColor;
4536 return MTLBlendFactorOneMinusBlendAlpha;
4538 return MTLBlendFactorSourceAlphaSaturated;
4540 return MTLBlendFactorSource1Color;
4542 return MTLBlendFactorOneMinusSource1Color;
4544 return MTLBlendFactorSource1Alpha;
4546 return MTLBlendFactorOneMinusSource1Alpha;
4549 return MTLBlendFactorZero;
4557 return MTLBlendOperationAdd;
4559 return MTLBlendOperationSubtract;
4561 return MTLBlendOperationReverseSubtract;
4563 return MTLBlendOperationMin;
4565 return MTLBlendOperationMax;
4568 return MTLBlendOperationAdd;
4576 f |= MTLColorWriteMaskRed;
4578 f |= MTLColorWriteMaskGreen;
4580 f |= MTLColorWriteMaskBlue;
4582 f |= MTLColorWriteMaskAlpha;
4590 return MTLCompareFunctionNever;
4592 return MTLCompareFunctionLess;
4594 return MTLCompareFunctionEqual;
4596 return MTLCompareFunctionLessEqual;
4598 return MTLCompareFunctionGreater;
4600 return MTLCompareFunctionNotEqual;
4602 return MTLCompareFunctionGreaterEqual;
4604 return MTLCompareFunctionAlways;
4607 return MTLCompareFunctionAlways;
4615 return MTLStencilOperationZero;
4617 return MTLStencilOperationKeep;
4619 return MTLStencilOperationReplace;
4621 return MTLStencilOperationIncrementClamp;
4623 return MTLStencilOperationDecrementClamp;
4625 return MTLStencilOperationInvert;
4627 return MTLStencilOperationIncrementWrap;
4629 return MTLStencilOperationDecrementWrap;
4632 return MTLStencilOperationKeep;
4640 return MTLPrimitiveTypeTriangle;
4642 return MTLPrimitiveTypeTriangleStrip;
4644 return MTLPrimitiveTypeLine;
4646 return MTLPrimitiveTypeLineStrip;
4648 return MTLPrimitiveTypePoint;
4651 return MTLPrimitiveTypeTriangle;
4661 return MTLPrimitiveTopologyClassTriangle;
4664 return MTLPrimitiveTopologyClassLine;
4666 return MTLPrimitiveTopologyClassPoint;
4669 return MTLPrimitiveTopologyClassTriangle;
4677 return MTLCullModeNone;
4679 return MTLCullModeFront;
4681 return MTLCullModeBack;
4684 return MTLCullModeNone;
4692 return MTLTriangleFillModeFill;
4694 return MTLTriangleFillModeLines;
4697 return MTLTriangleFillModeFill;
4705 return MTLWindingClockwise;
4707 return MTLWindingCounterClockwise;
4710 return MTLWindingCounterClockwise;
4718 return MTLTessellationPartitionModePow2;
4720 return MTLTessellationPartitionModeFractionalEven;
4722 return MTLTessellationPartitionModeFractionalOdd;
4725 return MTLTessellationPartitionModePow2;
4732 return MTLLanguageVersion(((
v / 10) << 16) + (
v % 10));
4738 QVarLengthArray<int, 8> versions;
4739 if (@available(macOS 13,
iOS 16, *))
4741 if (@available(macOS 12,
iOS 15, *))
4743 if (@available(macOS 11,
iOS 14, *))
4745 if (@available(macOS 10.15,
iOS 13, *))
4747 if (@available(macOS 10.14,
iOS 12, *))
4749 versions << 20 << 12;
4751 const QList<QShaderKey>
shaders =
shader.availableShaders();
4755 for (
const int &version : versions) {
4762 if (!mtllib.shader().isEmpty()) {
4763 dispatch_data_t
data = dispatch_data_create(mtllib.shader().constData(),
4764 size_t(mtllib.shader().size()),
4765 dispatch_get_global_queue(0, 0),
4766 DISPATCH_DATA_DESTRUCTOR_DEFAULT);
4768 id<MTLLibrary> lib = [
dev newLibraryWithData:
data error: &err];
4769 dispatch_release(
data);
4771 *entryPoint = mtllib.entryPoint();
4775 const QString msg = QString::fromNSString(err.localizedDescription);
4780 for (
const int &version : versions) {
4787 if (mslSource.shader().isEmpty()) {
4788 qWarning() <<
"No MSL 2.0 or 1.2 code found in baked shader" <<
shader;
4792 NSString *
src = [NSString stringWithUTF8String: mslSource.shader().constData()];
4793 MTLCompileOptions *opts = [[MTLCompileOptions alloc]
init];
4796 id<MTLLibrary> lib = [
dev newLibraryWithSource:
src options: opts
error: &err];
4804 const QString msg = QString::fromNSString(err.localizedDescription);
4809 *entryPoint = mslSource.entryPoint();
4816 return [lib newFunctionWithName:[NSString stringWithUTF8String:entryPoint.
constData()]];
4821 MTLRenderPipelineDescriptor *rpDesc =
reinterpret_cast<MTLRenderPipelineDescriptor *
>(metalRpDesc);
4823 if (rpD->colorAttachmentCount) {
4825 rpDesc.colorAttachments[0].pixelFormat = MTLPixelFormat(rpD->colorFormat[0]);
4826 rpDesc.colorAttachments[0].writeMask = MTLColorWriteMaskAll;
4827 rpDesc.colorAttachments[0].blendingEnabled =
false;
4830 || (
m_targetBlends.isEmpty() && rpD->colorAttachmentCount == 1));
4834 rpDesc.colorAttachments[
i].pixelFormat = MTLPixelFormat(rpD->colorFormat[
i]);
4835 rpDesc.colorAttachments[
i].blendingEnabled =
b.enable;
4841 rpDesc.colorAttachments[
i].alphaBlendOperation =
toMetalBlendOp(
b.opAlpha);
4846 if (rpD->hasDepthStencil) {
4849 MTLPixelFormat
fmt = MTLPixelFormat(rpD->dsFormat);
4850 rpDesc.depthAttachmentPixelFormat =
fmt;
4851#if defined(Q_OS_MACOS)
4852 if (
fmt != MTLPixelFormatDepth16Unorm &&
fmt != MTLPixelFormatDepth32Float)
4854 if (
fmt != MTLPixelFormatDepth32Float)
4856 rpDesc.stencilAttachmentPixelFormat =
fmt;
4865 MTLDepthStencilDescriptor *dsDesc =
reinterpret_cast<MTLDepthStencilDescriptor *
>(metalDsDesc);
4870 dsDesc.frontFaceStencil = [[MTLStencilDescriptor alloc]
init];
4878 dsDesc.backFaceStencil = [[MTLStencilDescriptor alloc]
init];
4909 desc.attributes[loc].offset =
NSUInteger(
it->offset());
4910 desc.attributes[loc].bufferIndex =
NSUInteger(firstVertexBinding +
it->binding());
4913 const NSUInteger viewCount = qMax<NSUInteger>(1,
q->multiViewCount());
4918 desc.layouts[layoutIdx].stepFunction =
4920 ? MTLVertexStepFunctionPerInstance : MTLVertexStepFunctionPerVertex;
4921 desc.layouts[layoutIdx].stepRate =
NSUInteger(
it->instanceStepRate());
4922 if (desc.layouts[layoutIdx].stepFunction == MTLVertexStepFunctionPerInstance)
4923 desc.layouts[layoutIdx].stepRate *= viewCount;
4924 desc.layouts[layoutIdx].stride =
it->stride();
4940 desc.attributes[loc].offset =
NSUInteger(
it->offset());
4941 desc.attributes[loc].bufferIndex =
NSUInteger(firstVertexBinding +
it->binding());
4948 if (desc.indexBufferIndex) {
4949 desc.layouts[layoutIdx].stepFunction =
4951 ? MTLStepFunctionThreadPositionInGridY : MTLStepFunctionThreadPositionInGridXIndexed;
4953 desc.layouts[layoutIdx].stepFunction =
4955 ? MTLStepFunctionThreadPositionInGridY : MTLStepFunctionThreadPositionInGridX;
4957 desc.layouts[layoutIdx].stepRate =
NSUInteger(
it->instanceStepRate());
4958 desc.layouts[layoutIdx].stride =
it->stride();
4964 if (@available(macOS 11.0,
iOS 14.0, *)) {
4966 NSArray *binArchArray = [NSArray arrayWithObjects: binArch, nil];
4967 rpDesc.binaryArchives = binArchArray;
4974 if (@available(macOS 11.0,
iOS 14.0, *)) {
4977 if (![binArch addRenderPipelineFunctionsWithDescriptor: rpDesc
error: &err]) {
4978 const QString msg = QString::fromNSString(err.localizedDescription);
4979 qWarning(
"Failed to collect render pipeline functions to binary archive: %s",
qPrintable(msg));
4989 MTLVertexDescriptor *vertexDesc = [MTLVertexDescriptor vertexDescriptor];
4992 MTLRenderPipelineDescriptor *rpDesc = [[MTLRenderPipelineDescriptor alloc]
init];
4993 rpDesc.vertexDescriptor = vertexDesc;
5002 auto cacheIt = rhiD->d->shaderCache.constFind(shaderStage);
5003 if (cacheIt != rhiD->d->shaderCache.constEnd()) {
5004 switch (shaderStage.type()) {
5009 rpDesc.vertexFunction =
d->
vs.
func;
5015 rpDesc.fragmentFunction =
d->
fs.
func;
5025 id<MTLLibrary> lib = rhiD->d->createMetalLib(
shader, shaderStage.shaderVariant(),
5026 &
error, &entryPoint, &activeKey);
5031 id<MTLFunction>
func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
5041 rhiD->d->shaderCache.clear();
5043 switch (shaderStage.type()) {
5050 rhiD->d->shaderCache.insert(shaderStage,
d->
vs);
5053 rpDesc.vertexFunction =
func;
5061 rhiD->d->shaderCache.insert(shaderStage,
d->
fs);
5064 rpDesc.fragmentFunction =
func;
5080 rhiD->d->trySeedingRenderPipelineFromBinaryArchive(rpDesc);
5083 rhiD->d->addRenderPipelineToBinaryArchive(rpDesc);
5086 d->
ps = [rhiD->d->dev newRenderPipelineStateWithDescriptor: rpDesc
error: &err];
5089 const QString msg = QString::fromNSString(err.localizedDescription);
5094 MTLDepthStencilDescriptor *dsDesc = [[MTLDepthStencilDescriptor alloc]
init];
5096 d->
ds = [rhiD->d->dev newDepthStencilStateWithDescriptor: dsDesc];
5107 switch (vertexCompVariant) {
5122 const int varIndex = vsCompVariantToIndex(vertexCompVariant);
5123 if (varIndex >= 0 && vertexComputeState[varIndex])
5124 return vertexComputeState[varIndex];
5126 id<MTLFunction>
func = nil;
5128 func = compVs[varIndex].func;
5131 qWarning(
"No compute function found for vertex shader translated for tessellation, this should not happen");
5135 const QMap<int, int> &ebb(compVs[varIndex].nativeShaderInfo.extraBufferBindings);
5138 MTLComputePipelineDescriptor *cpDesc = [MTLComputePipelineDescriptor
new];
5139 cpDesc.computeFunction =
func;
5140 cpDesc.threadGroupSizeIsMultipleOfThreadExecutionWidth = YES;
5141 cpDesc.stageInputDescriptor = [MTLStageInputOutputDescriptor stageInputOutputDescriptor];
5142 if (indexBufferBinding >= 0) {
5144 cpDesc.stageInputDescriptor.indexType = MTLIndexTypeUInt32;
5145 cpDesc.stageInputDescriptor.indexBufferIndex = indexBufferBinding;
5147 cpDesc.stageInputDescriptor.indexType = MTLIndexTypeUInt16;
5148 cpDesc.stageInputDescriptor.indexBufferIndex = indexBufferBinding;
5151 q->setupStageInputDescriptor(cpDesc.stageInputDescriptor);
5153 rhiD->d->trySeedingComputePipelineFromBinaryArchive(cpDesc);
5156 rhiD->d->addComputePipelineToBinaryArchive(cpDesc);
5159 id<MTLComputePipelineState>
ps = [rhiD->d->dev newComputePipelineStateWithDescriptor: cpDesc
5160 options: MTLPipelineOptionNone
5165 const QString msg = QString::fromNSString(err.localizedDescription);
5168 vertexComputeState[varIndex] =
ps;
5176 if (tessControlComputeState)
5177 return tessControlComputeState;
5179 MTLComputePipelineDescriptor *cpDesc = [MTLComputePipelineDescriptor
new];
5180 cpDesc.computeFunction = compTesc.func;
5182 rhiD->d->trySeedingComputePipelineFromBinaryArchive(cpDesc);
5185 rhiD->d->addComputePipelineToBinaryArchive(cpDesc);
5188 id<MTLComputePipelineState>
ps = [rhiD->d->dev newComputePipelineStateWithDescriptor: cpDesc
5189 options: MTLPipelineOptionNone
5194 const QString msg = QString::fromNSString(err.localizedDescription);
5197 tessControlComputeState =
ps;
5219 static const int maxVertexAttributes = 31;
5226 Q_UNREACHABLE_RETURN(-1);
5239 for (
const int dim :
variable.arrayDims)
5243 for (
int element = 0; element <
elements; ++element) {
5244 for (
const auto &member :
variable.structMembers) {
5254 vertexAlignment = std::max(vertexAlignment,
alignment);
5256 for (
int element = 0; element <
elements; ++element) {
5269 for (
const int dim :
variable.arrayDims)
5273 for (
int element = 0; element <
elements; ++element) {
5274 for (
const auto &member :
variable.structMembers) {
5284 vertexAlignment = std::max(vertexAlignment,
alignment);
5286 for (
int element = 0; element <
elements; ++element) {
5292 attributes[
index].bufferIndex = binding;
5306static inline bool matches(
const QList<QShaderDescription::BlockVariable> &
a,
const QList<QShaderDescription::BlockVariable> &
b)
5308 if (
a.size() ==
b.size()) {
5310 for (
int i = 0;
i <
a.size() &&
match; ++
i) {
5312 &&
a[
i].arrayDims ==
b[
i].arrayDims
5313 &&
matches(
a[
i].structMembers,
b[
i].structMembers);
5323 return a.location ==
b.location
5325 &&
a.perPatch ==
b.perPatch
5326 &&
matches(
a.structMembers,
b.structMembers);
5375 if (pipeline->
d->
ps)
5376 return pipeline->
d->
ps;
5378 MTLRenderPipelineDescriptor *rpDesc = [[MTLRenderPipelineDescriptor alloc]
init];
5379 MTLVertexDescriptor *vertexDesc = [MTLVertexDescriptor vertexDescriptor];
5382 const QMap<int, int> &ebb(compTesc.nativeShaderInfo.extraBufferBindings);
5386 quint32 offsetInTescOutput = 0;
5387 quint32 offsetInTescPatchOutput = 0;
5388 quint32 offsetInTessFactorBuffer = 0;
5389 quint32 tescOutputAlignment = 0;
5390 quint32 tescPatchOutputAlignment = 0;
5391 quint32 tessFactorAlignment = 0;
5392 QSet<int> usedBuffers;
5395 QMap<int, QShaderDescription::InOutVariable> tescOutVars;
5396 for (
const auto &tescOutVar : compTesc.desc.outputVariables())
5397 tescOutVars[tescOutVar.location] = tescOutVar;
5400 QMap<int, QShaderDescription::InOutVariable> teseInVars;
5401 for (
const auto &teseInVar : vertTese.desc.inputVariables())
5402 teseInVars[teseInVar.location] = teseInVar;
5409 int index = tescOutVar.location;
5414 if (tescOutVar.perPatch) {
5415 binding = tescPatchOutputBufferBinding;
5416 offset = &offsetInTescPatchOutput;
5419 tescOutVar.arrayDims.removeLast();
5420 binding = tescOutputBufferBinding;
5421 offset = &offsetInTescOutput;
5425 if (teseInVars.contains(
index)) {
5428 qWarning() <<
"mismatched tessellation control output -> tesssellation evaluation input at location" <<
index;
5429 qWarning() <<
" tesc out:" << tescOutVar;
5433 if (binding != -1) {
5435 usedBuffers << binding;
5437 qWarning() <<
"baked tessellation control shader missing output buffer binding information";
5442 qWarning() <<
"missing tessellation evaluation input for tessellation control output:" << tescOutVar;
5446 teseInVars.remove(tescOutVar.location);
5450 qWarning() <<
"missing tessellation control output for tessellation evaluation input:" << teseInVar;
5453 QMap<QShaderDescription::BuiltinType, QShaderDescription::BuiltinVariable> tescOutBuiltins;
5454 for (
const auto &tescOutBuiltin : compTesc.desc.outputBuiltinVariables())
5455 tescOutBuiltins[tescOutBuiltin.type] = tescOutBuiltin;
5458 QMap<QShaderDescription::BuiltinType, QShaderDescription::BuiltinVariable> teseInBuiltins;
5459 for (
const auto &teseInBuiltin : vertTese.desc.inputBuiltinVariables())
5460 teseInBuiltins[teseInBuiltin.type] = teseInBuiltin;
5463 bool tessLevelAdded =
false;
5472 switch (builtin.type) {
5475 binding = tescOutputBufferBinding;
5476 offset = &offsetInTescOutput;
5481 binding = tescOutputBufferBinding;
5482 offset = &offsetInTescOutput;
5487 variable.arrayDims = builtin.arrayDims;
5488 binding = tescOutputBufferBinding;
5489 offset = &offsetInTescOutput;
5494 binding = tessFactorBufferBinding;
5495 offset = &offsetInTessFactorBuffer;
5496 tessLevelAdded = trianglesMode;
5500 if (trianglesMode) {
5501 if (!tessLevelAdded) {
5503 binding = tessFactorBufferBinding;
5504 offsetInTessFactorBuffer = 0;
5505 offset = &offsetInTessFactorBuffer;
5507 tessLevelAdded =
true;
5509 teseInBuiltins.remove(builtin.type);
5514 binding = tessFactorBufferBinding;
5515 offsetInTessFactorBuffer = 8;
5516 offset = &offsetInTessFactorBuffer;
5525 if (teseInBuiltins.contains(builtin.type)) {
5526 if (binding != -1) {
5529 usedBuffers << binding;
5531 qWarning() <<
"baked tessellation control shader missing output buffer binding information";
5538 teseInBuiltins.remove(builtin.type);
5542 switch (builtin.type) {
5546 qWarning() <<
"missing tessellation control output for tessellation evaluation builtin input:" << builtin;
5553 if (usedBuffers.contains(tescOutputBufferBinding)) {
5554 vertexDesc.layouts[tescOutputBufferBinding].stepFunction = MTLVertexStepFunctionPerPatchControlPoint;
5555 vertexDesc.layouts[tescOutputBufferBinding].stride =
aligned(offsetInTescOutput, tescOutputAlignment);
5558 if (usedBuffers.contains(tescPatchOutputBufferBinding)) {
5559 vertexDesc.layouts[tescPatchOutputBufferBinding].stepFunction = MTLVertexStepFunctionPerPatch;
5560 vertexDesc.layouts[tescPatchOutputBufferBinding].stride =
aligned(offsetInTescPatchOutput, tescPatchOutputAlignment);
5563 if (usedBuffers.contains(tessFactorBufferBinding)) {
5564 vertexDesc.layouts[tessFactorBufferBinding].stepFunction = MTLVertexStepFunctionPerPatch;
5565 vertexDesc.layouts[tessFactorBufferBinding].stride = trianglesMode ?
sizeof(MTLTriangleTessellationFactorsHalf) :
sizeof(MTLQuadTessellationFactorsHalf);
5568 rpDesc.vertexDescriptor = vertexDesc;
5569 rpDesc.vertexFunction = vertTese.func;
5570 rpDesc.fragmentFunction = pipeline->
d->
fs.
func;
5583 rhiD->d->trySeedingRenderPipelineFromBinaryArchive(rpDesc);
5586 rhiD->d->addRenderPipelineToBinaryArchive(rpDesc);
5589 id<MTLRenderPipelineState>
ps = [rhiD->d->dev newRenderPipelineStateWithDescriptor: rpDesc
error: &err];
5592 const QString msg = QString::fromNSString(err.localizedDescription);
5593 qWarning(
"Failed to create render pipeline state for tessellation: %s",
qPrintable(msg));
5597 pipeline->
d->
ps =
ps;
5604 QVector<QMetalBuffer *> *workBuffers =
type == WorkBufType::DeviceLocal ? &deviceLocalWorkBuffers : &hostVisibleWorkBuffers;
5608 if (workBuf && workBuf->lastActiveFrameSlot == -1 && workBuf->size() >=
size) {
5618 if (workBuf && workBuf->lastActiveFrameSlot == -1) {
5619 workBuf->setSize(
size);
5620 if (workBuf->create()) {
5621 workBuf->lastActiveFrameSlot = rhiD->currentFrameSlot;
5630 if (
type == WorkBufType::DeviceLocal) {
5637 if (
buf->create()) {
5638 buf->lastActiveFrameSlot = rhiD->currentFrameSlot;
5639 workBuffers->append(
buf);
5643 qWarning(
"Failed to acquire work buffer of size %u",
size);
5656 d->tess.inControlPointCount =
uint(m_patchControlPointCount);
5657 d->tess.outControlPointCount = tescDesc.tessellationOutputVertexCount();
5658 if (!
d->tess.outControlPointCount)
5659 d->tess.outControlPointCount = teseDesc.tessellationOutputVertexCount();
5661 if (!
d->tess.outControlPointCount) {
5662 qWarning(
"Failed to determine output vertex count from the tessellation control or evaluation shader, cannot tessellate");
5663 d->tess.enabled =
false;
5664 d->tess.failed =
true;
5668 if (m_multiViewCount >= 2)
5669 qWarning(
"Multiview is not supported with tessellation");
5677 bool variantsPresent[3] = {};
5678 const QVector<QShaderKey> tessVertKeys = tessVert.availableShaders();
5680 switch (k.sourceVariant()) {
5682 variantsPresent[0] =
true;
5685 variantsPresent[1] =
true;
5688 variantsPresent[2] =
true;
5694 if (!(variantsPresent[0] && variantsPresent[1] && variantsPresent[2])) {
5695 qWarning(
"Vertex shader is not prepared for Metal tessellation. Cannot tessellate. "
5696 "Perhaps the relevant variants (UInt32IndexedVertexAsComputeShader et al) were not generated? "
5697 "Try passing --msltess to qsb.");
5698 d->tess.enabled =
false;
5699 d->tess.failed =
true;
5709 id<MTLLibrary> lib = rhiD->d->createMetalLib(tessVert,
variant, &
error, &entryPoint, &activeKey);
5712 d->tess.enabled =
false;
5713 d->tess.failed =
true;
5716 id<MTLFunction>
func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
5720 d->tess.enabled =
false;
5721 d->tess.failed =
true;
5727 compVs.
desc = tessVert.description();
5732 if (!
d->tess.vsCompPipeline(rhiD,
variant)) {
5733 qWarning(
"Failed to pre-generate compute pipeline for vertex compute shader (tessellation variant %d)",
int(
variant));
5734 d->tess.enabled =
false;
5735 d->tess.failed =
true;
5744 if (!tessControlLib) {
5746 d->tess.enabled =
false;
5747 d->tess.failed =
true;
5750 id<MTLFunction> tessControlFunc = rhiD->d->createMSLShaderFunction(tessControlLib, entryPoint);
5751 if (!tessControlFunc) {
5754 d->tess.enabled =
false;
5755 d->tess.failed =
true;
5758 d->tess.compTesc.lib = tessControlLib;
5759 d->tess.compTesc.func = tessControlFunc;
5760 d->tess.compTesc.desc = tesc.description();
5761 d->tess.compTesc.nativeResourceBindingMap = tesc.nativeResourceBindingMap(activeKey);
5762 d->tess.compTesc.nativeShaderInfo = tesc.nativeShaderInfo(activeKey);
5763 if (!
d->tess.tescCompPipeline(rhiD)) {
5764 qWarning(
"Failed to pre-generate compute pipeline for tessellation control shader");
5765 d->tess.enabled =
false;
5766 d->tess.failed =
true;
5774 d->tess.enabled =
false;
5775 d->tess.failed =
true;
5778 id<MTLFunction> tessEvalFunc = rhiD->d->createMSLShaderFunction(tessEvalLib, entryPoint);
5779 if (!tessEvalFunc) {
5782 d->tess.enabled =
false;
5783 d->tess.failed =
true;
5786 d->tess.vertTese.lib = tessEvalLib;
5787 d->tess.vertTese.func = tessEvalFunc;
5788 d->tess.vertTese.desc = tese.description();
5789 d->tess.vertTese.nativeResourceBindingMap = tese.nativeResourceBindingMap(activeKey);
5790 d->tess.vertTese.nativeShaderInfo = tese.nativeShaderInfo(activeKey);
5795 d->tess.enabled =
false;
5796 d->tess.failed =
true;
5799 id<MTLFunction> fragFunc = rhiD->d->createMSLShaderFunction(fragLib, entryPoint);
5803 d->tess.enabled =
false;
5804 d->tess.failed =
true;
5807 d->fs.lib = fragLib;
5808 d->fs.func = fragFunc;
5809 d->fs.desc = tessFrag.description();
5810 d->fs.nativeShaderInfo = tessFrag.nativeShaderInfo(activeKey);
5811 d->fs.nativeResourceBindingMap = tessFrag.nativeResourceBindingMap(activeKey);
5813 if (!
d->tess.teseFragRenderPipeline(rhiD,
this)) {
5814 qWarning(
"Failed to pre-generate render pipeline for tessellation evaluation + fragment shader");
5815 d->tess.enabled =
false;
5816 d->tess.failed =
true;
5820 MTLDepthStencilDescriptor *dsDesc = [[MTLDepthStencilDescriptor alloc]
init];
5821 setupMetalDepthStencilDescriptor(dsDesc);
5822 d->ds = [rhiD->d->dev newDepthStencilStateWithDescriptor: dsDesc];
5836 rhiD->pipelineCreationStart();
5837 if (!rhiD->sanityCheckGraphicsPipeline(
this))
5845 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
5846 switch (shaderStage.type()) {
5848 tessVert = shaderStage.
shader();
5851 tesc = shaderStage.
shader();
5854 tese = shaderStage.shader();
5857 tessFrag = shaderStage.shader();
5863 d->tess.enabled = tesc.isValid() && tese.isValid() && m_topology == Patches && m_patchControlPointCount > 0;
5864 d->tess.failed =
false;
5866 bool ok =
d->tess.enabled ? createTessellationPipelines(tessVert, tesc, tese, tessFrag) : createVertexFragmentPipeline();
5872 QVarLengthArray<QMetalShader *, 6>
shaders;
5873 if (
d->tess.enabled) {
5874 shaders.append(&
d->tess.compVs[0]);
5875 shaders.append(&
d->tess.compVs[1]);
5876 shaders.append(&
d->tess.compVs[2]);
5888 int maxNativeBinding = 0;
5890 maxNativeBinding =
qMax(maxNativeBinding,
shader->nativeResourceBindingMap[block.binding].first);
5894 buffers += ((maxNativeBinding + 1 + 7) / 8) * 8;
5899 if (!
d->bufferSizeBuffer)
5902 d->bufferSizeBuffer->setSize(
buffers *
sizeof(
int));
5903 d->bufferSizeBuffer->create();
5906 rhiD->pipelineCreationEnd();
5907 lastActiveFrameSlot = -1;
5909 rhiD->registerResource(
this);
5943 rhiD->d->releaseQueue.append(e);
5944 rhiD->unregisterResource(
this);
5950 if (@available(macOS 11.0,
iOS 14.0, *)) {
5952 NSArray *binArchArray = [NSArray arrayWithObjects: binArch, nil];
5953 cpDesc.binaryArchives = binArchArray;
5960 if (@available(macOS 11.0,
iOS 14.0, *)) {
5963 if (![binArch addComputePipelineFunctionsWithDescriptor: cpDesc
error: &err]) {
5964 const QString msg = QString::fromNSString(err.localizedDescription);
5965 qWarning(
"Failed to collect compute pipeline functions to binary archive: %s",
qPrintable(msg));
5977 rhiD->pipelineCreationStart();
5979 auto cacheIt = rhiD->d->shaderCache.constFind(
m_shaderStage);
5980 if (cacheIt != rhiD->d->shaderCache.constEnd()) {
5988 &
error, &entryPoint, &activeKey);
5993 id<MTLFunction>
func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
6015 rhiD->d->shaderCache.clear();
6025 MTLComputePipelineDescriptor *cpDesc = [MTLComputePipelineDescriptor
new];
6026 cpDesc.computeFunction =
d->
cs.
func;
6028 rhiD->d->trySeedingComputePipelineFromBinaryArchive(cpDesc);
6031 rhiD->d->addComputePipelineToBinaryArchive(cpDesc);
6034 d->
ps = [rhiD->d->dev newComputePipelineStateWithDescriptor: cpDesc
6035 options: MTLPipelineOptionNone
6040 const QString msg = QString::fromNSString(err.localizedDescription);
6060 rhiD->pipelineCreationEnd();
6063 rhiD->registerResource(
this);
6135 rtWrapper(rhi,
this),
6140 d->
sem[
i] =
nullptr;
6161 dispatch_release(
d->
sem[
i]);
6162 d->
sem[
i] =
nullptr;
6172 d->liveResizeStartObserver.remove();
6173 d->liveResizeEndObserver.remove();
6174 d->liveResizeObserverSet =
false;
6185 rhiD->swapchains.remove(
this);
6186 rhiD->unregisterResource(
this);
6207 NSView *
view =
reinterpret_cast<NSView *
>(
window->winId());
6209 UIView *
view =
reinterpret_cast<UIView *
>(
window->winId());
6212 return static_cast<CAMetalLayer *
>(
view.layer);
6243 if (@available(macOS 10.11,
iOS 16.0, *))
6244 return hdrInfo().limits.colorComponentValue.maxPotentialColorComponentValue > 1.0f;
6248 if (@available(macOS 11.0,
iOS 14.0, *))
6249 return hdrInfo().limits.colorComponentValue.maxPotentialColorComponentValue > 1.0f;
6263 rpD->colorAttachmentCount = 1;
6270 rpD->dsFormat = rhiD->d->dev.depth24Stencil8PixelFormatSupported
6271 ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8;
6273 rpD->dsFormat = MTLPixelFormatDepth32Float_Stencil8;
6276 rpD->updateSerializedFormat();
6278 rhiD->registerResource(rpD,
false);
6302 dispatch_semaphore_t
sem =
d->
sem[slot];
6303 dispatch_semaphore_wait(
sem, DISPATCH_TIME_FOREVER);
6304 dispatch_semaphore_signal(
sem);
6318 if (needsRegistration)
6319 rhiD->swapchains.insert(
this);
6324 qWarning(
"QMetalSwapChain only supports MetalSurface windows");
6336 if (@available(macOS 10.11,
iOS 16.0, *)) {
6337 d->
layer.colorspace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedLinearSRGB);
6338 d->
layer.wantsExtendedDynamicRangeContent = YES;
6341 if (@available(macOS 11.0,
iOS 16.0, *)) {
6342 d->
layer.colorspace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedLinearDisplayP3);
6343 d->
layer.wantsExtendedDynamicRangeContent = YES;
6348 d->
layer.framebufferOnly = NO;
6352 d->
layer.displaySyncEnabled = NO;
6373 const float scaleFactor =
d->
layer.contentsScale;
6374 layerSize.width *= scaleFactor;
6375 layerSize.height *= scaleFactor;
6376 d->
layer.drawableSize = layerSize;
6381 [
d->
layer setDevice: rhiD->d->dev];
6389 const bool canUsePresentsWithTransaction = NSThread.isMainThread;
6395 if (allowPresentsWithTransaction && canUsePresentsWithTransaction && !
d->liveResizeObserverSet) {
6396 d->liveResizeObserverSet =
true;
6397 NSView *
view =
reinterpret_cast<NSView *
>(
window->winId());
6400 qCDebug(QRHI_LOG_INFO,
"will set presentsWithTransaction during live resize");
6402 d->
layer.presentsWithTransaction =
true;
6405 d->
layer.presentsWithTransaction =
false;
6425 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
6432 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
6435 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the layer size (%dx%d). Expect problems.",
6448 qCDebug(QRHI_LOG_INFO,
"got CAMetalLayer, pixel size %dx%d (scale %.2f)",
6452 MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc]
init];
6453 desc.textureType = MTLTextureType2DMultisample;
6458 desc.resourceOptions = MTLResourceStorageModePrivate;
6459 desc.storageMode = MTLStorageModePrivate;
6460 desc.usage = MTLTextureUsageRenderTarget;
6463 d->
msaaTex[
i] = [rhiD->d->dev newTextureWithDescriptor: desc];
6468 if (needsRegistration)
6469 rhiD->registerResource(
this);
6478 info.limits.colorComponentValue.maxColorComponentValue = 1;
6479 info.limits.colorComponentValue.maxPotentialColorComponentValue = 1;
6481 info.sdrWhiteLevel = 200;
6485#if defined(Q_OS_MACOS)
6486 NSView *
view =
reinterpret_cast<NSView *
>(
m_window->winId());
6488 info.limits.colorComponentValue.maxColorComponentValue =
screen.maximumExtendedDynamicRangeColorComponentValue;
6489 info.limits.colorComponentValue.maxPotentialColorComponentValue =
screen.maximumPotentialExtendedDynamicRangeColorComponentValue;
6490#elif defined(Q_OS_IOS)
6491 if (@available(
iOS 16.0, *)) {
6492 UIView *
view =
reinterpret_cast<UIView *
>(
m_window->winId());
6493 UIScreen *
screen =
view.window.windowScene.screen;
6494 info.limits.colorComponentValue.maxColorComponentValue =
view.window.windowScene.screen.currentEDRHeadroom;
6495 info.limits.colorComponentValue.maxPotentialColorComponentValue =
screen.potentialEDRHeadroom;
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
qsizetype length() const noexcept
Same as size().
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
The QColor class provides colors based on RGB, HSV or CMYK values.
QString absoluteFilePath() const
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
qsizetype sizeInBytes() const
bool isNull() const
Returns true if it is a null image, otherwise returns false.
bool contains(const Key &key) const
const_iterator cend() const
const_iterator constFind(const Key &key) const
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
static Q_CORE_EXPORT QOperatingSystemVersionBase current()
constexpr int majorVersion() const
constexpr int minorVersion() const
\inmodule QtCore\reentrant
constexpr bool isNull() const noexcept
Returns true if both the x and y coordinates are set to 0, otherwise returns false.
constexpr int x() const noexcept
Returns the x coordinate of this point.
constexpr int y() const noexcept
Returns the y coordinate of this point.
Type
Specifies storage type of buffer resource.
void setSize(quint32 sz)
Sets the size of the buffer in bytes.
QRhiRenderBuffer * renderBuffer() const
QRhiTexture * texture() const
void draw(quint32 vertexCount, quint32 instanceCount=1, quint32 firstVertex=0, quint32 firstInstance=0)
Records a non-indexed draw.
QPair< int, quint32 > DynamicOffset
Synonym for QPair<int, quint32>.
QPair< QRhiBuffer *, quint32 > VertexInput
Synonym for QPair<QRhiBuffer *, quint32>.
IndexFormat
Specifies the index data type.
QRhiShaderStage m_shaderStage
QRhiRenderPassDescriptor * m_renderPassDesc
quint32 m_stencilReadMask
BlendOp
Specifies the blend operation.
void setCullMode(CullMode mode)
Sets the specified face culling mode.
PolygonMode
Specifies the polygon rasterization mode.
BlendFactor
Specifies the blend factor.
StencilOpState m_stencilFront
quint32 m_stencilWriteMask
QRhiShaderResourceBindings * shaderResourceBindings() const
CompareOp
Specifies the depth or stencil comparison function.
CullMode
Specifies the culling mode.
QVarLengthArray< QRhiShaderStage, 4 > m_shaderStages
QRhiRenderPassDescriptor * renderPassDescriptor() const
QVarLengthArray< TargetBlend, 8 > m_targetBlends
PolygonMode m_polygonMode
float m_slopeScaledDepthBias
Topology
Specifies the primitive topology.
StencilOpState m_stencilBack
void setDepthBias(int bias)
Sets the depth bias.
StencilOp
Specifies the stencil operation.
bool isCompressedFormat(QRhiTexture::Format format) const
static const QRhiShaderResourceBinding::Data * shaderResourceBindingData(const QRhiShaderResourceBinding &binding)
quint32 pipelineCacheRhiId() const
void compressedFormatInfo(QRhiTexture::Format format, const QSize &size, quint32 *bpl, quint32 *byteSize, QSize *blockDim) const
static const int MAX_SHADER_CACHE_ENTRIES
static bool sortedBindingLessThan(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
qint64 totalPipelineCreationTime() const
void textureFormatInfo(QRhiTexture::Format format, const QSize &size, quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const
void setPixelSize(const QSize &sz)
Sets the size (in pixels) to sz.
QRhiTexture::Format m_backingFormatHint
Type
Specifies the type of the renderbuffer.
virtual bool create()=0
Creates the corresponding native graphics resources.
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Sets the QRhiRenderPassDescriptor desc for use with this render target.
virtual QSize pixelSize() const =0
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
virtual Type resourceType() const =0
QRhiImplementation * m_rhi
Filter
Specifies the minification, magnification, or mipmap filtering.
AddressMode
Specifies the addressing mode.
CompareOp
Specifies the texture comparison function.
std::array< int, 4 > scissor() const
static QRhiShaderResourceBinding bufferLoad(int binding, StageFlags stage, QRhiBuffer *buf)
StageFlag
Flag values to indicate which stages the shader resource is visible in.
@ TessellationEvaluationStage
@ TessellationControlStage
QVarLengthArray< QRhiShaderResourceBinding, BINDING_PREALLOC > m_bindings
QShader::Variant shaderVariant() const
QRhiSwapChainProxyData m_proxyData
@ SurfaceHasNonPreMulAlpha
QRhiRenderPassDescriptor * m_renderPassDesc
Format
Describes the swapchain format.
@ HDRExtendedDisplayP3Linear
QRhiRenderBuffer * m_depthStencil
const QRhiColorAttachment * cbeginColorAttachments() const
QRhiTexture * depthTexture() const
const QRhiColorAttachment * cendColorAttachments() const
QRhiRenderBuffer * depthStencilBuffer() const
const QRhiColorAttachment * colorAttachmentAt(qsizetype index) const
qsizetype colorAttachmentCount() const
QRhiTexture * depthResolveTexture() const
QRhiTextureRenderTargetDescription m_desc
@ DoNotStoreDepthStencilContents
@ PreserveDepthStencilContents
quint32 dataStride() const
QPoint sourceTopLeft() const
QPoint destinationTopLeft() const
Format
Specifies the texture format.
static constexpr int MAX_MIP_LEVELS
ResourceLimit
Describes the resource limit to query.
@ MaxThreadsPerThreadGroup
@ MaxThreadGroupsPerDimension
Feature
Flag values to indicate what features are supported by the backend currently in use.
@ NonDynamicUniformBuffers
@ RenderToNonBaseMipLevel
@ MultisampleRenderBuffer
@ PipelineCacheDataLoadSave
@ ReadBackNonUniformBuffer
@ RenderToOneDimensionalTexture
@ OneDimensionalTextureMipmaps
@ ReadBackNonBaseMipLevel
@ ThreeDimensionalTextureMipmaps
@ NonFourAlignedEffectiveIndexBufferOffset
@ ThreeDimensionalTextures
@ ReadBackAnyTextureFormat
FrameOpResult
Describes the result of operations that can have a soft failure.
@ EnablePipelineCacheDataSave
QByteArray shader() const
TessellationWindingOrder
\value UnknownTessellationWindingOrder \value CwTessellationWindingOrder \value CcwTessellationWindin...
@ CwTessellationWindingOrder
@ CcwTessellationWindingOrder
QList< StorageBlock > storageBlocks() const
@ TrianglesTessellationMode
TessellationPartitioning
\value UnknownTessellationPartitioning \value EqualTessellationPartitioning \value FractionalEvenTess...
@ EqualTessellationPartitioning
@ FractionalEvenTessellationPartitioning
@ FractionalOddTessellationPartitioning
QShaderCode shader(const QShaderKey &key) const
Variant
Describes what kind of shader code an entry contains.
@ UInt32IndexedVertexAsComputeShader
@ NonIndexedVertexAsComputeShader
@ UInt16IndexedVertexAsComputeShader
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
\macro QT_RESTRICTED_CAST_FROM_ASCII
QByteArray toUtf8() const &
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
const_iterator cbegin() const noexcept
const_iterator cend() const noexcept
iterator begin() noexcept
SurfaceType surfaceType() const override
Returns the surface type of the window.
QMap< QString, QString > map
[6]
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
Combined button and popup list for selecting options.
#define Q_STATIC_ASSERT(Condition)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError * error
static QString header(const QString &name)
static const qint64 headerSize
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLint GLint GLint GLint GLint x
[0]
GLuint const GLuint * buffers
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum GLuint GLint level
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLint GLint GLint GLsizei GLsizei GLsizei GLboolean commit
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLuint GLsizei const GLchar * label
[43]
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLuint GLintptr offset
GLint GLsizei GLsizei GLenum format
GLsizei GLenum const void * indices
GLfloat GLfloat GLfloat GLfloat h
GLuint GLsizei const GLuint const GLintptr * offsets
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
GLdouble GLdouble GLdouble GLdouble q
GLsizei GLsizei GLuint * shaders
GLfloat GLfloat GLfloat alpha
GLenum GLenum colorFormat
GLsizeiptr const void GLenum usage
QT_BEGIN_NAMESPACE constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
static QPair< int, int > mapBinding(int binding, int stageIndex, const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
Int aligned(Int v, Int byteAlign)
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define qPrintable(string)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
static const QTextHtmlElement elements[Html_NumElements]
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
unsigned long long quint64
QVideoFrameFormat::PixelFormat fmt
QUrl url("example.com")
[constructor-url-reference]
view viewport() -> scroll(dx, dy, deviceRect)
id< MTLTexture > viewForLevel(int level)
QMetalTextureData(QMetalTexture *t)
id< MTLBuffer > stagingBuf[QMTL_FRAMES_IN_FLIGHT]
id< MTLTexture > perLevelViews[QRhi::MAX_MIP_LEVELS]
~QMetalTextureRenderTarget()
float devicePixelRatio() const override
QMetalRenderTargetData * d
QMetalTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags)
bool create() override
Creates the corresponding native graphics resources.
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
int sampleCount() const override
QSize pixelSize() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, Flags flags)
bool prepareCreate(QSize *adjustedSize=nullptr)
NativeTexture nativeTexture() override
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
bool createFrom(NativeTexture src) override
Similar to create(), except that no new native textures are created.
QVarLengthArray< Batch, 4 > batches
struct QRhiMetalData::DeferredReleaseEntry::@352::@360 graphicsPipeline
id< MTLComputePipelineState > pipelineState
struct QRhiMetalData::DeferredReleaseEntry::@352::@361 computePipeline
id< MTLDepthStencilState > depthStencilState
struct QRhiMetalData::DeferredReleaseEntry::@352::@356 renderbuffer
std::array< id< MTLComputePipelineState >, 3 > tessVertexComputeState
id< MTLSamplerState > samplerState
struct QRhiMetalData::DeferredReleaseEntry::@352::@359 stagingBuffer
struct QRhiMetalData::DeferredReleaseEntry::@352::@355 buffer
id< MTLComputePipelineState > tessTessControlComputeState
id< MTLRenderPipelineState > pipelineState
struct QRhiMetalData::DeferredReleaseEntry::@352::@358 sampler
QRhiReadbackResult * result
QRhiReadbackDescription desc
QRhiTexture::Format format
\variable QRhiReadbackResult::completed
qint64 totalPipelineCreationTime
\variable QShaderDescription::StorageBlock::blockName
\variable QShaderDescription::PushConstantBlock::name
@ MslTessTescTessLevelBufferBinding
@ MslMultiViewMaskBufferBinding
@ MslTessTescInputBufferBinding
@ MslTessTescPatchOutputBufferBinding
@ MslBufferSizeBufferBinding
@ MslTessVertTescOutputBufferBinding
@ MslTessTescParamsBufferBinding
@ MslTessVertIndicesBufferBinding
QMap< int, int > extraBufferBindings