7#include <QGuiApplication>
11#include <QTemporaryFile>
14#include <QOperatingSystemVersion>
16#include <QtCore/private/qcore_mac_p.h>
17#include <QtGui/private/qmetallayer_p.h>
18#include <QtGui/qpa/qplatformwindow_p.h>
21#include <AppKit/AppKit.h>
23#include <UIKit/UIKit.h>
26#include <QuartzCore/CATransaction.h>
28#include <Metal/Metal.h>
35
36
37
38
39
40
41
42
43
46#error ARC not supported
55#define QRHI_METAL_DISABLE_BINARY_ARCHIVE
60#define QRHI_METAL_COMMAND_BUFFERS_WITH_UNRETAINED_REFERENCES
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
103
104
105
106
107
108
109
110
113
114
115
116
119
120
121
122
123
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
147
148
151
152
156 id<MTLLibrary> lib = nil;
157 id<MTLFunction> func = nil;
158 std::array<uint, 3> localSize = {};
159 uint outputVertexCount = 0;
160 QShaderDescription desc;
161 QShader::NativeResourceBindingMap nativeResourceBindingMap;
162 QShader::NativeShaderInfo nativeShaderInfo;
165 nativeResourceBindingMap.clear();
184 const QColor &colorClearValue,
185 const QRhiDepthStencilClearValue &depthStencilClearValue,
187 QRhiShadingRateMap *shadingRateMap);
189 QString *error, QByteArray *entryPoint, QShaderKey *activeKey);
218 id<MTLTexture> texture;
437 return vertexOrIndexCount * instanceCount *
sizeof(
float) * 60;
446 return patchCount *
sizeof(
float) * 128;
494 if (importDevice->dev) {
495 d->dev = (id<MTLDevice>) importDevice->dev;
497 if (importedCmdQueue)
498 d->cmdQueue = (id<MTLCommandQueue>) importDevice->cmdQueue;
500 qWarning(
"No MTLDevice given, cannot import");
514 return (v + byteAlign - 1) & ~(byteAlign - 1);
519 QMacAutoReleasePool pool;
522 id<MTLDevice> dev = MTLCreateSystemDefaultDevice();
536 return [cmdQueue commandBufferWithUnretainedReferences];
538 return [cmdQueue commandBuffer];
549 MTLBinaryArchiveDescriptor *binArchDesc = [MTLBinaryArchiveDescriptor
new];
550 binArchDesc.url = sourceFileUrl;
552 binArch = [dev newBinaryArchiveWithDescriptor: binArchDesc error: &err];
553 [binArchDesc release];
555 const QString msg = QString::fromNSString(err.localizedDescription);
556 qWarning(
"newBinaryArchiveWithDescriptor failed: %s", qPrintable(msg));
569 d->dev = MTLCreateSystemDefaultDevice();
572 qWarning(
"No MTLDevice");
576 const QString deviceName = QString::fromNSString([d->dev name]);
577 qCDebug(QRHI_LOG_INFO,
"Metal device: %s", qPrintable(deviceName));
578 driverInfoStruct.deviceName = deviceName.toUtf8();
585 const MTLDeviceLocation deviceLocation = [d->dev location];
586 switch (deviceLocation) {
587 case MTLDeviceLocationBuiltIn:
588 driverInfoStruct.deviceType = QRhiDriverInfo::IntegratedDevice;
590 case MTLDeviceLocationSlot:
591 driverInfoStruct.deviceType = QRhiDriverInfo::DiscreteDevice;
593 case MTLDeviceLocationExternal:
594 driverInfoStruct.deviceType = QRhiDriverInfo::ExternalDevice;
600 driverInfoStruct.deviceType = QRhiDriverInfo::IntegratedDevice;
603 const QOperatingSystemVersion ver = QOperatingSystemVersion::current();
604 osMajor = ver.majorVersion();
605 osMinor = ver.minorVersion();
607 if (importedCmdQueue)
608 [d->cmdQueue retain];
610 d->cmdQueue = [d->dev newCommandQueue];
612 d->captureMgr = [MTLCaptureManager sharedCaptureManager];
616 d->captureScope = [d->captureMgr newCaptureScopeWithCommandQueue: d->cmdQueue];
617 const QString label = QString::asprintf(
"Qt capture scope for QRhi %p",
this);
618 d->captureScope.label = label.toNSString();
620#if defined(Q_OS_MACOS) || defined(Q_OS_VISIONOS)
621 caps.maxTextureSize = 16384;
622 caps.baseVertexAndInstance =
true;
623 caps.isAppleGPU = [d->dev supportsFamily:MTLGPUFamilyApple7];
624 caps.maxThreadGroupSize = 1024;
625 caps.multiView =
true;
626#elif defined(Q_OS_TVOS)
627 if ([d->dev supportsFamily:MTLGPUFamilyApple3])
628 caps.maxTextureSize = 16384;
630 caps.maxTextureSize = 8192;
631 caps.baseVertexAndInstance =
false;
632 caps.isAppleGPU =
true;
633#elif defined(Q_OS_IOS)
634 if ([d->dev supportsFamily:MTLGPUFamilyApple3]) {
635 caps.maxTextureSize = 16384;
636 caps.baseVertexAndInstance =
true;
637 }
else if ([d->dev supportsFamily:MTLGPUFamilyApple2]) {
638 caps.maxTextureSize = 8192;
639 caps.baseVertexAndInstance =
false;
641 caps.maxTextureSize = 4096;
642 caps.baseVertexAndInstance =
false;
644 caps.isAppleGPU =
true;
645 if ([d->dev supportsFamily:MTLGPUFamilyApple4])
646 caps.maxThreadGroupSize = 1024;
647 if ([d->dev supportsFamily:MTLGPUFamilyApple5])
648 caps.multiView =
true;
651 caps.supportedSampleCounts = { 1 };
652 for (
int sampleCount : { 2, 4, 8 }) {
653 if ([d->dev supportsTextureSampleCount: sampleCount])
654 caps.supportedSampleCounts.append(sampleCount);
657 caps.shadingRateMap = [d->dev supportsRasterizationRateMapWithLayerCount: 1];
658 if (caps.shadingRateMap && caps.multiView)
659 caps.shadingRateMap = [d->dev supportsRasterizationRateMapWithLayerCount: 2];
662 caps.depthClamp = [d->dev supportsFamily:MTLGPUFamilyApple3];
664 if (rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
665 d->setupBinaryArchive();
667 nativeHandlesStruct.dev = (MTLDevice *) d->dev;
668 nativeHandlesStruct.cmdQueue = (MTLCommandQueue *) d->cmdQueue;
678 for (QMetalShader &s : d->shaderCache)
680 d->shaderCache.clear();
682 [d->captureScope release];
683 d->captureScope = nil;
685 [d->binArch release];
688 [d->cmdQueue release];
689 if (!importedCmdQueue)
699 return caps.supportedSampleCounts;
704 Q_UNUSED(sampleCount);
705 return { QSize(1, 1) };
710 return new QMetalSwapChain(
this);
713QRhiBuffer *
QRhiMetal::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
715 return new QMetalBuffer(
this, type, usage, size);
742 if (m.isIdentity()) {
744 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
745 0.0f, 1.0f, 0.0f, 0.0f,
746 0.0f, 0.0f, 0.5f, 0.5f,
747 0.0f, 0.0f, 0.0f, 1.0f);
756 bool supportsFamilyMac2 =
false;
757 bool supportsFamilyApple3 =
false;
760 supportsFamilyMac2 =
true;
762 supportsFamilyApple3 =
true;
764 supportsFamilyApple3 =
true;
768 if (format == QRhiTexture::BC5)
771 if (!supportsFamilyApple3) {
772 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8)
774 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12)
778 if (!supportsFamilyMac2)
779 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7)
788 case QRhi::MultisampleTexture:
790 case QRhi::MultisampleRenderBuffer:
792 case QRhi::DebugMarkers:
794 case QRhi::Timestamps:
796 case QRhi::Instancing:
798 case QRhi::CustomInstanceStepRate:
800 case QRhi::PrimitiveRestart:
802 case QRhi::NonDynamicUniformBuffers:
804 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
806 case QRhi::NPOTTextureRepeat:
808 case QRhi::RedOrAlpha8IsRed:
810 case QRhi::ElementIndexUint:
814 case QRhi::WideLines:
816 case QRhi::VertexShaderPointSize:
818 case QRhi::BaseVertex:
819 return caps.baseVertexAndInstance;
820 case QRhi::BaseInstance:
821 return caps.baseVertexAndInstance;
822 case QRhi::TriangleFanTopology:
824 case QRhi::ReadBackNonUniformBuffer:
826 case QRhi::ReadBackNonBaseMipLevel:
828 case QRhi::TexelFetch:
830 case QRhi::RenderToNonBaseMipLevel:
832 case QRhi::IntAttributes:
834 case QRhi::ScreenSpaceDerivatives:
836 case QRhi::ReadBackAnyTextureFormat:
838 case QRhi::PipelineCacheDataLoadSave:
840 case QRhi::ImageDataStride:
842 case QRhi::RenderBufferImport:
844 case QRhi::ThreeDimensionalTextures:
846 case QRhi::RenderTo3DTextureSlice:
848 case QRhi::TextureArrays:
850 case QRhi::Tessellation:
852 case QRhi::GeometryShader:
854 case QRhi::TextureArrayRange:
856 case QRhi::NonFillPolygonMode:
858 case QRhi::OneDimensionalTextures:
860 case QRhi::OneDimensionalTextureMipmaps:
862 case QRhi::HalfAttributes:
864 case QRhi::RenderToOneDimensionalTexture:
866 case QRhi::ThreeDimensionalTextureMipmaps:
868 case QRhi::MultiView:
869 return caps.multiView;
870 case QRhi::TextureViewFormat:
872 case QRhi::ResolveDepthStencil:
874 case QRhi::VariableRateShading:
876 case QRhi::VariableRateShadingMap:
877 return caps.shadingRateMap;
878 case QRhi::VariableRateShadingMapWithTexture:
880 case QRhi::PerRenderTargetBlending:
881 case QRhi::SampleVariables:
883 case QRhi::InstanceIndexIncludesBaseInstance:
885 case QRhi::DepthClamp:
886 return caps.depthClamp;
887 case QRhi::DrawIndirect:
889 case QRhi::DrawIndirectMulti:
900 case QRhi::TextureSizeMin:
902 case QRhi::TextureSizeMax:
903 return caps.maxTextureSize;
904 case QRhi::MaxColorAttachments:
906 case QRhi::FramesInFlight:
908 case QRhi::MaxAsyncReadbackFrames:
910 case QRhi::MaxThreadGroupsPerDimension:
912 case QRhi::MaxThreadsPerThreadGroup:
914 case QRhi::MaxThreadGroupX:
916 case QRhi::MaxThreadGroupY:
918 case QRhi::MaxThreadGroupZ:
919 return caps.maxThreadGroupSize;
920 case QRhi::TextureArraySizeMax:
922 case QRhi::MaxUniformBufferRange:
924 case QRhi::MaxVertexInputs:
926 case QRhi::MaxVertexOutputs:
928 case QRhi::ShadingRateImageTileSize:
938 return &nativeHandlesStruct;
943 return driverInfoStruct;
949 result.totalPipelineCreationTime = totalPipelineCreationTime();
959void QRhiMetal::setQueueSubmitParams(QRhiNativeHandles *)
966 for (QMetalShader &s : d->shaderCache)
969 d->shaderCache.clear();
991 if (!d->binArch || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
996 qCDebug(QRHI_LOG_INFO,
"pipelineCacheData: Failed to create temporary file for Metal");
1001 const QString fn = QFileInfo(tmp.fileName()).absoluteFilePath();
1002 NSURL *url = QUrl::fromLocalFile(fn).toNSURL();
1004 if (![d->binArch serializeToURL: url error: &err]) {
1005 const QString msg = QString::fromNSString(err.localizedDescription);
1007 qCDebug(QRHI_LOG_INFO,
"Failed to serialize MTLBinaryArchive: %s", qPrintable(msg));
1012 if (!f.open(QIODevice::ReadOnly)) {
1013 qCDebug(QRHI_LOG_INFO,
"pipelineCacheData: Failed to reopen temporary file");
1016 const QByteArray blob = f.readAll();
1020 const quint32 dataSize = quint32(blob.size());
1022 data.resize(headerSize + dataSize);
1025 header.rhiId = pipelineCacheRhiId();
1026 header.arch = quint32(
sizeof(
void*));
1027 header.dataSize = quint32(dataSize);
1028 header.osMajor = osMajor;
1029 header.osMinor = osMinor;
1030 const size_t driverStrLen = qMin(
sizeof(header
.driver) - 1, size_t(driverInfoStruct.deviceName.length()));
1032 memcpy(header.driver, driverInfoStruct.deviceName.constData(), driverStrLen);
1033 header.driver[driverStrLen] =
'\0';
1035 memcpy(data.data(), &header, headerSize);
1036 memcpy(data.data() + headerSize, blob.constData(), dataSize);
1046 if (data.size() < qsizetype(headerSize)) {
1047 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size (header incomplete)");
1051 const size_t dataOffset = headerSize;
1053 memcpy(&header, data.constData(), headerSize);
1055 const quint32 rhiId = pipelineCacheRhiId();
1056 if (header.rhiId != rhiId) {
1057 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
1058 rhiId, header.rhiId);
1062 const quint32 arch = quint32(
sizeof(
void*));
1063 if (header.arch != arch) {
1064 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
1069 if (header.osMajor != osMajor || header.osMinor != osMinor) {
1070 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: OS version does not match (%u.%u, %u.%u)",
1071 osMajor, osMinor, header.osMajor, header.osMinor);
1075 const size_t driverStrLen = qMin(
sizeof(header
.driver) - 1, size_t(driverInfoStruct.deviceName.length()));
1076 if (strncmp(header
.driver, driverInfoStruct.deviceName.constData(), driverStrLen)) {
1077 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Metal device name does not match");
1081 if (data.size() < qsizetype(dataOffset + header.dataSize)) {
1082 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size (data incomplete)");
1086 const char *p = data.constData() + dataOffset;
1090 qCDebug(QRHI_LOG_INFO,
"pipelineCacheData: Failed to create temporary file for Metal");
1093 tmp.write(p, header.dataSize);
1096 const QString fn = QFileInfo(tmp.fileName()).absoluteFilePath();
1097 NSURL *url = QUrl::fromLocalFile(fn).toNSURL();
1098 if (
d->setupBinaryArchive(url))
1099 qCDebug(QRHI_LOG_INFO,
"Created MTLBinaryArchive with initial data of %u bytes", header.dataSize);
1102QRhiRenderBuffer *
QRhiMetal::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
1103 int sampleCount, QRhiRenderBuffer::Flags flags,
1104 QRhiTexture::Format backingFormatHint)
1106 return new QMetalRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
1110 const QSize &pixelSize,
int depth,
int arraySize,
1111 int sampleCount, QRhiTexture::Flags flags)
1113 return new QMetalTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
1117 QRhiSampler::Filter mipmapMode,
1118 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
1120 return new QMetalSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
1125 return new QMetalShadingRateMap(
this);
1129 QRhiTextureRenderTarget::Flags flags)
1136 return new QMetalGraphicsPipeline(
this);
1141 return new QMetalComputePipeline(
this);
1146 return new QMetalShaderResourceBindings(
this);
1157 const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[],
1160 const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex];
1161 if (!map || map->isEmpty())
1164 auto it = map->constFind(binding);
1165 if (it != map->cend())
1176 const QRhiBatchedBindings<id<MTLBuffer>>::Batch &bufferBatch,
1177 const QRhiBatchedBindings<NSUInteger>::Batch &offsetBatch)
1180 case QMetalShaderResourceBindingsData::VERTEX:
1181 [cbD->d->currentRenderPassEncoder setVertexBuffers: bufferBatch.resources.constData()
1182 offsets: offsetBatch.resources.constData()
1183 withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
1185 case QMetalShaderResourceBindingsData::FRAGMENT:
1186 [cbD->d->currentRenderPassEncoder setFragmentBuffers: bufferBatch.resources.constData()
1187 offsets: offsetBatch.resources.constData()
1188 withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
1190 case QMetalShaderResourceBindingsData::COMPUTE:
1191 [cbD->d->currentComputePassEncoder setBuffers: bufferBatch.resources.constData()
1192 offsets: offsetBatch.resources.constData()
1193 withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
1207 const QRhiBatchedBindings<id<MTLTexture>>::Batch &textureBatch)
1210 case QMetalShaderResourceBindingsData::VERTEX:
1211 [cbD->d->currentRenderPassEncoder setVertexTextures: textureBatch.resources.constData()
1212 withRange: NSMakeRange(textureBatch.startBinding, NSUInteger(textureBatch.resources.count()))];
1214 case QMetalShaderResourceBindingsData::FRAGMENT:
1215 [cbD->d->currentRenderPassEncoder setFragmentTextures: textureBatch.resources.constData()
1216 withRange: NSMakeRange(textureBatch.startBinding, NSUInteger(textureBatch.resources.count()))];
1218 case QMetalShaderResourceBindingsData::COMPUTE:
1219 [cbD->d->currentComputePassEncoder setTextures: textureBatch.resources.constData()
1220 withRange: NSMakeRange(textureBatch.startBinding, NSUInteger(textureBatch.resources.count()))];
1234 const QRhiBatchedBindings<id<MTLSamplerState>>::Batch &samplerBatch)
1236 switch (encoderStage) {
1237 case QMetalShaderResourceBindingsData::VERTEX:
1238 [cbD->d->currentRenderPassEncoder setVertexSamplerStates: samplerBatch.resources.constData()
1239 withRange: NSMakeRange(samplerBatch.startBinding, NSUInteger(samplerBatch.resources.count()))];
1241 case QMetalShaderResourceBindingsData::FRAGMENT:
1242 [cbD->d->currentRenderPassEncoder setFragmentSamplerStates: samplerBatch.resources.constData()
1243 withRange: NSMakeRange(samplerBatch.startBinding, NSUInteger(samplerBatch.resources.count()))];
1245 case QMetalShaderResourceBindingsData::COMPUTE:
1246 [cbD->d->currentComputePassEncoder setSamplerStates: samplerBatch.resources.constData()
1247 withRange: NSMakeRange(samplerBatch.startBinding, NSUInteger(samplerBatch.resources.count()))];
1269 for (
int i = 0, ie = bindingData->res[resourceStage].bufferBatches.batches.count(); i != ie; ++i) {
1270 const auto &bufferBatch(bindingData->res[resourceStage].bufferBatches.batches[i]);
1271 const auto &offsetBatch(bindingData->res[resourceStage].bufferOffsetBatches.batches[i]);
1272 bindStageBuffers(cbD, encoderStage, bufferBatch, offsetBatch);
1275 for (
int i = 0, ie = bindingData->res[resourceStage].textureBatches.batches.count(); i != ie; ++i) {
1276 const auto &batch(bindingData->res[resourceStage].textureBatches.batches[i]);
1277 bindStageTextures(cbD, encoderStage, batch);
1280 for (
int i = 0, ie = bindingData->res[resourceStage].samplerBatches.batches.count(); i != ie; ++i) {
1281 const auto &batch(bindingData->res[resourceStage].samplerBatches.batches[i]);
1282 bindStageSamplers(cbD, encoderStage, batch);
1289 case QMetalShaderResourceBindingsData::VERTEX:
1290 return QRhiShaderResourceBinding::StageFlag::VertexStage;
1291 case QMetalShaderResourceBindingsData::TESSCTRL:
1292 return QRhiShaderResourceBinding::StageFlag::TessellationControlStage;
1293 case QMetalShaderResourceBindingsData::TESSEVAL:
1294 return QRhiShaderResourceBinding::StageFlag::TessellationEvaluationStage;
1295 case QMetalShaderResourceBindingsData::FRAGMENT:
1296 return QRhiShaderResourceBinding::StageFlag::FragmentStage;
1297 case QMetalShaderResourceBindingsData::COMPUTE:
1298 return QRhiShaderResourceBinding::StageFlag::ComputeStage;
1301 Q_UNREACHABLE_RETURN(QRhiShaderResourceBinding::StageFlag::VertexStage);
1306 int dynamicOffsetCount,
1307 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
1308 bool offsetOnlyChange,
1309 const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[
SUPPORTED_STAGES])
1313 for (
const QRhiShaderResourceBinding &binding : std::as_const(srbD->sortedBindings)) {
1314 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
1316 case QRhiShaderResourceBinding::UniformBuffer:
1318 QMetalBuffer *bufD =
QRHI_RES(QMetalBuffer, b->u.ubuf.buf);
1319 id<MTLBuffer> mtlbuf = bufD->d->buf[bufD->d->slotted ? currentFrameSlot : 0];
1320 quint32 offset = b->u.ubuf.offset;
1321 for (
int i = 0; i < dynamicOffsetCount; ++i) {
1322 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1323 if (dynOfs.first == b->binding) {
1324 offset = dynOfs.second;
1329 for (
int stage = 0; stage < SUPPORTED_STAGES; ++stage) {
1330 if (b->stage.testFlag(toRhiSrbStage(stage))) {
1331 const int nativeBinding = mapBinding(b->binding, stage, nativeResourceBindingMaps, BindingType::Buffer);
1332 if (nativeBinding >= 0)
1333 bindingData.res[stage].buffers.append({ nativeBinding, mtlbuf, offset });
1338 case QRhiShaderResourceBinding::SampledTexture:
1339 case QRhiShaderResourceBinding::Texture:
1340 case QRhiShaderResourceBinding::Sampler:
1342 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
1343 for (
int elem = 0; elem < data->count; ++elem) {
1344 QMetalTexture *texD =
QRHI_RES(QMetalTexture, b->u.stex.texSamplers[elem].tex);
1345 QMetalSampler *samplerD =
QRHI_RES(QMetalSampler, b->u.stex.texSamplers[elem].sampler);
1347 for (
int stage = 0; stage < SUPPORTED_STAGES; ++stage) {
1348 if (b->stage.testFlag(toRhiSrbStage(stage))) {
1353 const int textureBinding = mapBinding(b->binding, stage, nativeResourceBindingMaps, BindingType::Texture);
1354 const int samplerBinding = texD && samplerD ? mapBinding(b->binding, stage, nativeResourceBindingMaps, BindingType::Sampler)
1355 : (samplerD ? mapBinding(b->binding, stage, nativeResourceBindingMaps, BindingType::Texture) : -1);
1356 if (textureBinding >= 0 && texD)
1357 bindingData.res[stage].textures.append({ textureBinding + elem, texD->d->tex });
1358 if (samplerBinding >= 0)
1359 bindingData.res[stage].samplers.append({ samplerBinding + elem, samplerD->d->samplerState });
1365 case QRhiShaderResourceBinding::ImageLoad:
1366 case QRhiShaderResourceBinding::ImageStore:
1367 case QRhiShaderResourceBinding::ImageLoadStore:
1369 QMetalTexture *texD =
QRHI_RES(QMetalTexture, b->u.simage.tex);
1370 id<MTLTexture> t = texD->d->viewForLevel(b->u.simage.level);
1372 for (
int stage = 0; stage < SUPPORTED_STAGES; ++stage) {
1373 if (b->stage.testFlag(toRhiSrbStage(stage))) {
1374 const int nativeBinding = mapBinding(b->binding, stage, nativeResourceBindingMaps, BindingType::Texture);
1375 if (nativeBinding >= 0)
1376 bindingData.res[stage].textures.append({ nativeBinding, t });
1381 case QRhiShaderResourceBinding::BufferLoad:
1382 case QRhiShaderResourceBinding::BufferStore:
1383 case QRhiShaderResourceBinding::BufferLoadStore:
1385 QMetalBuffer *bufD =
QRHI_RES(QMetalBuffer, b->u.sbuf.buf);
1386 id<MTLBuffer> mtlbuf = bufD->d->buf[0];
1387 quint32 offset = b->u.sbuf.offset;
1388 for (
int stage = 0; stage < SUPPORTED_STAGES; ++stage) {
1389 if (b->stage.testFlag(toRhiSrbStage(stage))) {
1390 const int nativeBinding = mapBinding(b->binding, stage, nativeResourceBindingMaps, BindingType::Buffer);
1391 if (nativeBinding >= 0)
1392 bindingData.res[stage].buffers.append({ nativeBinding, mtlbuf, offset });
1415 std::sort(bindingData.res[stage].buffers.begin(), bindingData.res[stage].buffers.end(), [](
const QMetalShaderResourceBindingsData::Stage::Buffer &a,
const QMetalShaderResourceBindingsData::Stage::Buffer &b) {
1416 return a.nativeBinding < b.nativeBinding;
1419 for (
const QMetalShaderResourceBindingsData::Stage::Buffer &buf : std::as_const(bindingData.res[stage].buffers)) {
1420 bindingData.res[stage].bufferBatches.feed(buf.nativeBinding, buf.mtlbuf);
1421 bindingData.res[stage].bufferOffsetBatches.feed(buf.nativeBinding, buf.offset);
1424 bindingData.res[stage].bufferBatches.finish();
1425 bindingData.res[stage].bufferOffsetBatches.finish();
1427 for (
int i = 0, ie = bindingData.res[stage].bufferBatches.batches.count(); i != ie; ++i) {
1428 const auto &bufferBatch(bindingData.res[stage].bufferBatches.batches[i]);
1429 const auto &offsetBatch(bindingData.res[stage].bufferOffsetBatches.batches[i]);
1431 if (cbD
->d->currentShaderResourceBindingState.res[stage].bufferBatches.batches.count() > i
1432 && cbD
->d->currentShaderResourceBindingState.res[stage].bufferOffsetBatches.batches.count() > i
1433 && bufferBatch == cbD
->d->currentShaderResourceBindingState.res[stage].bufferBatches.batches[i]
1434 && offsetBatch == cbD
->d->currentShaderResourceBindingState.res[stage].bufferOffsetBatches.batches[i])
1438 bindStageBuffers(cbD, stage, bufferBatch, offsetBatch);
1441 if (offsetOnlyChange)
1444 std::sort(bindingData.res[stage].textures.begin(), bindingData.res[stage].textures.end(), [](
const QMetalShaderResourceBindingsData::Stage::Texture &a,
const QMetalShaderResourceBindingsData::Stage::Texture &b) {
1445 return a.nativeBinding < b.nativeBinding;
1448 std::sort(bindingData.res[stage].samplers.begin(), bindingData.res[stage].samplers.end(), [](
const QMetalShaderResourceBindingsData::Stage::Sampler &a,
const QMetalShaderResourceBindingsData::Stage::Sampler &b) {
1449 return a.nativeBinding < b.nativeBinding;
1452 for (
const QMetalShaderResourceBindingsData::Stage::Texture &t : std::as_const(bindingData.res[stage].textures))
1453 bindingData.res[stage].textureBatches.feed(t.nativeBinding, t.mtltex);
1455 for (
const QMetalShaderResourceBindingsData::Stage::Sampler &s : std::as_const(bindingData.res[stage].samplers))
1456 bindingData.res[stage].samplerBatches.feed(s.nativeBinding, s.mtlsampler);
1458 bindingData.res[stage].textureBatches.finish();
1459 bindingData.res[stage].samplerBatches.finish();
1461 for (
int i = 0, ie = bindingData.res[stage].textureBatches.batches.count(); i != ie; ++i) {
1462 const auto &batch(bindingData.res[stage].textureBatches.batches[i]);
1464 if (cbD
->d->currentShaderResourceBindingState.res[stage].textureBatches.batches.count() > i
1465 && batch == cbD
->d->currentShaderResourceBindingState.res[stage].textureBatches.batches[i])
1469 bindStageTextures(cbD, stage, batch);
1472 for (
int i = 0, ie = bindingData.res[stage].samplerBatches.batches.count(); i != ie; ++i) {
1473 const auto &batch(bindingData.res[stage].samplerBatches.batches[i]);
1475 if (cbD
->d->currentShaderResourceBindingState.res[stage].samplerBatches.batches.count() > i
1476 && batch == cbD
->d->currentShaderResourceBindingState.res[stage].samplerBatches.batches[i])
1480 bindStageSamplers(cbD, stage, batch);
1484 cbD
->d->currentShaderResourceBindingState = bindingData;
1491 [cbD->d->currentRenderPassEncoder setRenderPipelineState: d->ps];
1493 if (cbD
->d->currentDepthStencilState !=
d->ds) {
1494 [cbD->d->currentRenderPassEncoder setDepthStencilState: d->ds];
1495 cbD
->d->currentDepthStencilState =
d->ds;
1498 [cbD->d->currentRenderPassEncoder setCullMode: d->cullMode];
1502 [cbD->d->currentRenderPassEncoder setTriangleFillMode: d->triangleFillMode];
1505 if (rhiD->caps.depthClamp) {
1507 [cbD->d->currentRenderPassEncoder setDepthClipMode: d->depthClipMode];
1512 [cbD->d->currentRenderPassEncoder setFrontFacingWinding: d->winding];
1515 if (!qFuzzyCompare(
d->depthBias, cbD->currentDepthBiasValues.first)
1518 [cbD->d->currentRenderPassEncoder setDepthBias: d->depthBias
1519 slopeScale: d->slopeScaledDepthBias
1536 cbD->currentPipelineGeneration = psD->generation;
1541 if (!psD
->d->tess.enabled && !psD
->d->tess.failed)
1546 for (QMetalBuffer *workBuf : psD->d->extraBufMgr.deviceLocalWorkBuffers) {
1547 if (workBuf && workBuf->lastActiveFrameSlot == currentFrameSlot)
1548 workBuf->lastActiveFrameSlot = -1;
1550 for (QMetalBuffer *workBuf : psD->d->extraBufMgr.hostVisibleWorkBuffers) {
1551 if (workBuf && workBuf->lastActiveFrameSlot == currentFrameSlot)
1552 workBuf->lastActiveFrameSlot = -1;
1555 psD->lastActiveFrameSlot = currentFrameSlot;
1559 int dynamicOffsetCount,
1560 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1569 srb = gfxPsD->m_shaderResourceBindings;
1571 srb = compPsD->m_shaderResourceBindings;
1575 bool hasSlottedResourceInSrb =
false;
1576 bool hasDynamicOffsetInSrb =
false;
1577 bool resNeedsRebind =
false;
1579 bool pipelineChanged =
false;
1592 QMap<QRhiShaderResourceBinding::StageFlag, QMap<
int, quint32>> storageBufferSizes;
1595 for (
int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
1596 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
1599 case QRhiShaderResourceBinding::UniformBuffer:
1602 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
1603 sanityCheckResourceOwnership(bufD);
1606 hasSlottedResourceInSrb =
true;
1607 if (b->u.ubuf.hasDynamicOffset)
1608 hasDynamicOffsetInSrb =
true;
1609 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
1610 resNeedsRebind =
true;
1611 bd.ubuf.id = bufD->m_id;
1612 bd.ubuf.generation = bufD->generation;
1614 bufD->lastActiveFrameSlot = currentFrameSlot;
1617 case QRhiShaderResourceBinding::SampledTexture:
1618 case QRhiShaderResourceBinding::Texture:
1619 case QRhiShaderResourceBinding::Sampler:
1621 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
1622 if (bd.stex.count != data->count) {
1623 bd.stex.count = data->count;
1624 resNeedsRebind =
true;
1626 for (
int elem = 0; elem < data->count; ++elem) {
1629 Q_ASSERT(texD || samplerD);
1630 sanityCheckResourceOwnership(texD);
1631 sanityCheckResourceOwnership(samplerD);
1632 const quint64 texId = texD ? texD->m_id : 0;
1633 const uint texGen = texD ? texD->generation : 0;
1634 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
1635 const uint samplerGen = samplerD ? samplerD->generation : 0;
1636 if (texGen != bd.stex.d[elem].texGeneration
1637 || texId != bd.stex.d[elem].texId
1638 || samplerGen != bd.stex.d[elem].samplerGeneration
1639 || samplerId != bd.stex.d[elem].samplerId)
1641 resNeedsRebind =
true;
1642 bd.stex.d[elem].texId = texId;
1643 bd.stex.d[elem].texGeneration = texGen;
1644 bd.stex.d[elem].samplerId = samplerId;
1645 bd.stex.d[elem].samplerGeneration = samplerGen;
1648 texD->lastActiveFrameSlot = currentFrameSlot;
1650 samplerD->lastActiveFrameSlot = currentFrameSlot;
1654 case QRhiShaderResourceBinding::ImageLoad:
1655 case QRhiShaderResourceBinding::ImageStore:
1656 case QRhiShaderResourceBinding::ImageLoadStore:
1659 sanityCheckResourceOwnership(texD);
1660 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
1661 resNeedsRebind =
true;
1662 bd.simage.id = texD->m_id;
1663 bd.simage.generation = texD->generation;
1665 texD->lastActiveFrameSlot = currentFrameSlot;
1668 case QRhiShaderResourceBinding::BufferLoad:
1669 case QRhiShaderResourceBinding::BufferStore:
1670 case QRhiShaderResourceBinding::BufferLoadStore:
1673 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
1674 sanityCheckResourceOwnership(bufD);
1676 if (needsBufferSizeBuffer) {
1677 for (
int i = 0; i < 6; ++i) {
1678 const QRhiShaderResourceBinding::StageFlag stage =
1679 QRhiShaderResourceBinding::StageFlag(1 << i);
1680 if (b->stage.testFlag(stage)) {
1681 storageBufferSizes[stage][b->binding] = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : bufD->size();
1687 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
1688 resNeedsRebind =
true;
1689 bd.sbuf.id = bufD->m_id;
1690 bd.sbuf.generation = bufD->generation;
1692 bufD->lastActiveFrameSlot = currentFrameSlot;
1701 if (needsBufferSizeBuffer) {
1703 QVarLengthArray<std::pair<QMetalShader *, QRhiShaderResourceBinding::StageFlag>, 4> shaders;
1707 Q_ASSERT(compPsD
->d->cs.nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding));
1708 shaders.append({&compPsD->d->cs, QRhiShaderResourceBinding::StageFlag::ComputeStage});
1711 if (gfxPsD
->d->tess.enabled) {
1721 Q_ASSERT(gfxPsD
->d->tess.compVs[0].desc.storageBlocks() == gfxPsD
->d->tess.compVs[1].desc.storageBlocks());
1722 Q_ASSERT(gfxPsD
->d->tess.compVs[0].desc.storageBlocks() == gfxPsD
->d->tess.compVs[2].desc.storageBlocks());
1723 Q_ASSERT(gfxPsD
->d->tess.compVs[0].nativeResourceBindingMap == gfxPsD
->d->tess.compVs[1].nativeResourceBindingMap);
1724 Q_ASSERT(gfxPsD
->d->tess.compVs[0].nativeResourceBindingMap == gfxPsD
->d->tess.compVs[2].nativeResourceBindingMap);
1725 Q_ASSERT(gfxPsD
->d->tess.compVs[0].nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding)
1726 == gfxPsD
->d->tess.compVs[1].nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding));
1727 Q_ASSERT(gfxPsD
->d->tess.compVs[0].nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding)
1728 == gfxPsD
->d->tess.compVs[2].nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding));
1729 Q_ASSERT(gfxPsD->d->tess.compVs[0].nativeShaderInfo.extraBufferBindings[QShaderPrivate::MslBufferSizeBufferBinding]
1730 == gfxPsD->d->tess.compVs[1].nativeShaderInfo.extraBufferBindings[QShaderPrivate::MslBufferSizeBufferBinding]);
1731 Q_ASSERT(gfxPsD->d->tess.compVs[0].nativeShaderInfo.extraBufferBindings[QShaderPrivate::MslBufferSizeBufferBinding]
1732 == gfxPsD->d->tess.compVs[2].nativeShaderInfo.extraBufferBindings[QShaderPrivate::MslBufferSizeBufferBinding]);
1734 if (gfxPsD
->d->tess.compVs[0].nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding))
1735 shaders.append({&gfxPsD->d->tess.compVs[0], QRhiShaderResourceBinding::StageFlag::VertexStage});
1737 if (gfxPsD
->d->tess.compTesc.nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding))
1738 shaders.append({&gfxPsD->d->tess.compTesc, QRhiShaderResourceBinding::StageFlag::TessellationControlStage});
1740 if (gfxPsD
->d->tess.vertTese.nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding))
1741 shaders.append({&gfxPsD->d->tess.vertTese, QRhiShaderResourceBinding::StageFlag::TessellationEvaluationStage});
1744 if (gfxPsD
->d->vs.nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding))
1745 shaders.append({&gfxPsD->d->vs, QRhiShaderResourceBinding::StageFlag::VertexStage});
1747 if (gfxPsD
->d->fs.nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding))
1748 shaders.append({&gfxPsD->d->fs, QRhiShaderResourceBinding::StageFlag::FragmentStage});
1752 for (
const auto &shader : shaders) {
1754 const int binding = shader.first->nativeShaderInfo.extraBufferBindings[QShaderPrivate::MslBufferSizeBufferBinding];
1757 if (!(storageBufferSizes.contains(shader.second) && storageBufferSizes[shader.second].contains(binding))) {
1759 int maxNativeBinding = 0;
1760 for (
const QShaderDescription::StorageBlock &block : shader.first->desc.storageBlocks())
1761 maxNativeBinding = qMax(maxNativeBinding, shader.first->nativeResourceBindingMap[block.binding].first);
1763 const int size = (maxNativeBinding + 1) *
sizeof(
int);
1765 Q_ASSERT(offset + size <= bufD->size());
1766 srbD->sortedBindings.append(QRhiShaderResourceBinding::bufferLoad(binding, shader.second, bufD, offset, size));
1768 QMetalShaderResourceBindings::BoundResourceData bd;
1769 bd.sbuf.id = bufD->m_id;
1770 bd.sbuf.generation = bufD->generation;
1771 srbD->boundResourceData.append(bd);
1775 QVarLengthArray<
int, 8> bufferSizeBufferData;
1776 Q_ASSERT(storageBufferSizes.contains(shader.second));
1777 const QMap<
int, quint32> &sizes(storageBufferSizes[shader.second]);
1778 for (
const QShaderDescription::StorageBlock &block : shader.first->desc.storageBlocks()) {
1779 const int index = shader.first->nativeResourceBindingMap[block.binding].first;
1785 if (bufferSizeBufferData.size() <= index)
1786 bufferSizeBufferData.resize(index + 1);
1788 Q_ASSERT(sizes.contains(block.binding));
1789 bufferSizeBufferData[index] = sizes[block.binding];
1792 QRhiBufferData data;
1793 const quint32 size = bufferSizeBufferData.size() *
sizeof(
int);
1794 data.assign(
reinterpret_cast<
const char *>(bufferSizeBufferData.constData()), size);
1795 Q_ASSERT(offset + size <= bufD->size());
1796 bufD->d->pendingUpdates[bufD->d->slotted ? currentFrameSlot : 0].append({ offset, data });
1799 offset += ((size + 31) / 32) * 32;
1803 bufD->lastActiveFrameSlot = currentFrameSlot;
1807 const int resSlot = hasSlottedResourceInSrb ? currentFrameSlot : 0;
1809 resNeedsRebind =
true;
1812 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1815 if (hasDynamicOffsetInSrb || resNeedsRebind || srbChanged || srbRebuilt || pipelineChanged) {
1816 const QShader::NativeResourceBindingMap *resBindMaps[
SUPPORTED_STAGES] = {
nullptr,
nullptr,
nullptr,
nullptr,
nullptr };
1820 if (gfxPsD
->d->tess.enabled) {
1823 Q_ASSERT(gfxPsD
->d->tess.compVs[0].nativeResourceBindingMap == gfxPsD
->d->tess.compVs[1].nativeResourceBindingMap);
1824 Q_ASSERT(gfxPsD
->d->tess.compVs[0].nativeResourceBindingMap == gfxPsD
->d->tess.compVs[2].nativeResourceBindingMap);
1837 cbD->currentSrbGeneration = srbD->generation;
1840 const bool offsetOnlyChange = hasDynamicOffsetInSrb && !resNeedsRebind && !srbChanged && !srbRebuilt;
1841 enqueueShaderResourceBindings(srbD, cbD, dynamicOffsetCount, dynamicOffsets, offsetOnlyChange, resBindMaps);
1846 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1847 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1852 QRhiBatchedBindings<id<MTLBuffer> > buffers;
1853 QRhiBatchedBindings<NSUInteger> offsets;
1854 for (
int i = 0; i < bindingCount; ++i) {
1857 bufD->lastActiveFrameSlot = currentFrameSlot;
1858 id<MTLBuffer> mtlbuf = bufD->d->buf[bufD->d->slotted ? currentFrameSlot : 0];
1859 buffers.feed(startBinding + i, mtlbuf);
1860 offsets.feed(startBinding + i, bindings[i].second);
1875 || buffers != cbD
->d->currentVertexInputsBuffers
1876 || offsets != cbD
->d->currentVertexInputOffsets)
1879 cbD
->d->currentVertexInputsBuffers = buffers;
1880 cbD
->d->currentVertexInputOffsets = offsets;
1882 for (
int i = 0, ie = buffers.batches.count(); i != ie; ++i) {
1883 const auto &bufferBatch(buffers.batches[i]);
1884 const auto &offsetBatch(offsets.batches[i]);
1885 [cbD->d->currentRenderPassEncoder setVertexBuffers:
1886 bufferBatch.resources.constData()
1887 offsets: offsetBatch.resources.constData()
1888 withRange: NSMakeRange(uint(firstVertexBinding) + bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
1895 ibufD->lastActiveFrameSlot = currentFrameSlot;
1897 cbD->currentIndexOffset = indexOffset;
1898 cbD->currentIndexFormat = indexFormat;
1908 const QSize outputSize = cbD->currentTarget->pixelSize();
1909 std::array<
float, 4> vp = cbD->currentViewport.viewport();
1910 float x = 0, y = 0, w = 0, h = 0;
1912 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
1915 w = outputSize.width();
1916 h = outputSize.height();
1919 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, vp, &x, &y, &w, &h);
1923 s.x = NSUInteger(x);
1924 s.y = NSUInteger(y);
1925 s.width = NSUInteger(w);
1926 s.height = NSUInteger(h);
1927 [cbD->d->currentRenderPassEncoder setScissorRect: s];
1934 QSize outputSize = cbD->currentTarget->pixelSize();
1940 if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
1941 QRhiTextureRenderTarget *rt =
static_cast<QRhiTextureRenderTarget *>(cbD->currentTarget);
1942 if (QRhiShadingRateMap *srm = rt->description().shadingRateMap()) {
1943 if (id<MTLRasterizationRateMap> rateMap =
QRHI_RES(QMetalShadingRateMap, srm)->d->rateMap) {
1944 auto screenSize = [rateMap screenSize];
1945 outputSize = QSize(screenSize.width, screenSize.height);
1952 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1956 vp.originX =
double(x);
1957 vp.originY =
double(y);
1958 vp.width =
double(w);
1959 vp.height =
double(h);
1960 vp.znear =
double(viewport.minDepth());
1961 vp.zfar =
double(viewport.maxDepth());
1963 [cbD->d->currentRenderPassEncoder setViewport: vp];
1965 cbD->currentViewport = viewport;
1979 const QSize outputSize = cbD->currentTarget->pixelSize();
1983 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
1987 s.x = NSUInteger(x);
1988 s.y = NSUInteger(y);
1989 s.width = NSUInteger(w);
1990 s.height = NSUInteger(h);
1992 [cbD->d->currentRenderPassEncoder setScissorRect: s];
2002 [cbD->d->currentRenderPassEncoder setBlendColorRed: c.redF()
2003 green: c.greenF() blue: c.blueF() alpha: c.alphaF()];
2011 [cbD->d->currentRenderPassEncoder setStencilReferenceValue: refValue];
2017 Q_UNUSED(coarsePixelSize);
2022 if (cbD
->d->currentRenderPassEncoder) {
2023 [cbD->d->currentRenderPassEncoder endEncoding];
2024 cbD->d->currentRenderPassEncoder = nil;
2027 if (!cbD->d->tessellationComputeEncoder)
2028 cbD->d->tessellationComputeEncoder = [cbD->d->cb computeCommandEncoder];
2030 return cbD
->d->tessellationComputeEncoder;
2035 if (cbD
->d->tessellationComputeEncoder) {
2036 [cbD->d->tessellationComputeEncoder endEncoding];
2037 cbD->d->tessellationComputeEncoder = nil;
2042 switch (cbD->currentTarget->resourceType()) {
2043 case QRhiResource::SwapChainRenderTarget:
2046 case QRhiResource::TextureRenderTarget:
2055 QVarLengthArray<MTLLoadAction, 4> oldColorLoad;
2057 oldColorLoad.append(cbD
->d->currentPassRpDesc.colorAttachments[i].loadAction);
2058 if (cbD->d->currentPassRpDesc.colorAttachments[i].storeAction != MTLStoreActionDontCare)
2059 cbD->d->currentPassRpDesc.colorAttachments[i].loadAction = MTLLoadActionLoad;
2062 MTLLoadAction oldDepthLoad;
2063 MTLLoadAction oldStencilLoad;
2065 oldDepthLoad = cbD
->d->currentPassRpDesc.depthAttachment.loadAction;
2066 if (cbD->d->currentPassRpDesc.depthAttachment.storeAction != MTLStoreActionDontCare)
2067 cbD->d->currentPassRpDesc.depthAttachment.loadAction = MTLLoadActionLoad;
2069 oldStencilLoad = cbD
->d->currentPassRpDesc.stencilAttachment.loadAction;
2070 if (cbD->d->currentPassRpDesc.stencilAttachment.storeAction != MTLStoreActionDontCare)
2071 cbD->d->currentPassRpDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
2074 cbD->d->currentRenderPassEncoder = [cbD->d->cb renderCommandEncoderWithDescriptor: cbD->d->currentPassRpDesc];
2078 cbD
->d->currentPassRpDesc.colorAttachments[i].loadAction = oldColorLoad[i];
2082 cbD
->d->currentPassRpDesc.depthAttachment.loadAction = oldDepthLoad;
2083 cbD
->d->currentPassRpDesc.stencilAttachment.loadAction = oldStencilLoad;
2092 if (graphicsPipeline
->d->tess.failed)
2096 const quint32 instanceCount = indexed ? args.drawIndexed.instanceCount : args.draw.instanceCount;
2097 const quint32 vertexOrIndexCount = indexed ? args.drawIndexed.indexCount : args.draw.vertexCount;
2101 const quint32 patchCount = tess.patchCountForDrawCall(vertexOrIndexCount, instanceCount);
2107 id<MTLComputeCommandEncoder> vertTescComputeEncoder = tessellationComputeEncoder(cbD);
2111 id<MTLComputeCommandEncoder> computeEncoder = vertTescComputeEncoder;
2112 QShader::Variant shaderVariant = QShader::NonIndexedVertexAsComputeShader;
2113 if (args.type == TessDrawArgs::U16Indexed)
2114 shaderVariant = QShader::UInt16IndexedVertexAsComputeShader;
2115 else if (args.type == TessDrawArgs::U32Indexed)
2116 shaderVariant = QShader::UInt32IndexedVertexAsComputeShader;
2117 const int varIndex = QMetalGraphicsPipelineData::Tessellation::vsCompVariantToIndex(shaderVariant);
2118 id<MTLComputePipelineState> computePipelineState = tess.vsCompPipeline(
this, shaderVariant);
2119 [computeEncoder setComputePipelineState: computePipelineState];
2124 cbD
->d->currentComputePassEncoder = computeEncoder;
2126 cbD->d->currentComputePassEncoder = nil;
2128 const QMap<
int,
int> &ebb(tess.compVs[varIndex].nativeShaderInfo.extraBufferBindings);
2129 const int outputBufferBinding = ebb.value(QShaderPrivate::MslTessVertTescOutputBufferBinding, -1);
2130 const int indexBufferBinding = ebb.value(QShaderPrivate::MslTessVertIndicesBufferBinding, -1);
2132 if (outputBufferBinding >= 0) {
2133 const quint32 workBufSize = tess.vsCompOutputBufferSize(vertexOrIndexCount, instanceCount);
2134 vertOutBuf = extraBufMgr.acquireWorkBuffer(
this, workBufSize);
2137 [computeEncoder setBuffer: vertOutBuf->d->buf[0] offset: 0 atIndex: outputBufferBinding];
2140 if (indexBufferBinding >= 0)
2141 [computeEncoder setBuffer: (id<MTLBuffer>) args.drawIndexed.indexBuffer offset: 0 atIndex: indexBufferBinding];
2143 for (
int i = 0, ie = cbD
->d->currentVertexInputsBuffers.batches.count(); i != ie; ++i) {
2144 const auto &bufferBatch(cbD
->d->currentVertexInputsBuffers.batches[i]);
2145 const auto &offsetBatch(cbD
->d->currentVertexInputOffsets.batches[i]);
2146 [computeEncoder setBuffers: bufferBatch.resources.constData()
2147 offsets: offsetBatch.resources.constData()
2148 withRange: NSMakeRange(uint(cbD->d->currentFirstVertexBinding) + bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
2152 [computeEncoder setStageInRegion: MTLRegionMake2D(args.drawIndexed.vertexOffset, args.drawIndexed.firstInstance,
2153 args.drawIndexed.indexCount, args.drawIndexed.instanceCount)];
2155 [computeEncoder setStageInRegion: MTLRegionMake2D(args.draw.firstVertex, args.draw.firstInstance,
2156 args.draw.vertexCount, args.draw.instanceCount)];
2159 [computeEncoder dispatchThreads: MTLSizeMake(vertexOrIndexCount, instanceCount, 1)
2160 threadsPerThreadgroup: MTLSizeMake(computePipelineState.threadExecutionWidth, 1, 1)];
2165 id<MTLComputeCommandEncoder> computeEncoder = vertTescComputeEncoder;
2166 id<MTLComputePipelineState> computePipelineState = tess.tescCompPipeline(
this);
2167 [computeEncoder setComputePipelineState: computePipelineState];
2169 cbD
->d->currentComputePassEncoder = computeEncoder;
2171 cbD->d->currentComputePassEncoder = nil;
2173 const QMap<
int,
int> &ebb(tess.compTesc.nativeShaderInfo.extraBufferBindings);
2174 const int outputBufferBinding = ebb.value(QShaderPrivate::MslTessVertTescOutputBufferBinding, -1);
2175 const int patchOutputBufferBinding = ebb.value(QShaderPrivate::MslTessTescPatchOutputBufferBinding, -1);
2176 const int tessFactorBufferBinding = ebb.value(QShaderPrivate::MslTessTescTessLevelBufferBinding, -1);
2177 const int paramsBufferBinding = ebb.value(QShaderPrivate::MslTessTescParamsBufferBinding, -1);
2178 const int inputBufferBinding = ebb.value(QShaderPrivate::MslTessTescInputBufferBinding, -1);
2180 if (outputBufferBinding >= 0) {
2181 const quint32 workBufSize = tess.tescCompOutputBufferSize(patchCount);
2182 tescOutBuf = extraBufMgr.acquireWorkBuffer(
this, workBufSize);
2185 [computeEncoder setBuffer: tescOutBuf->d->buf[0] offset: 0 atIndex: outputBufferBinding];
2188 if (patchOutputBufferBinding >= 0) {
2189 const quint32 workBufSize = tess.tescCompPatchOutputBufferSize(patchCount);
2190 tescPatchOutBuf = extraBufMgr.acquireWorkBuffer(
this, workBufSize);
2191 if (!tescPatchOutBuf)
2193 [computeEncoder setBuffer: tescPatchOutBuf->d->buf[0] offset: 0 atIndex: patchOutputBufferBinding];
2196 if (tessFactorBufferBinding >= 0) {
2197 tescFactorBuf = extraBufMgr.acquireWorkBuffer(
this, patchCount *
sizeof(MTLQuadTessellationFactorsHalf));
2198 [computeEncoder setBuffer: tescFactorBuf->d->buf[0] offset: 0 atIndex: tessFactorBufferBinding];
2201 if (paramsBufferBinding >= 0) {
2203 quint32 inControlPointCount;
2210 params.patchCount = patchCount;
2211 id<MTLBuffer> paramsBuf = tescParamsBuf
->d->buf[0];
2212 char *p =
reinterpret_cast<
char *>([paramsBuf contents]);
2213 memcpy(p, ¶ms,
sizeof(params));
2214 [computeEncoder setBuffer: paramsBuf offset: 0 atIndex: paramsBufferBinding];
2217 if (vertOutBuf && inputBufferBinding >= 0)
2218 [computeEncoder setBuffer: vertOutBuf->d->buf[0] offset: 0 atIndex: inputBufferBinding];
2220 int sgSize =
int(computePipelineState.threadExecutionWidth);
2221 int wgSize = std::lcm(tess.outControlPointCount, sgSize);
2222 while (wgSize > caps.maxThreadGroupSize) {
2224 wgSize = std::lcm(tess.outControlPointCount, sgSize);
2226 [computeEncoder dispatchThreads: MTLSizeMake(patchCount * tess.outControlPointCount, 1, 1)
2227 threadsPerThreadgroup: MTLSizeMake(wgSize, 1, 1)];
2244 id<MTLRenderCommandEncoder> renderEncoder = cbD
->d->currentRenderPassEncoder;
2249 const QMap<
int,
int> &ebb(tess.compTesc.nativeShaderInfo.extraBufferBindings);
2250 const int outputBufferBinding = ebb.value(QShaderPrivate::MslTessVertTescOutputBufferBinding, -1);
2251 const int patchOutputBufferBinding = ebb.value(QShaderPrivate::MslTessTescPatchOutputBufferBinding, -1);
2252 const int tessFactorBufferBinding = ebb.value(QShaderPrivate::MslTessTescTessLevelBufferBinding, -1);
2254 if (outputBufferBinding >= 0 && tescOutBuf)
2255 [renderEncoder setVertexBuffer: tescOutBuf->d->buf[0] offset: 0 atIndex: outputBufferBinding];
2257 if (patchOutputBufferBinding >= 0 && tescPatchOutBuf)
2258 [renderEncoder setVertexBuffer: tescPatchOutBuf->d->buf[0] offset: 0 atIndex: patchOutputBufferBinding];
2260 if (tessFactorBufferBinding >= 0 && tescFactorBuf) {
2261 [renderEncoder setTessellationFactorBuffer: tescFactorBuf->d->buf[0] offset: 0 instanceStride: 0];
2262 [renderEncoder setVertexBuffer: tescFactorBuf->d->buf[0] offset: 0 atIndex: tessFactorBufferBinding];
2265 [cbD->d->currentRenderPassEncoder drawPatches: tess.outControlPointCount
2267 patchCount: patchCount
2268 patchIndexBuffer: nil
2269 patchIndexBufferOffset: 0
2279 if (multiViewCount <= 1)
2283 const int viewMaskBufBinding = ebb.value(QShaderPrivate::MslMultiViewMaskBufferBinding, -1);
2284 if (viewMaskBufBinding == -1) {
2285 qWarning(
"No extra buffer for multiview in the vertex shader; was it built with --view-count specified?");
2292 multiViewInfo.viewOffset = 0;
2293 multiViewInfo.viewCount = quint32(multiViewCount);
2297 id<MTLBuffer> mtlbuf = buf
->d->buf[0];
2298 char *p =
reinterpret_cast<
char *>([mtlbuf contents]);
2299 memcpy(p, &multiViewInfo,
sizeof(multiViewInfo));
2300 [cbD->d->currentRenderPassEncoder setVertexBuffer: mtlbuf offset: 0 atIndex: viewMaskBufBinding];
2304 *instanceCount *= multiViewCount;
2309 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
2318 a.draw.vertexCount = vertexCount;
2319 a.draw.instanceCount = instanceCount;
2320 a.draw.firstVertex = firstVertex;
2321 a.draw.firstInstance = firstInstance;
2326 adjustForMultiViewDraw(&instanceCount, cb);
2328 if (caps.baseVertexAndInstance) {
2329 [cbD->d->currentRenderPassEncoder drawPrimitives: cbD->currentGraphicsPipeline->d->primitiveType
2330 vertexStart: firstVertex vertexCount: vertexCount instanceCount: instanceCount baseInstance: firstInstance];
2332 [cbD->d->currentRenderPassEncoder drawPrimitives: cbD->currentGraphicsPipeline->d->primitiveType
2333 vertexStart: firstVertex vertexCount: vertexCount instanceCount: instanceCount];
2338 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
2346 const quint32 indexOffset = cbD->currentIndexOffset + firstIndex * (cbD->currentIndexFormat == QRhiCommandBuffer::IndexUInt16 ? 2 : 4);
2347 Q_ASSERT(indexOffset == aligned(indexOffset, 4u));
2350 id<MTLBuffer> mtlibuf = ibufD->d->buf[ibufD->d->slotted ? currentFrameSlot : 0];
2355 a.type = cbD->currentIndexFormat == QRhiCommandBuffer::IndexUInt16 ? TessDrawArgs::U16Indexed : TessDrawArgs::U32Indexed;
2356 a.drawIndexed.indexCount = indexCount;
2357 a.drawIndexed.instanceCount = instanceCount;
2358 a.drawIndexed.firstIndex = firstIndex;
2359 a.drawIndexed.vertexOffset = vertexOffset;
2360 a.drawIndexed.firstInstance = firstInstance;
2361 a.drawIndexed.indexBuffer = mtlibuf;
2366 adjustForMultiViewDraw(&instanceCount, cb);
2368 if (caps.baseVertexAndInstance) {
2369 [cbD->d->currentRenderPassEncoder drawIndexedPrimitives: cbD->currentGraphicsPipeline->d->primitiveType
2370 indexCount: indexCount
2371 indexType: cbD->currentIndexFormat == QRhiCommandBuffer::IndexUInt16 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
2372 indexBuffer: mtlibuf
2373 indexBufferOffset: indexOffset
2374 instanceCount: instanceCount
2375 baseVertex: vertexOffset
2376 baseInstance: firstInstance];
2378 [cbD->d->currentRenderPassEncoder drawIndexedPrimitives: cbD->currentGraphicsPipeline->d->primitiveType
2379 indexCount: indexCount
2380 indexType: cbD->currentIndexFormat == QRhiCommandBuffer::IndexUInt16 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
2381 indexBuffer: mtlibuf
2382 indexBufferOffset: indexOffset
2383 instanceCount: instanceCount];
2388 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
2395 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
2396 id<MTLBuffer> indirectBufMtl = indirectBufD->d->buf[indirectBufD->d->slotted ? currentFrameSlot : 0];
2398 NSUInteger offset = indirectBufferOffset;
2399 for (quint32 i = 0; i < drawCount; ++i) {
2400 [cbD->d->currentRenderPassEncoder drawPrimitives: cbD->currentGraphicsPipeline->d->primitiveType
2401 indirectBuffer: indirectBufMtl
2402 indirectBufferOffset: offset];
2408 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
2417 id<MTLBuffer> indexBufMtl = indexBufD->d->buf[indexBufD->d->slotted ? currentFrameSlot : 0];
2421 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
2422 id<MTLBuffer> indirectBufMtl = indirectBufD->d->buf[indirectBufD->d->slotted ? currentFrameSlot : 0];
2424 NSUInteger offset = indirectBufferOffset;
2425 for (quint32 i = 0; i < drawCount; ++i) {
2426 [cbD->d->currentRenderPassEncoder drawIndexedPrimitives: cbD->currentGraphicsPipeline->d->primitiveType
2427 indexType: cbD->currentIndexFormat == QRhiCommandBuffer::IndexUInt16 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
2428 indexBuffer: indexBufMtl
2429 indexBufferOffset: cbD->currentIndexOffset
2430 indirectBuffer: indirectBufMtl
2431 indirectBufferOffset: offset];
2441 NSString *str = [NSString stringWithUTF8String: name.constData()];
2443 if (cbD->recordingPass != QMetalCommandBuffer::NoPass)
2444 [cbD->d->currentRenderPassEncoder pushDebugGroup: str];
2446 [cbD->d->cb pushDebugGroup: str];
2455 if (cbD->recordingPass != QMetalCommandBuffer::NoPass)
2456 [cbD->d->currentRenderPassEncoder popDebugGroup];
2458 [cbD->d->cb popDebugGroup];
2467 if (cbD->recordingPass != QMetalCommandBuffer::NoPass)
2468 [cbD->d->currentRenderPassEncoder insertDebugSignpost: [NSString stringWithUTF8String: msg.constData()]];
2473 return QRHI_RES(QMetalCommandBuffer, cb)->nativeHandles();
2499 currentFrameSlot = swapChainD->currentFrameSlot;
2504 dispatch_semaphore_wait(swapChainD->d->sem[currentFrameSlot], DISPATCH_TIME_FOREVER);
2512 for (QMetalSwapChain *sc : std::as_const(swapchains)) {
2513 if (sc != swapChainD)
2514 sc->waitUntilCompleted(currentFrameSlot);
2517 [d->captureScope beginScope];
2519 swapChainD->cbWrapper.d->cb =
d->newCommandBuffer();
2523 colorAtt.tex = swapChainD->d->msaaTex[currentFrameSlot];
2530 swapChainD->rtWrapper.d->fb.dsTex = swapChainD->ds ? swapChainD->ds->d->tex : nil;
2531 swapChainD->rtWrapper.d->fb.dsResolveTex = nil;
2536 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2539 swapChainD->cbWrapper.resetState(swapChainD->d->lastGpuTime[currentFrameSlot]);
2540 swapChainD->d->lastGpuTime[currentFrameSlot] = 0;
2543 return QRhi::FrameOpSuccess;
2552 id<MTLCommandBuffer> commandBuffer = swapChainD->cbWrapper.d->cb;
2554 __block
int thisFrameSlot = currentFrameSlot;
2555 [commandBuffer addCompletedHandler: ^(id<MTLCommandBuffer> cb) {
2556 swapChainD->d->lastGpuTime[thisFrameSlot] += cb.GPUEndTime - cb.GPUStartTime;
2557 dispatch_semaphore_signal(swapChainD->d->sem[thisFrameSlot]);
2564 id<MTLTexture> drawableTexture = [swapChainD->d->curDrawable.texture retain];
2565 [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>) {
2566 [drawableTexture release];
2570 if (flags.testFlag(QRhi::SkipPresent)) {
2572 [commandBuffer commit];
2574 if (id<CAMetalDrawable> drawable = swapChainD->d->curDrawable) {
2576 if (swapChainD
->d->layer.presentsWithTransaction) {
2577 [commandBuffer commit];
2579 auto *metalLayer = swapChainD
->d->layer;
2580 auto presentWithTransaction = ^{
2581 [commandBuffer waitUntilScheduled];
2588 const auto surfaceSize = QSizeF::fromCGSize(metalLayer.bounds.size) * metalLayer.contentsScale;
2589 const auto textureSize = QSizeF(drawable.texture.width, drawable.texture.height);
2590 if (textureSize == surfaceSize) {
2593 qCDebug(QRHI_LOG_INFO) <<
"Skipping" << drawable <<
"due to texture size"
2594 << textureSize <<
"not matching surface size" << surfaceSize;
2598 if (NSThread.currentThread == NSThread.mainThread) {
2599 presentWithTransaction();
2601 auto *qtMetalLayer = qt_objc_cast<QMetalLayer*>(swapChainD->d->layer);
2602 Q_ASSERT(qtMetalLayer);
2604 qtMetalLayer.mainThreadPresentation = presentWithTransaction;
2608 auto *qtMetalLayer = qt_objc_cast<QMetalLayer*>(swapChainD->d->layer);
2609 [commandBuffer addScheduledHandler:^(id<MTLCommandBuffer>) {
2615 if (qtMetalLayer.displayLock.tryLockForRead()) {
2617 qtMetalLayer.displayLock.unlock();
2619 qCDebug(QRHI_LOG_INFO) <<
"Skipping" << drawable
2620 <<
"due to" << qtMetalLayer <<
"needing display";
2626 [commandBuffer commit];
2630 [commandBuffer commit];
2637 [swapChainD->d->curDrawable release];
2638 swapChainD->d->curDrawable = nil;
2640 [d->captureScope endScope];
2644 return QRhi::FrameOpSuccess;
2651 currentFrameSlot = (currentFrameSlot + 1) % QMTL_FRAMES_IN_FLIGHT;
2653 for (QMetalSwapChain *sc : std::as_const(swapchains))
2654 sc->waitUntilCompleted(currentFrameSlot);
2656 d->ofr.active =
true;
2657 *cb = &
d->ofr.cbWrapper;
2658 d->ofr.cbWrapper.d->cb =
d->newCommandBuffer();
2661 d->ofr.cbWrapper.resetState(
d->ofr.lastGpuTime);
2662 d->ofr.lastGpuTime = 0;
2665 return QRhi::FrameOpSuccess;
2671 Q_ASSERT(
d->ofr.active);
2672 d->ofr.active =
false;
2674 id<MTLCommandBuffer> cb =
d->ofr.cbWrapper.d->cb;
2678 [cb waitUntilCompleted];
2680 d->ofr.lastGpuTime += cb.GPUEndTime - cb.GPUStartTime;
2684 return QRhi::FrameOpSuccess;
2689 id<MTLCommandBuffer> cb = nil;
2692 if (
d->ofr.active) {
2695 cb =
d->ofr.cbWrapper.d->cb;
2700 cb = swapChainD->cbWrapper.d->cb;
2704 for (QMetalSwapChain *sc : std::as_const(swapchains)) {
2705 for (
int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) {
2706 if (currentSwapChain && sc == currentSwapChain && i == currentFrameSlot) {
2711 sc->waitUntilCompleted(i);
2717 [cb waitUntilCompleted];
2721 if (
d->ofr.active) {
2722 d->ofr.lastGpuTime += cb.GPUEndTime - cb.GPUStartTime;
2723 d->ofr.cbWrapper.d->cb =
d->newCommandBuffer();
2725 swapChainD->d->lastGpuTime[currentFrameSlot] += cb.GPUEndTime - cb.GPUStartTime;
2726 swapChainD->cbWrapper.d->cb =
d->newCommandBuffer();
2734 return QRhi::FrameOpSuccess;
2738 const QColor &colorClearValue,
2739 const QRhiDepthStencilClearValue &depthStencilClearValue,
2741 QRhiShadingRateMap *shadingRateMap)
2743 MTLRenderPassDescriptor *rp = [MTLRenderPassDescriptor renderPassDescriptor];
2744 MTLClearColor c = MTLClearColorMake(colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
2745 colorClearValue.alphaF());
2747 for (uint i = 0; i < uint(colorAttCount); ++i) {
2748 rp.colorAttachments[i].loadAction = MTLLoadActionClear;
2749 rp.colorAttachments[i].storeAction = MTLStoreActionStore;
2750 rp.colorAttachments[i].clearColor = c;
2753 if (hasDepthStencil) {
2754 rp.depthAttachment.loadAction = MTLLoadActionClear;
2755 rp.depthAttachment.storeAction = MTLStoreActionDontCare;
2756 rp.stencilAttachment.loadAction = MTLLoadActionClear;
2757 rp.stencilAttachment.storeAction = MTLStoreActionDontCare;
2758 rp.depthAttachment.clearDepth =
double(depthStencilClearValue.depthClearValue());
2759 rp.stencilAttachment.clearStencil = depthStencilClearValue.stencilClearValue();
2763 rp.rasterizationRateMap =
QRHI_RES(QMetalShadingRateMap, shadingRateMap)->d->rateMap;
2771 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
2772 subresDesc.data().size() : subresDesc.image().sizeInBytes();
2773 if (imageSizeBytes > 0)
2774 size += aligned<qsizetype>(imageSizeBytes, QRhiMetalData::TEXBUF_ALIGN);
2779 int layer,
int level,
const QRhiTextureSubresourceUploadDescription &subresDesc,
2782 const QPoint dp = subresDesc.destinationTopLeft();
2783 const QByteArray rawData = subresDesc.data();
2784 QImage img = subresDesc.image();
2785 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
2786 id<MTLBlitCommandEncoder> blitEnc = (id<MTLBlitCommandEncoder>) blitEncPtr;
2788 if (!img.isNull()) {
2789 const qsizetype fullImageSizeBytes = img.sizeInBytes();
2790 QSize size = img.size();
2791 int bpl = img.bytesPerLine();
2793 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
2794 const int sx = subresDesc.sourceTopLeft().x();
2795 const int sy = subresDesc.sourceTopLeft().y();
2796 if (!subresDesc.sourceSize().isEmpty())
2797 size = subresDesc.sourceSize();
2798 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
2799 if (size.width() == img.width()) {
2800 const int bpc = qMax(1, img.depth() / 8);
2801 Q_ASSERT(size.height() * img.bytesPerLine() <= fullImageSizeBytes);
2802 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs,
2803 img.constBits() + sy * img.bytesPerLine() + sx * bpc,
2804 size.height() * img.bytesPerLine());
2806 img = img.copy(sx, sy, size.width(), size.height());
2807 bpl = img.bytesPerLine();
2808 Q_ASSERT(img.sizeInBytes() <= fullImageSizeBytes);
2809 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, img.constBits(), size_t(img.sizeInBytes()));
2812 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
2813 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, img.constBits(), size_t(fullImageSizeBytes));
2816 [blitEnc copyFromBuffer: texD->d->stagingBuf[currentFrameSlot]
2817 sourceOffset: NSUInteger(*curOfs)
2818 sourceBytesPerRow: NSUInteger(bpl)
2819 sourceBytesPerImage: 0
2820 sourceSize: MTLSizeMake(NSUInteger(size.width()), NSUInteger(size.height()), 1)
2821 toTexture: texD->d->tex
2822 destinationSlice: NSUInteger(is3D ? 0 : layer)
2823 destinationLevel: NSUInteger(level)
2824 destinationOrigin: MTLOriginMake(NSUInteger(dp.x()), NSUInteger(dp.y()), NSUInteger(is3D ? layer : 0))
2825 options: MTLBlitOptionNone];
2827 *curOfs += aligned<qsizetype>(fullImageSizeBytes, QRhiMetalData::TEXBUF_ALIGN);
2828 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
2829 const QSize subresSize = q->sizeForMipLevel(level, texD->m_pixelSize);
2830 const int subresw = subresSize.width();
2831 const int subresh = subresSize.height();
2833 if (subresDesc.sourceSize().isEmpty()) {
2837 w = subresDesc.sourceSize().width();
2838 h = subresDesc.sourceSize().height();
2843 compressedFormatInfo(texD->m_format, QSize(w, h), &bpl,
nullptr, &blockDim);
2845 const int dx = aligned(dp.x(), blockDim.width());
2846 const int dy = aligned(dp.y(), blockDim.height());
2847 if (dx + w != subresw)
2848 w = aligned(w, blockDim.width());
2849 if (dy + h != subresh)
2850 h = aligned(h, blockDim.height());
2852 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, rawData.constData(), size_t(rawData.size()));
2854 [blitEnc copyFromBuffer: texD->d->stagingBuf[currentFrameSlot]
2855 sourceOffset: NSUInteger(*curOfs)
2856 sourceBytesPerRow: bpl
2857 sourceBytesPerImage: 0
2858 sourceSize: MTLSizeMake(NSUInteger(w), NSUInteger(h), 1)
2859 toTexture: texD->d->tex
2860 destinationSlice: NSUInteger(is3D ? 0 : layer)
2861 destinationLevel: NSUInteger(level)
2862 destinationOrigin: MTLOriginMake(NSUInteger(dx), NSUInteger(dy), NSUInteger(is3D ? layer : 0))
2863 options: MTLBlitOptionNone];
2865 *curOfs += aligned<qsizetype>(rawData.size(), QRhiMetalData::TEXBUF_ALIGN);
2866 }
else if (!rawData.isEmpty()) {
2867 const QSize subresSize = q->sizeForMipLevel(level, texD->m_pixelSize);
2868 const int subresw = subresSize.width();
2869 const int subresh = subresSize.height();
2871 if (subresDesc.sourceSize().isEmpty()) {
2875 w = subresDesc.sourceSize().width();
2876 h = subresDesc.sourceSize().height();
2880 if (subresDesc.dataStride())
2881 bpl = subresDesc.dataStride();
2883 textureFormatInfo(texD->m_format, QSize(w, h), &bpl,
nullptr,
nullptr);
2885 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, rawData.constData(), size_t(rawData.size()));
2887 [blitEnc copyFromBuffer: texD->d->stagingBuf[currentFrameSlot]
2888 sourceOffset: NSUInteger(*curOfs)
2889 sourceBytesPerRow: bpl
2890 sourceBytesPerImage: 0
2891 sourceSize: MTLSizeMake(NSUInteger(w), NSUInteger(h), 1)
2892 toTexture: texD->d->tex
2893 destinationSlice: NSUInteger(is3D ? 0 : layer)
2894 destinationLevel: NSUInteger(level)
2895 destinationOrigin: MTLOriginMake(NSUInteger(dp.x()), NSUInteger(dp.y()), NSUInteger(is3D ? layer : 0))
2896 options: MTLBlitOptionNone];
2898 *curOfs += aligned<qsizetype>(rawData.size(), QRhiMetalData::TEXBUF_ALIGN);
2900 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
2909 id<MTLBlitCommandEncoder> blitEnc = nil;
2910 auto ensureBlit = [&blitEnc, cbD,
this]() {
2912 blitEnc = [cbD->d->cb blitCommandEncoder];
2914 [blitEnc pushDebugGroup: @
"Texture upload/copy"];
2922 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
2924 if (u.offset == 0 && u
.data.size() == bufD->m_size)
2925 bufD
->d->pendingUpdates[i].clear();
2926 bufD
->d->pendingUpdates[i].append({ u.offset, u
.data });
2932 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
2933 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
2935 bufD
->d->pendingUpdates[i].append({ u.offset, u
.data });
2939 const int idx = bufD->d->slotted ? currentFrameSlot : 0;
2940 if (bufD->m_type == QRhiBuffer::Dynamic) {
2941 char *p =
reinterpret_cast<
char *>([bufD->d->buf[idx] contents]);
2943 u.result->data.resize(u.readSize);
2944 memcpy(u.result->data.data(), p + u.offset, size_t(u.readSize));
2946 if (u.result->completed)
2947 u.result->completed();
2951 readback.buf = bufD
->d->buf[idx];
2952 readback.offset = u.offset;
2953 readback.readSize = u.readSize;
2954 readback.result = u.result;
2955 d->activeBufferReadbacks.append(readback);
2957 if (bufD->d->managed) {
2960 [blitEnc synchronizeResource:readback.buf];
2971 qsizetype stagingSize = 0;
2972 for (
int layer = 0, maxLayer = u.subresDesc.count(); layer < maxLayer; ++layer) {
2973 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
2974 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
2975 stagingSize += subresUploadByteSize(subresDesc);
2980 Q_ASSERT(!utexD->d->stagingBuf[currentFrameSlot]);
2981 utexD->d->stagingBuf[currentFrameSlot] = [d->dev newBufferWithLength: NSUInteger(stagingSize)
2982 options: MTLResourceStorageModeShared];
2984 void *mp = [utexD->d->stagingBuf[currentFrameSlot] contents];
2985 qsizetype curOfs = 0;
2986 for (
int layer = 0, maxLayer = u.subresDesc.count(); layer < maxLayer; ++layer) {
2987 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
2988 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
2989 enqueueSubresUpload(utexD, mp, blitEnc, layer, level, subresDesc, &curOfs);
2993 utexD->lastActiveFrameSlot = currentFrameSlot;
2997 e.lastActiveFrameSlot = currentFrameSlot;
2998 e.stagingBuffer.buffer = utexD->d->stagingBuf[currentFrameSlot];
2999 utexD->d->stagingBuf[currentFrameSlot] = nil;
3000 d->releaseQueue.append(e);
3005 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3006 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3007 const QPoint dp = u.desc.destinationTopLeft();
3008 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
3009 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
3010 const QPoint sp = u.desc.sourceTopLeft();
3013 [blitEnc copyFromTexture: srcD->d->tex
3014 sourceSlice: NSUInteger(srcIs3D ? 0 : u.desc.sourceLayer())
3015 sourceLevel: NSUInteger(u.desc.sourceLevel())
3016 sourceOrigin: MTLOriginMake(NSUInteger(sp.x()), NSUInteger(sp.y()), NSUInteger(srcIs3D ? u.desc.sourceLayer() : 0))
3017 sourceSize: MTLSizeMake(NSUInteger(copySize.width()), NSUInteger(copySize.height()), 1)
3018 toTexture: dstD->d->tex
3019 destinationSlice: NSUInteger(dstIs3D ? 0 : u.desc.destinationLayer())
3020 destinationLevel: NSUInteger(u.desc.destinationLevel())
3021 destinationOrigin: MTLOriginMake(NSUInteger(dp.x()), NSUInteger(dp.y()), NSUInteger(dstIs3D ? u.desc.destinationLayer() : 0))];
3023 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
3026 readback.activeFrameSlot = currentFrameSlot;
3027 readback.desc = u.rb;
3028 readback.result = u.result;
3037 qWarning(
"Multisample texture cannot be read back");
3040 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3041 if (u.rb.rect().isValid())
3044 rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
3045 readback.format = texD->m_format;
3047 texD->lastActiveFrameSlot = currentFrameSlot;
3051 if (u.rb.rect().isValid())
3054 rect = QRect({0, 0}, swapChainD->pixelSize);
3055 readback.format = swapChainD
->d->rhiColorFormat;
3059 src = colorAtt.resolveTex ? colorAtt.resolveTex : colorAtt.tex;
3061 readback.pixelSize = rect.size();
3064 textureFormatInfo(readback.format, readback.pixelSize, &bpl, &readback.bufSize,
nullptr);
3065 readback.buf = [d->dev newBufferWithLength: readback.bufSize options: MTLResourceStorageModeShared];
3068 [blitEnc copyFromTexture: src
3069 sourceSlice: NSUInteger(is3D ? 0 : u.rb.layer())
3070 sourceLevel: NSUInteger(u.rb.level())
3071 sourceOrigin: MTLOriginMake(NSUInteger(rect.x()), NSUInteger(rect.y()), NSUInteger(is3D ? u.rb.layer() : 0))
3072 sourceSize: MTLSizeMake(NSUInteger(rect.width()), NSUInteger(rect.height()), 1)
3073 toBuffer: readback.buf
3074 destinationOffset: 0
3075 destinationBytesPerRow: bpl
3076 destinationBytesPerImage: 0
3077 options: MTLBlitOptionNone];
3079 d->activeTextureReadbacks.append(readback);
3083 [blitEnc generateMipmapsForTexture: utexD->d->tex];
3084 utexD->lastActiveFrameSlot = currentFrameSlot;
3090 [blitEnc popDebugGroup];
3091 [blitEnc endEncoding];
3100 if (bufD
->d->pendingUpdates[slot].isEmpty())
3103 void *p = [bufD->d->buf[slot] contents];
3104 quint32 changeBegin = UINT32_MAX;
3105 quint32 changeEnd = 0;
3106 for (
const QMetalBufferData::BufferUpdate &u : std::as_const(bufD->d->pendingUpdates[slot])) {
3107 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
3108 if (u.offset < changeBegin)
3109 changeBegin = u.offset;
3110 if (u.offset + u.data.size() > changeEnd)
3111 changeEnd = u.offset + u.data.size();
3114 if (changeBegin < UINT32_MAX && changeBegin < changeEnd && bufD->d->managed)
3115 [bufD->d->buf[slot] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))];
3118 bufD
->d->pendingUpdates[slot].clear();
3128 Q_ASSERT(
QRHI_RES(QMetalCommandBuffer, cb)->recordingPass == QMetalCommandBuffer::NoPass);
3134 QRhiRenderTarget *rt,
3135 const QColor &colorClearValue,
3136 const QRhiDepthStencilClearValue &depthStencilClearValue,
3137 QRhiResourceUpdateBatch *resourceUpdates,
3143 if (resourceUpdates)
3147 switch (rt->resourceType()) {
3148 case QRhiResource::SwapChainRenderTarget:
3152 QRhiShadingRateMap *shadingRateMap = rtSc->swapChain()->shadingRateMap();
3155 depthStencilClearValue,
3163 if (!swapChainD
->d->curDrawable) {
3164 QMacAutoReleasePool pool;
3165 swapChainD->d->curDrawable = [[swapChainD->d->layer nextDrawable] retain];
3167 if (!swapChainD
->d->curDrawable) {
3168 qWarning(
"No drawable");
3171 id<MTLTexture> scTex = swapChainD
->d->curDrawable.texture;
3176 color0.resolveTex = scTex;
3182 QRHI_RES(QMetalShadingRateMap, shadingRateMap)->lastActiveFrameSlot = currentFrameSlot;
3185 case QRhiResource::TextureRenderTarget:
3189 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QMetalTexture, QMetalRenderBuffer>(rtTex->description(), rtD->currentResIdList))
3193 depthStencilClearValue,
3195 rtTex->m_desc.shadingRateMap());
3196 if (rtD->fb.preserveColor) {
3197 for (uint i = 0; i < uint(rtD->colorAttCount); ++i)
3198 cbD->d->currentPassRpDesc.colorAttachments[i].loadAction = MTLLoadActionLoad;
3201 cbD->d->currentPassRpDesc.depthAttachment.loadAction = MTLLoadActionLoad;
3202 cbD->d->currentPassRpDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
3204 int colorAttCount = 0;
3205 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
3209 if (it->texture()) {
3210 QRHI_RES(QMetalTexture, it->texture())->lastActiveFrameSlot = currentFrameSlot;
3211 if (it->multiViewCount() >= 2)
3212 cbD
->d->currentPassRpDesc.renderTargetArrayLength = NSUInteger(it->multiViewCount());
3213 }
else if (it->renderBuffer()) {
3214 QRHI_RES(QMetalRenderBuffer, it->renderBuffer())->lastActiveFrameSlot = currentFrameSlot;
3216 if (it->resolveTexture())
3217 QRHI_RES(QMetalTexture, it->resolveTexture())->lastActiveFrameSlot = currentFrameSlot;
3219 if (rtTex->m_desc.depthStencilBuffer())
3220 QRHI_RES(QMetalRenderBuffer, rtTex->m_desc.depthStencilBuffer())->lastActiveFrameSlot = currentFrameSlot;
3221 if (rtTex->m_desc.depthTexture()) {
3223 depthTexture->lastActiveFrameSlot = currentFrameSlot;
3224 if (colorAttCount == 0 && depthTexture->arraySize() >= 2)
3225 cbD
->d->currentPassRpDesc.renderTargetArrayLength = NSUInteger(depthTexture->arraySize());
3227 if (rtTex->m_desc.depthResolveTexture())
3228 QRHI_RES(QMetalTexture, rtTex->m_desc.depthResolveTexture())->lastActiveFrameSlot = currentFrameSlot;
3229 if (rtTex->m_desc.shadingRateMap())
3230 QRHI_RES(QMetalShadingRateMap, rtTex->m_desc.shadingRateMap())->lastActiveFrameSlot = currentFrameSlot;
3239 cbD
->d->currentPassRpDesc.colorAttachments[i].texture = rtD->fb.colorAtt[i].tex;
3240 cbD
->d->currentPassRpDesc.colorAttachments[i].slice = NSUInteger(rtD->fb.colorAtt[i].arrayLayer);
3241 cbD
->d->currentPassRpDesc.colorAttachments[i].depthPlane = NSUInteger(rtD->fb.colorAtt[i].slice);
3242 cbD
->d->currentPassRpDesc.colorAttachments[i].level = NSUInteger(rtD->fb.colorAtt[i].level);
3243 if (rtD->fb.colorAtt[i].resolveTex) {
3244 cbD->d->currentPassRpDesc.colorAttachments[i].storeAction = rtD->fb.preserveColor ? MTLStoreActionStoreAndMultisampleResolve
3245 : MTLStoreActionMultisampleResolve;
3246 cbD
->d->currentPassRpDesc.colorAttachments[i].resolveTexture = rtD->fb.colorAtt[i].resolveTex;
3247 cbD
->d->currentPassRpDesc.colorAttachments[i].resolveSlice = NSUInteger(rtD->fb.colorAtt[i].resolveLayer);
3248 cbD
->d->currentPassRpDesc.colorAttachments[i].resolveLevel = NSUInteger(rtD->fb.colorAtt[i].resolveLevel);
3253 Q_ASSERT(rtD->fb.dsTex);
3254 cbD
->d->currentPassRpDesc.depthAttachment.texture = rtD->fb.dsTex;
3255 cbD->d->currentPassRpDesc.stencilAttachment.texture = rtD->fb.hasStencil ? rtD->fb.dsTex : nil;
3256 if (rtD->fb.depthNeedsStore)
3257 cbD->d->currentPassRpDesc.depthAttachment.storeAction = MTLStoreActionStore;
3258 if (rtD->fb.dsResolveTex) {
3259 cbD->d->currentPassRpDesc.depthAttachment.storeAction = rtD->fb.depthNeedsStore ? MTLStoreActionStoreAndMultisampleResolve
3260 : MTLStoreActionMultisampleResolve;
3261 cbD
->d->currentPassRpDesc.depthAttachment.resolveTexture = rtD->fb.dsResolveTex;
3262 if (rtD->fb.hasStencil) {
3263 cbD
->d->currentPassRpDesc.stencilAttachment.resolveTexture = rtD->fb.dsResolveTex;
3264 cbD
->d->currentPassRpDesc.stencilAttachment.storeAction = cbD
->d->currentPassRpDesc.depthAttachment.storeAction;
3269 cbD->d->currentRenderPassEncoder = [cbD->d->cb renderCommandEncoderWithDescriptor: cbD->d->currentPassRpDesc];
3274 cbD->currentTarget = rt;
3282 [cbD->d->currentRenderPassEncoder endEncoding];
3285 cbD->currentTarget =
nullptr;
3287 if (resourceUpdates)
3292 QRhiResourceUpdateBatch *resourceUpdates,
3298 if (resourceUpdates)
3301 cbD->d->currentComputePassEncoder = [cbD->d->cb computeCommandEncoder];
3311 [cbD->d->currentComputePassEncoder endEncoding];
3314 if (resourceUpdates)
3327 cbD->currentPipelineGeneration = psD->generation;
3329 [cbD->d->currentComputePassEncoder setComputePipelineState: psD->d->ps];
3332 psD->lastActiveFrameSlot = currentFrameSlot;
3341 [cbD->d->currentComputePassEncoder dispatchThreadgroups: MTLSizeMake(NSUInteger(x), NSUInteger(y), NSUInteger(z))
3342 threadsPerThreadgroup: psD->d->localSize];
3347 for (
int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
3348 [e.buffer.buffers[i] release];
3353 [e.renderbuffer.texture release];
3358 [e.texture.texture release];
3359 for (
int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
3360 [e.texture.stagingBuffers[i] release];
3361 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
3362 [e.texture.views[i] release];
3367 [e.sampler.samplerState release];
3372 for (
int i =
d->releaseQueue.count() - 1; i >= 0; --i) {
3374 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
3388 case QRhiMetalData::DeferredReleaseEntry::StagingBuffer:
3389 [e.stagingBuffer.buffer release];
3391 case QRhiMetalData::DeferredReleaseEntry::GraphicsPipeline:
3392 [e.graphicsPipeline.pipelineState release];
3393 [e.graphicsPipeline.depthStencilState release];
3394 [e.graphicsPipeline.tessVertexComputeState[0] release];
3395 [e.graphicsPipeline.tessVertexComputeState[1] release];
3396 [e.graphicsPipeline.tessVertexComputeState[2] release];
3397 [e.graphicsPipeline.tessTessControlComputeState release];
3399 case QRhiMetalData::DeferredReleaseEntry::ComputePipeline:
3400 [e.computePipeline.pipelineState release];
3402 case QRhiMetalData::DeferredReleaseEntry::ShadingRateMap:
3403 [e.shadingRateMap.rateMap release];
3408 d->releaseQueue.removeAt(i);
3415 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
3417 for (
int i =
d->activeTextureReadbacks.count() - 1; i >= 0; --i) {
3419 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
3420 readback.result->format = readback.format;
3421 readback.result->pixelSize = readback.pixelSize;
3422 readback.result->data.resize(
int(readback.bufSize));
3423 void *p = [readback.buf contents];
3424 memcpy(readback.result->data.data(), p, readback.bufSize);
3425 [readback.buf release];
3427 if (readback.result->completed)
3428 completedCallbacks.append(readback.result->completed);
3430 d->activeTextureReadbacks.remove(i);
3434 for (
int i =
d->activeBufferReadbacks.count() - 1; i >= 0; --i) {
3436 if (forced || currentFrameSlot == readback.activeFrameSlot
3437 || readback.activeFrameSlot < 0) {
3438 readback.result->data.resize(readback.readSize);
3439 char *p =
reinterpret_cast<
char *>([readback.buf contents]);
3441 memcpy(readback.result->data.data(), p + readback.offset, size_t(readback.readSize));
3443 if (readback.result->completed)
3444 completedCallbacks.append(readback.result->completed);
3446 d->activeBufferReadbacks.remove(i);
3450 for (
auto f : completedCallbacks)
3458 for (
int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
3478 e.buffer.buffers[i] =
d->buf[i];
3480 d->pendingUpdates[i].clear();
3485 rhiD
->d->releaseQueue.append(e);
3486 rhiD->unregisterResource(
this);
3495 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
3496 qWarning(
"StorageBuffer cannot be combined with Dynamic");
3500 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
3501 const quint32 roundedSize = m_usage.testFlag(QRhiBuffer::UniformBuffer) ? aligned(nonZeroSize, 256u) : nonZeroSize;
3504 MTLResourceOptions opts = MTLResourceStorageModeShared;
3508 if (!rhiD->caps.isAppleGPU && m_type != Dynamic) {
3509 opts = MTLResourceStorageModeManaged;
3518 d->slotted = !m_usage.testFlag(QRhiBuffer::StorageBuffer);
3520 if (
int(m_usage) == WorkBufPoolUsage)
3525 d->buf[i] = [rhiD->d->dev newBufferWithLength: roundedSize options: opts];
3526 if (!m_objectName.isEmpty()) {
3528 d->buf[i].label = [NSString stringWithUTF8String: m_objectName.constData()];
3530 const QByteArray name = m_objectName +
'/' + QByteArray::number(i);
3531 d->buf[i].label = [NSString stringWithUTF8String: name.constData()];
3539 rhiD->registerResource(
this);
3551 b.objects[i] = &
d->buf[i];
3556 return { { &
d->buf[0] }, 1 };
3566 Q_ASSERT(m_type == Dynamic);
3568 Q_ASSERT(rhiD->inFrame);
3569 const int slot = rhiD->currentFrameSlot;
3570 void *p = [d->buf[slot] contents];
3571 return static_cast<
char *>(p);
3578 QRHI_RES_RHI(QRhiMetal);
3579 const int slot = rhiD->currentFrameSlot;
3580 [d->buf[slot] didModifyRange: NSMakeRange(0, NSUInteger(m_size))];
3591 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
3593 case QRhiTexture::RGBA8:
3594 return srgb ? MTLPixelFormatRGBA8Unorm_sRGB : MTLPixelFormatRGBA8Unorm;
3595 case QRhiTexture::BGRA8:
3596 return srgb ? MTLPixelFormatBGRA8Unorm_sRGB : MTLPixelFormatBGRA8Unorm;
3597 case QRhiTexture::R8:
3599 return MTLPixelFormatR8Unorm;
3601 return srgb ? MTLPixelFormatR8Unorm_sRGB : MTLPixelFormatR8Unorm;
3603 case QRhiTexture::R8SI:
3604 return MTLPixelFormatR8Sint;
3605 case QRhiTexture::R8UI:
3606 return MTLPixelFormatR8Uint;
3607 case QRhiTexture::RG8:
3609 return MTLPixelFormatRG8Unorm;
3611 return srgb ? MTLPixelFormatRG8Unorm_sRGB : MTLPixelFormatRG8Unorm;
3613 case QRhiTexture::R16:
3614 return MTLPixelFormatR16Unorm;
3615 case QRhiTexture::RG16:
3616 return MTLPixelFormatRG16Unorm;
3617 case QRhiTexture::RED_OR_ALPHA8:
3618 return MTLPixelFormatR8Unorm;
3620 case QRhiTexture::RGBA16F:
3621 return MTLPixelFormatRGBA16Float;
3622 case QRhiTexture::RGBA32F:
3623 return MTLPixelFormatRGBA32Float;
3624 case QRhiTexture::R16F:
3625 return MTLPixelFormatR16Float;
3626 case QRhiTexture::R32F:
3627 return MTLPixelFormatR32Float;
3629 case QRhiTexture::RGB10A2:
3630 return MTLPixelFormatRGB10A2Unorm;
3632 case QRhiTexture::R32SI:
3633 return MTLPixelFormatR32Sint;
3634 case QRhiTexture::R32UI:
3635 return MTLPixelFormatR32Uint;
3636 case QRhiTexture::RG32SI:
3637 return MTLPixelFormatRG32Sint;
3638 case QRhiTexture::RG32UI:
3639 return MTLPixelFormatRG32Uint;
3640 case QRhiTexture::RGBA32SI:
3641 return MTLPixelFormatRGBA32Sint;
3642 case QRhiTexture::RGBA32UI:
3643 return MTLPixelFormatRGBA32Uint;
3646 case QRhiTexture::D16:
3647 return MTLPixelFormatDepth16Unorm;
3648 case QRhiTexture::D24:
3649 return [d->d->dev isDepth24Stencil8PixelFormatSupported] ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float;
3650 case QRhiTexture::D24S8:
3651 return [d->d->dev isDepth24Stencil8PixelFormatSupported] ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8;
3653 case QRhiTexture::D16:
3654 return MTLPixelFormatDepth32Float;
3655 case QRhiTexture::D24:
3656 return MTLPixelFormatDepth32Float;
3657 case QRhiTexture::D24S8:
3658 return MTLPixelFormatDepth32Float_Stencil8;
3660 case QRhiTexture::D32F:
3661 return MTLPixelFormatDepth32Float;
3662 case QRhiTexture::D32FS8:
3663 return MTLPixelFormatDepth32Float_Stencil8;
3666 case QRhiTexture::BC1:
3667 return srgb ? MTLPixelFormatBC1_RGBA_sRGB : MTLPixelFormatBC1_RGBA;
3668 case QRhiTexture::BC2:
3669 return srgb ? MTLPixelFormatBC2_RGBA_sRGB : MTLPixelFormatBC2_RGBA;
3670 case QRhiTexture::BC3:
3671 return srgb ? MTLPixelFormatBC3_RGBA_sRGB : MTLPixelFormatBC3_RGBA;
3672 case QRhiTexture::BC4:
3673 return MTLPixelFormatBC4_RUnorm;
3674 case QRhiTexture::BC5:
3675 qWarning(
"QRhiMetal does not support BC5");
3676 return MTLPixelFormatInvalid;
3677 case QRhiTexture::BC6H:
3678 return MTLPixelFormatBC6H_RGBUfloat;
3679 case QRhiTexture::BC7:
3680 return srgb ? MTLPixelFormatBC7_RGBAUnorm_sRGB : MTLPixelFormatBC7_RGBAUnorm;
3682 case QRhiTexture::BC1:
3683 case QRhiTexture::BC2:
3684 case QRhiTexture::BC3:
3685 case QRhiTexture::BC4:
3686 case QRhiTexture::BC5:
3687 case QRhiTexture::BC6H:
3688 case QRhiTexture::BC7:
3689 qWarning(
"QRhiMetal: BCx compression not supported on this platform");
3690 return MTLPixelFormatInvalid;
3694 case QRhiTexture::ETC2_RGB8:
3695 return srgb ? MTLPixelFormatETC2_RGB8_sRGB : MTLPixelFormatETC2_RGB8;
3696 case QRhiTexture::ETC2_RGB8A1:
3697 return srgb ? MTLPixelFormatETC2_RGB8A1_sRGB : MTLPixelFormatETC2_RGB8A1;
3698 case QRhiTexture::ETC2_RGBA8:
3699 return srgb ? MTLPixelFormatEAC_RGBA8_sRGB : MTLPixelFormatEAC_RGBA8;
3701 case QRhiTexture::ASTC_4x4:
3702 return srgb ? MTLPixelFormatASTC_4x4_sRGB : MTLPixelFormatASTC_4x4_LDR;
3703 case QRhiTexture::ASTC_5x4:
3704 return srgb ? MTLPixelFormatASTC_5x4_sRGB : MTLPixelFormatASTC_5x4_LDR;
3705 case QRhiTexture::ASTC_5x5:
3706 return srgb ? MTLPixelFormatASTC_5x5_sRGB : MTLPixelFormatASTC_5x5_LDR;
3707 case QRhiTexture::ASTC_6x5:
3708 return srgb ? MTLPixelFormatASTC_6x5_sRGB : MTLPixelFormatASTC_6x5_LDR;
3709 case QRhiTexture::ASTC_6x6:
3710 return srgb ? MTLPixelFormatASTC_6x6_sRGB : MTLPixelFormatASTC_6x6_LDR;
3711 case QRhiTexture::ASTC_8x5:
3712 return srgb ? MTLPixelFormatASTC_8x5_sRGB : MTLPixelFormatASTC_8x5_LDR;
3713 case QRhiTexture::ASTC_8x6:
3714 return srgb ? MTLPixelFormatASTC_8x6_sRGB : MTLPixelFormatASTC_8x6_LDR;
3715 case QRhiTexture::ASTC_8x8:
3716 return srgb ? MTLPixelFormatASTC_8x8_sRGB : MTLPixelFormatASTC_8x8_LDR;
3717 case QRhiTexture::ASTC_10x5:
3718 return srgb ? MTLPixelFormatASTC_10x5_sRGB : MTLPixelFormatASTC_10x5_LDR;
3719 case QRhiTexture::ASTC_10x6:
3720 return srgb ? MTLPixelFormatASTC_10x6_sRGB : MTLPixelFormatASTC_10x6_LDR;
3721 case QRhiTexture::ASTC_10x8:
3722 return srgb ? MTLPixelFormatASTC_10x8_sRGB : MTLPixelFormatASTC_10x8_LDR;
3723 case QRhiTexture::ASTC_10x10:
3724 return srgb ? MTLPixelFormatASTC_10x10_sRGB : MTLPixelFormatASTC_10x10_LDR;
3725 case QRhiTexture::ASTC_12x10:
3726 return srgb ? MTLPixelFormatASTC_12x10_sRGB : MTLPixelFormatASTC_12x10_LDR;
3727 case QRhiTexture::ASTC_12x12:
3728 return srgb ? MTLPixelFormatASTC_12x12_sRGB : MTLPixelFormatASTC_12x12_LDR;
3730 case QRhiTexture::ETC2_RGB8:
3731 if (d->caps.isAppleGPU)
3732 return srgb ? MTLPixelFormatETC2_RGB8_sRGB : MTLPixelFormatETC2_RGB8;
3733 qWarning(
"QRhiMetal: ETC2 compression not supported on this platform");
3734 return MTLPixelFormatInvalid;
3735 case QRhiTexture::ETC2_RGB8A1:
3736 if (d->caps.isAppleGPU)
3737 return srgb ? MTLPixelFormatETC2_RGB8A1_sRGB : MTLPixelFormatETC2_RGB8A1;
3738 qWarning(
"QRhiMetal: ETC2 compression not supported on this platform");
3739 return MTLPixelFormatInvalid;
3740 case QRhiTexture::ETC2_RGBA8:
3741 if (d->caps.isAppleGPU)
3742 return srgb ? MTLPixelFormatEAC_RGBA8_sRGB : MTLPixelFormatEAC_RGBA8;
3743 qWarning(
"QRhiMetal: ETC2 compression not supported on this platform");
3744 return MTLPixelFormatInvalid;
3745 case QRhiTexture::ASTC_4x4:
3746 if (d->caps.isAppleGPU)
3747 return srgb ? MTLPixelFormatASTC_4x4_sRGB : MTLPixelFormatASTC_4x4_LDR;
3748 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3749 return MTLPixelFormatInvalid;
3750 case QRhiTexture::ASTC_5x4:
3751 if (d->caps.isAppleGPU)
3752 return srgb ? MTLPixelFormatASTC_5x4_sRGB : MTLPixelFormatASTC_5x4_LDR;
3753 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3754 return MTLPixelFormatInvalid;
3755 case QRhiTexture::ASTC_5x5:
3756 if (d->caps.isAppleGPU)
3757 return srgb ? MTLPixelFormatASTC_5x5_sRGB : MTLPixelFormatASTC_5x5_LDR;
3758 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3759 return MTLPixelFormatInvalid;
3760 case QRhiTexture::ASTC_6x5:
3761 if (d->caps.isAppleGPU)
3762 return srgb ? MTLPixelFormatASTC_6x5_sRGB : MTLPixelFormatASTC_6x5_LDR;
3763 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3764 return MTLPixelFormatInvalid;
3765 case QRhiTexture::ASTC_6x6:
3766 if (d->caps.isAppleGPU)
3767 return srgb ? MTLPixelFormatASTC_6x6_sRGB : MTLPixelFormatASTC_6x6_LDR;
3768 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3769 return MTLPixelFormatInvalid;
3770 case QRhiTexture::ASTC_8x5:
3771 if (d->caps.isAppleGPU)
3772 return srgb ? MTLPixelFormatASTC_8x5_sRGB : MTLPixelFormatASTC_8x5_LDR;
3773 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3774 return MTLPixelFormatInvalid;
3775 case QRhiTexture::ASTC_8x6:
3776 if (d->caps.isAppleGPU)
3777 return srgb ? MTLPixelFormatASTC_8x6_sRGB : MTLPixelFormatASTC_8x6_LDR;
3778 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3779 return MTLPixelFormatInvalid;
3780 case QRhiTexture::ASTC_8x8:
3781 if (d->caps.isAppleGPU)
3782 return srgb ? MTLPixelFormatASTC_8x8_sRGB : MTLPixelFormatASTC_8x8_LDR;
3783 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3784 return MTLPixelFormatInvalid;
3785 case QRhiTexture::ASTC_10x5:
3786 if (d->caps.isAppleGPU)
3787 return srgb ? MTLPixelFormatASTC_10x5_sRGB : MTLPixelFormatASTC_10x5_LDR;
3788 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3789 return MTLPixelFormatInvalid;
3790 case QRhiTexture::ASTC_10x6:
3791 if (d->caps.isAppleGPU)
3792 return srgb ? MTLPixelFormatASTC_10x6_sRGB : MTLPixelFormatASTC_10x6_LDR;
3793 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3794 return MTLPixelFormatInvalid;
3795 case QRhiTexture::ASTC_10x8:
3796 if (d->caps.isAppleGPU)
3797 return srgb ? MTLPixelFormatASTC_10x8_sRGB : MTLPixelFormatASTC_10x8_LDR;
3798 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3799 return MTLPixelFormatInvalid;
3800 case QRhiTexture::ASTC_10x10:
3801 if (d->caps.isAppleGPU)
3802 return srgb ? MTLPixelFormatASTC_10x10_sRGB : MTLPixelFormatASTC_10x10_LDR;
3803 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3804 return MTLPixelFormatInvalid;
3805 case QRhiTexture::ASTC_12x10:
3806 if (d->caps.isAppleGPU)
3807 return srgb ? MTLPixelFormatASTC_12x10_sRGB : MTLPixelFormatASTC_12x10_LDR;
3808 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3809 return MTLPixelFormatInvalid;
3810 case QRhiTexture::ASTC_12x12:
3811 if (d->caps.isAppleGPU)
3812 return srgb ? MTLPixelFormatASTC_12x12_sRGB : MTLPixelFormatASTC_12x12_LDR;
3813 qWarning(
"QRhiMetal: ASTC compression not supported on this platform");
3814 return MTLPixelFormatInvalid;
3819 return MTLPixelFormatInvalid;
3824 int sampleCount, QRhiRenderBuffer::Flags flags,
3825 QRhiTexture::Format backingFormatHint)
3846 e.renderbuffer.texture =
d->tex;
3851 rhiD
->d->releaseQueue.append(e);
3852 rhiD->unregisterResource(
this);
3861 if (m_pixelSize.isEmpty())
3865 samples = rhiD->effectiveSampleCount(m_sampleCount);
3867 MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc] init];
3868 desc.textureType = samples > 1 ? MTLTextureType2DMultisample : MTLTextureType2D;
3869 desc.width = NSUInteger(m_pixelSize.width());
3870 desc.height = NSUInteger(m_pixelSize.height());
3872 desc.sampleCount = NSUInteger(
samples);
3873 desc.resourceOptions = MTLResourceStorageModePrivate;
3874 desc.usage = MTLTextureUsageRenderTarget;
3879 if (rhiD->caps.isAppleGPU) {
3880 desc.storageMode = MTLStorageModeMemoryless;
3881 d->format = MTLPixelFormatDepth32Float_Stencil8;
3883 desc.storageMode = MTLStorageModePrivate;
3884 d->format = rhiD->d->dev.depth24Stencil8PixelFormatSupported
3885 ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8;
3888 desc.storageMode = MTLStorageModeMemoryless;
3889 d->format = MTLPixelFormatDepth32Float_Stencil8;
3891 desc.pixelFormat =
d->format;
3894 desc.storageMode = MTLStorageModePrivate;
3895 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
3896 d->format = toMetalTextureFormat(m_backingFormatHint, {}, rhiD);
3898 d->format = MTLPixelFormatRGBA8Unorm;
3899 desc.pixelFormat =
d->format;
3906 d->tex = [rhiD->d->dev newTextureWithDescriptor: desc];
3909 if (!m_objectName.isEmpty())
3910 d->tex.label = [NSString stringWithUTF8String: m_objectName.constData()];
3914 rhiD->registerResource(
this);
3920 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
3921 return m_backingFormatHint;
3923 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
3927 int arraySize,
int sampleCount, Flags flags)
3931 for (
int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
3932 d->stagingBuf[i] = nil;
3934 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
3935 d->perLevelViews[i] = nil;
3953 e.texture.texture = d->owns ? d->tex : nil;
3957 e.texture.stagingBuffers[i] =
d->stagingBuf[i];
3958 d->stagingBuf[i] = nil;
3961 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
3962 e.texture.views[i] =
d->perLevelViews[i];
3963 d->perLevelViews[i] = nil;
3968 rhiD
->d->releaseQueue.append(e);
3969 rhiD->unregisterResource(
this);
3978 const bool isCube = m_flags.testFlag(CubeMap);
3979 const bool is3D = m_flags.testFlag(ThreeDimensional);
3980 const bool isArray = m_flags.testFlag(TextureArray);
3981 const bool hasMipMaps = m_flags.testFlag(MipMapped);
3982 const bool is1D = m_flags.testFlag(OneDimensional);
3984 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
3985 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
3988 d->format = toMetalTextureFormat(m_format, m_flags, rhiD);
3989 mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
3990 samples = rhiD->effectiveSampleCount(m_sampleCount);
3993 qWarning(
"Cubemap texture cannot be multisample");
3997 qWarning(
"3D texture cannot be multisample");
4001 qWarning(
"Multisample texture cannot have mipmaps");
4005 if (isCube && is3D) {
4006 qWarning(
"Texture cannot be both cube and 3D");
4009 if (isArray && is3D) {
4010 qWarning(
"Texture cannot be both array and 3D");
4014 qWarning(
"Texture cannot be both 1D and 3D");
4017 if (is1D && isCube) {
4018 qWarning(
"Texture cannot be both 1D and cube");
4021 if (m_depth > 1 && !is3D) {
4022 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
4025 if (m_arraySize > 0 && !isArray) {
4026 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
4029 if (m_arraySize < 1 && isArray) {
4030 qWarning(
"Texture is an array but array size is %d", m_arraySize);
4035 *adjustedSize = size;
4043 if (!prepareCreate(&size))
4046 MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc] init];
4048 const bool isCube = m_flags.testFlag(CubeMap);
4049 const bool is3D = m_flags.testFlag(ThreeDimensional);
4050 const bool isArray = m_flags.testFlag(TextureArray);
4051 const bool is1D = m_flags.testFlag(OneDimensional);
4053 desc.textureType = MTLTextureTypeCube;
4055 desc.textureType = MTLTextureType3D;
4057 desc.textureType = isArray ? MTLTextureType1DArray : MTLTextureType1D;
4058 }
else if (isArray) {
4059 desc.textureType = samples > 1 ? MTLTextureType2DMultisampleArray : MTLTextureType2DArray;
4061 desc.textureType = samples > 1 ? MTLTextureType2DMultisample : MTLTextureType2D;
4063 desc.pixelFormat =
d->format;
4064 desc.width = NSUInteger(size.width());
4065 desc.height = NSUInteger(size.height());
4066 desc.depth = is3D ? qMax(1, m_depth) : 1;
4069 desc.sampleCount = NSUInteger(
samples);
4071 desc.arrayLength = NSUInteger(qMax(0, m_arraySize));
4072 desc.resourceOptions = MTLResourceStorageModePrivate;
4073 desc.storageMode = MTLStorageModePrivate;
4074 desc.usage = MTLTextureUsageShaderRead;
4075 if (m_flags.testFlag(RenderTarget))
4076 desc.usage |= MTLTextureUsageRenderTarget;
4077 if (m_flags.testFlag(UsedWithLoadStore))
4078 desc.usage |= MTLTextureUsageShaderWrite;
4081 d->tex = [rhiD->d->dev newTextureWithDescriptor: desc];
4084 if (!m_objectName.isEmpty())
4085 d->tex.label = [NSString stringWithUTF8String: m_objectName.constData()];
4091 rhiD->registerResource(
this);
4097 id<MTLTexture> tex = id<MTLTexture>(src.object);
4101 if (!prepareCreate())
4111 rhiD->registerResource(
this);
4117 return {quint64(
d->tex), 0};
4123 if (perLevelViews[level])
4124 return perLevelViews[level];
4126 const MTLTextureType type = [tex textureType];
4127 const bool isCube =
q->m_flags.testFlag(QRhiTexture::CubeMap);
4128 const bool isArray =
q->m_flags.testFlag(QRhiTexture::TextureArray);
4129 id<MTLTexture> view = [tex newTextureViewWithPixelFormat: format textureType: type
4130 levels: NSMakeRange(NSUInteger(level), 1)
4131 slices: NSMakeRange(0, isCube ? 6 : (isArray ? qMax(0, q->m_arraySize) : 1))];
4133 perLevelViews[level] = view;
4138 AddressMode u, AddressMode v, AddressMode w)
4152 if (!
d->samplerState)
4159 e.sampler.samplerState =
d->samplerState;
4160 d->samplerState = nil;
4164 rhiD
->d->releaseQueue.append(e);
4165 rhiD->unregisterResource(
this);
4172 case QRhiSampler::Nearest:
4173 return MTLSamplerMinMagFilterNearest;
4174 case QRhiSampler::Linear:
4175 return MTLSamplerMinMagFilterLinear;
4178 return MTLSamplerMinMagFilterNearest;
4185 case QRhiSampler::None:
4186 return MTLSamplerMipFilterNotMipmapped;
4187 case QRhiSampler::Nearest:
4188 return MTLSamplerMipFilterNearest;
4189 case QRhiSampler::Linear:
4190 return MTLSamplerMipFilterLinear;
4193 return MTLSamplerMipFilterNotMipmapped;
4200 case QRhiSampler::Repeat:
4201 return MTLSamplerAddressModeRepeat;
4202 case QRhiSampler::ClampToEdge:
4203 return MTLSamplerAddressModeClampToEdge;
4204 case QRhiSampler::Mirror:
4205 return MTLSamplerAddressModeMirrorRepeat;
4208 return MTLSamplerAddressModeClampToEdge;
4215 case QRhiSampler::Never:
4216 return MTLCompareFunctionNever;
4217 case QRhiSampler::Less:
4218 return MTLCompareFunctionLess;
4219 case QRhiSampler::Equal:
4220 return MTLCompareFunctionEqual;
4221 case QRhiSampler::LessOrEqual:
4222 return MTLCompareFunctionLessEqual;
4223 case QRhiSampler::Greater:
4224 return MTLCompareFunctionGreater;
4225 case QRhiSampler::NotEqual:
4226 return MTLCompareFunctionNotEqual;
4227 case QRhiSampler::GreaterOrEqual:
4228 return MTLCompareFunctionGreaterEqual;
4229 case QRhiSampler::Always:
4230 return MTLCompareFunctionAlways;
4233 return MTLCompareFunctionNever;
4239 if (
d->samplerState)
4242 MTLSamplerDescriptor *desc = [[MTLSamplerDescriptor alloc] init];
4243 desc.minFilter = toMetalFilter(m_minFilter);
4244 desc.magFilter = toMetalFilter(m_magFilter);
4245 desc.mipFilter = toMetalMipmapMode(m_mipmapMode);
4246 desc.sAddressMode = toMetalAddressMode(m_addressU);
4247 desc.tAddressMode = toMetalAddressMode(m_addressV);
4248 desc.rAddressMode = toMetalAddressMode(m_addressW);
4249 desc.compareFunction = toMetalTextureCompareFunction(m_compareOp);
4252 d->samplerState = [rhiD->d->dev newSamplerStateWithDescriptor: desc];
4257 rhiD->registerResource(
this);
4282 e.shadingRateMap.rateMap =
d->rateMap;
4287 rhiD
->d->releaseQueue.append(e);
4288 rhiD->unregisterResource(
this);
4297 d->rateMap = (id<MTLRasterizationRateMap>) (quintptr(src.object));
4301 [d->rateMap retain];
4306 rhiD->registerResource(
this);
4315 serializedFormatData.reserve(16);
4327 rhiD->unregisterResource(
this);
4361 serializedFormatData.clear();
4362 auto p =
std::back_inserter(serializedFormatData);
4384 rhiD->registerResource(rpD,
false);
4390 return serializedFormatData;
4412 return d->pixelSize;
4426 const QRhiTextureRenderTargetDescription &desc,
4443 rhiD->unregisterResource(
this);
4448 const int colorAttachmentCount =
int(m_desc.colorAttachmentCount());
4451 rpD->hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
4453 for (
int i = 0; i < colorAttachmentCount; ++i) {
4454 const QRhiColorAttachment *colorAtt = m_desc.colorAttachmentAt(i);
4460 if (m_desc.depthTexture())
4461 rpD->dsFormat =
int(
QRHI_RES(QMetalTexture, m_desc.depthTexture())->d->format);
4462 else if (m_desc.depthStencilBuffer())
4463 rpD->dsFormat =
int(
QRHI_RES(QMetalRenderBuffer, m_desc.depthStencilBuffer())->d->format);
4465 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
4470 rhiD->registerResource(rpD,
false);
4477 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
4478 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
4479 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
4483 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
4487 Q_ASSERT(texD || rbD);
4488 id<MTLTexture> dst = nil;
4492 if (attIndex == 0) {
4493 d->pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
4496 is3D = texD->flags().testFlag(QRhiTexture::ThreeDimensional);
4499 if (attIndex == 0) {
4500 d->pixelSize = rbD->pixelSize();
4507 colorAtt
.slice = is3D ? it->layer() : 0;
4508 colorAtt
.level = it->level();
4510 colorAtt.resolveTex = resTexD ? resTexD->d->tex : nil;
4513 d->fb.colorAtt[attIndex] = colorAtt;
4517 if (hasDepthStencil) {
4518 if (m_desc.depthTexture()) {
4520 d->fb.dsTex = depthTexD
->d->tex;
4521 d->fb.hasStencil = rhiD->isStencilSupportingFormat(depthTexD->format());
4522 d->fb.depthNeedsStore = !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture();
4523 d->fb.preserveDs = m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
4525 d->pixelSize = depthTexD->pixelSize();
4530 d->fb.dsTex = depthRbD
->d->tex;
4531 d->fb.hasStencil =
true;
4532 d->fb.depthNeedsStore =
false;
4533 d->fb.preserveDs =
false;
4535 d->pixelSize = depthRbD->pixelSize();
4539 if (m_desc.depthResolveTexture()) {
4541 d->fb.dsResolveTex = depthResolveTexD
->d->tex;
4548 if (d->colorAttCount > 0)
4549 d->fb.preserveColor = m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
4551 QRhiRenderTargetAttachmentTracker::updateResIdList<QMetalTexture, QMetalRenderBuffer>(m_desc, &d->currentResIdList);
4553 rhiD->registerResource(
this,
false);
4559 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QMetalTexture, QMetalRenderBuffer>(m_desc, d->currentResIdList))
4562 return d->pixelSize;
4587 sortedBindings.clear();
4592 rhiD->unregisterResource(
this);
4597 if (!sortedBindings.isEmpty())
4601 if (!rhiD->sanityCheckShaderResourceBindings(
this))
4604 rhiD->updateLayoutDesc(
this);
4606 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
4607 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
4608 if (!sortedBindings.isEmpty())
4609 maxBinding = QRhiImplementation::shaderResourceBindingData(sortedBindings.last())->binding;
4613 boundResourceData.resize(sortedBindings.count());
4615 for (BoundResourceData &bd : boundResourceData)
4616 memset(&bd, 0,
sizeof(BoundResourceData));
4619 rhiD->registerResource(
this,
false);
4625 sortedBindings.clear();
4626 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
4627 if (!flags.testFlag(BindingsAreSorted))
4628 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
4630 for (BoundResourceData &bd : boundResourceData)
4631 memset(&bd, 0,
sizeof(BoundResourceData));
4655 d->tess.compVs[0].destroy();
4656 d->tess.compVs[1].destroy();
4657 d->tess.compVs[2].destroy();
4659 d->tess.compTesc.destroy();
4660 d->tess.vertTese.destroy();
4662 qDeleteAll(
d->extraBufMgr.deviceLocalWorkBuffers);
4663 d->extraBufMgr.deviceLocalWorkBuffers.clear();
4664 qDeleteAll(
d->extraBufMgr.hostVisibleWorkBuffers);
4665 d->extraBufMgr.hostVisibleWorkBuffers.clear();
4670 if (!
d->ps && !
d->ds
4671 && !
d->tess.vertexComputeState[0] && !
d->tess.vertexComputeState[1] && !
d->tess.vertexComputeState[2]
4672 && !
d->tess.tessControlComputeState)
4680 e.graphicsPipeline.pipelineState =
d->ps;
4681 e.graphicsPipeline.depthStencilState =
d->ds;
4682 e.graphicsPipeline.tessVertexComputeState =
d->tess.vertexComputeState;
4683 e.graphicsPipeline.tessTessControlComputeState =
d->tess.tessControlComputeState;
4686 d->tess.vertexComputeState = {};
4687 d->tess.tessControlComputeState = nil;
4691 rhiD
->d->releaseQueue.append(e);
4692 rhiD->unregisterResource(
this);
4699 case QRhiVertexInputAttribute::Float4:
4700 return MTLVertexFormatFloat4;
4701 case QRhiVertexInputAttribute::Float3:
4702 return MTLVertexFormatFloat3;
4703 case QRhiVertexInputAttribute::Float2:
4704 return MTLVertexFormatFloat2;
4705 case QRhiVertexInputAttribute::Float:
4706 return MTLVertexFormatFloat;
4707 case QRhiVertexInputAttribute::UNormByte4:
4708 return MTLVertexFormatUChar4Normalized;
4709 case QRhiVertexInputAttribute::UNormByte2:
4710 return MTLVertexFormatUChar2Normalized;
4711 case QRhiVertexInputAttribute::UNormByte:
4712 return MTLVertexFormatUCharNormalized;
4713 case QRhiVertexInputAttribute::UInt4:
4714 return MTLVertexFormatUInt4;
4715 case QRhiVertexInputAttribute::UInt3:
4716 return MTLVertexFormatUInt3;
4717 case QRhiVertexInputAttribute::UInt2:
4718 return MTLVertexFormatUInt2;
4719 case QRhiVertexInputAttribute::UInt:
4720 return MTLVertexFormatUInt;
4721 case QRhiVertexInputAttribute::SInt4:
4722 return MTLVertexFormatInt4;
4723 case QRhiVertexInputAttribute::SInt3:
4724 return MTLVertexFormatInt3;
4725 case QRhiVertexInputAttribute::SInt2:
4726 return MTLVertexFormatInt2;
4727 case QRhiVertexInputAttribute::SInt:
4728 return MTLVertexFormatInt;
4729 case QRhiVertexInputAttribute::Half4:
4730 return MTLVertexFormatHalf4;
4731 case QRhiVertexInputAttribute::Half3:
4732 return MTLVertexFormatHalf3;
4733 case QRhiVertexInputAttribute::Half2:
4734 return MTLVertexFormatHalf2;
4735 case QRhiVertexInputAttribute::Half:
4736 return MTLVertexFormatHalf;
4737 case QRhiVertexInputAttribute::UShort4:
4738 return MTLVertexFormatUShort4;
4739 case QRhiVertexInputAttribute::UShort3:
4740 return MTLVertexFormatUShort3;
4741 case QRhiVertexInputAttribute::UShort2:
4742 return MTLVertexFormatUShort2;
4743 case QRhiVertexInputAttribute::UShort:
4744 return MTLVertexFormatUShort;
4745 case QRhiVertexInputAttribute::SShort4:
4746 return MTLVertexFormatShort4;
4747 case QRhiVertexInputAttribute::SShort3:
4748 return MTLVertexFormatShort3;
4749 case QRhiVertexInputAttribute::SShort2:
4750 return MTLVertexFormatShort2;
4751 case QRhiVertexInputAttribute::SShort:
4752 return MTLVertexFormatShort;
4755 return MTLVertexFormatFloat4;
4762 case QRhiGraphicsPipeline::Zero:
4763 return MTLBlendFactorZero;
4764 case QRhiGraphicsPipeline::One:
4765 return MTLBlendFactorOne;
4766 case QRhiGraphicsPipeline::SrcColor:
4767 return MTLBlendFactorSourceColor;
4768 case QRhiGraphicsPipeline::OneMinusSrcColor:
4769 return MTLBlendFactorOneMinusSourceColor;
4770 case QRhiGraphicsPipeline::DstColor:
4771 return MTLBlendFactorDestinationColor;
4772 case QRhiGraphicsPipeline::OneMinusDstColor:
4773 return MTLBlendFactorOneMinusDestinationColor;
4774 case QRhiGraphicsPipeline::SrcAlpha:
4775 return MTLBlendFactorSourceAlpha;
4776 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
4777 return MTLBlendFactorOneMinusSourceAlpha;
4778 case QRhiGraphicsPipeline::DstAlpha:
4779 return MTLBlendFactorDestinationAlpha;
4780 case QRhiGraphicsPipeline::OneMinusDstAlpha:
4781 return MTLBlendFactorOneMinusDestinationAlpha;
4782 case QRhiGraphicsPipeline::ConstantColor:
4783 return MTLBlendFactorBlendColor;
4784 case QRhiGraphicsPipeline::ConstantAlpha:
4785 return MTLBlendFactorBlendAlpha;
4786 case QRhiGraphicsPipeline::OneMinusConstantColor:
4787 return MTLBlendFactorOneMinusBlendColor;
4788 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
4789 return MTLBlendFactorOneMinusBlendAlpha;
4790 case QRhiGraphicsPipeline::SrcAlphaSaturate:
4791 return MTLBlendFactorSourceAlphaSaturated;
4792 case QRhiGraphicsPipeline::Src1Color:
4793 return MTLBlendFactorSource1Color;
4794 case QRhiGraphicsPipeline::OneMinusSrc1Color:
4795 return MTLBlendFactorOneMinusSource1Color;
4796 case QRhiGraphicsPipeline::Src1Alpha:
4797 return MTLBlendFactorSource1Alpha;
4798 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
4799 return MTLBlendFactorOneMinusSource1Alpha;
4802 return MTLBlendFactorZero;
4809 case QRhiGraphicsPipeline::Add:
4810 return MTLBlendOperationAdd;
4811 case QRhiGraphicsPipeline::Subtract:
4812 return MTLBlendOperationSubtract;
4813 case QRhiGraphicsPipeline::ReverseSubtract:
4814 return MTLBlendOperationReverseSubtract;
4815 case QRhiGraphicsPipeline::Min:
4816 return MTLBlendOperationMin;
4817 case QRhiGraphicsPipeline::Max:
4818 return MTLBlendOperationMax;
4821 return MTLBlendOperationAdd;
4828 if (c.testFlag(QRhiGraphicsPipeline::R))
4829 f |= MTLColorWriteMaskRed;
4830 if (c.testFlag(QRhiGraphicsPipeline::G))
4831 f |= MTLColorWriteMaskGreen;
4832 if (c.testFlag(QRhiGraphicsPipeline::B))
4833 f |= MTLColorWriteMaskBlue;
4834 if (c.testFlag(QRhiGraphicsPipeline::A))
4835 f |= MTLColorWriteMaskAlpha;
4842 case QRhiGraphicsPipeline::Never:
4843 return MTLCompareFunctionNever;
4844 case QRhiGraphicsPipeline::Less:
4845 return MTLCompareFunctionLess;
4846 case QRhiGraphicsPipeline::Equal:
4847 return MTLCompareFunctionEqual;
4848 case QRhiGraphicsPipeline::LessOrEqual:
4849 return MTLCompareFunctionLessEqual;
4850 case QRhiGraphicsPipeline::Greater:
4851 return MTLCompareFunctionGreater;
4852 case QRhiGraphicsPipeline::NotEqual:
4853 return MTLCompareFunctionNotEqual;
4854 case QRhiGraphicsPipeline::GreaterOrEqual:
4855 return MTLCompareFunctionGreaterEqual;
4856 case QRhiGraphicsPipeline::Always:
4857 return MTLCompareFunctionAlways;
4860 return MTLCompareFunctionAlways;
4867 case QRhiGraphicsPipeline::StencilZero:
4868 return MTLStencilOperationZero;
4869 case QRhiGraphicsPipeline::Keep:
4870 return MTLStencilOperationKeep;
4871 case QRhiGraphicsPipeline::Replace:
4872 return MTLStencilOperationReplace;
4873 case QRhiGraphicsPipeline::IncrementAndClamp:
4874 return MTLStencilOperationIncrementClamp;
4875 case QRhiGraphicsPipeline::DecrementAndClamp:
4876 return MTLStencilOperationDecrementClamp;
4877 case QRhiGraphicsPipeline::Invert:
4878 return MTLStencilOperationInvert;
4879 case QRhiGraphicsPipeline::IncrementAndWrap:
4880 return MTLStencilOperationIncrementWrap;
4881 case QRhiGraphicsPipeline::DecrementAndWrap:
4882 return MTLStencilOperationDecrementWrap;
4885 return MTLStencilOperationKeep;
4892 case QRhiGraphicsPipeline::Triangles:
4893 return MTLPrimitiveTypeTriangle;
4894 case QRhiGraphicsPipeline::TriangleStrip:
4895 return MTLPrimitiveTypeTriangleStrip;
4896 case QRhiGraphicsPipeline::Lines:
4897 return MTLPrimitiveTypeLine;
4898 case QRhiGraphicsPipeline::LineStrip:
4899 return MTLPrimitiveTypeLineStrip;
4900 case QRhiGraphicsPipeline::Points:
4901 return MTLPrimitiveTypePoint;
4904 return MTLPrimitiveTypeTriangle;
4911 case QRhiGraphicsPipeline::Triangles:
4912 case QRhiGraphicsPipeline::TriangleStrip:
4913 case QRhiGraphicsPipeline::TriangleFan:
4914 return MTLPrimitiveTopologyClassTriangle;
4915 case QRhiGraphicsPipeline::Lines:
4916 case QRhiGraphicsPipeline::LineStrip:
4917 return MTLPrimitiveTopologyClassLine;
4918 case QRhiGraphicsPipeline::Points:
4919 return MTLPrimitiveTopologyClassPoint;
4922 return MTLPrimitiveTopologyClassTriangle;
4929 case QRhiGraphicsPipeline::None:
4930 return MTLCullModeNone;
4931 case QRhiGraphicsPipeline::Front:
4932 return MTLCullModeFront;
4933 case QRhiGraphicsPipeline::Back:
4934 return MTLCullModeBack;
4937 return MTLCullModeNone;
4944 case QRhiGraphicsPipeline::Fill:
4945 return MTLTriangleFillModeFill;
4946 case QRhiGraphicsPipeline::Line:
4947 return MTLTriangleFillModeLines;
4950 return MTLTriangleFillModeFill;
4957 case QShaderDescription::CwTessellationWindingOrder:
4958 return MTLWindingClockwise;
4959 case QShaderDescription::CcwTessellationWindingOrder:
4960 return MTLWindingCounterClockwise;
4963 return MTLWindingCounterClockwise;
4970 case QShaderDescription::EqualTessellationPartitioning:
4971 return MTLTessellationPartitionModePow2;
4972 case QShaderDescription::FractionalEvenTessellationPartitioning:
4973 return MTLTessellationPartitionModeFractionalEven;
4974 case QShaderDescription::FractionalOddTessellationPartitioning:
4975 return MTLTessellationPartitionModeFractionalOdd;
4978 return MTLTessellationPartitionModePow2;
4984 int v = version.version();
4985 return MTLLanguageVersion(((v / 10) << 16) + (v % 10));
4989 QString *error, QByteArray *entryPoint, QShaderKey *activeKey)
4991 QVarLengthArray<
int, 8> versions;
4992 versions << 30 << 24 << 23 << 22 << 21 << 20 << 12;
4994 const QList<QShaderKey> shaders = shader.availableShaders();
4998 for (
const int &version : versions) {
4999 key = { QShader::Source::MetalLibShader, version, shaderVariant };
5000 if (shaders.contains(key))
5004 QShaderCode mtllib = shader.shader(key);
5005 if (!mtllib.shader().isEmpty()) {
5006 dispatch_data_t data = dispatch_data_create(mtllib.shader().constData(),
5007 size_t(mtllib.shader().size()),
5008 dispatch_get_global_queue(0, 0),
5009 DISPATCH_DATA_DESTRUCTOR_DEFAULT);
5011 id<MTLLibrary> lib = [dev newLibraryWithData: data error: &err];
5012 dispatch_release(data);
5014 *entryPoint = mtllib.entryPoint();
5018 const QString msg = QString::fromNSString(err.localizedDescription);
5019 qWarning(
"Failed to load metallib from baked shader: %s", qPrintable(msg));
5023 for (
const int &version : versions) {
5024 key = { QShader::Source::MslShader, version, shaderVariant };
5025 if (shaders.contains(key))
5029 QShaderCode mslSource = shader.shader(key);
5030 if (mslSource.shader().isEmpty()) {
5031 qWarning() <<
"No MSL 2.0 or 1.2 code found in baked shader" << shader;
5035 NSString *src = [NSString stringWithUTF8String: mslSource.shader().constData()];
5036 MTLCompileOptions *opts = [[MTLCompileOptions alloc] init];
5037 opts.languageVersion = toMetalLanguageVersion(key.sourceVersion());
5039 id<MTLLibrary> lib = [dev newLibraryWithSource: src options: opts error: &err];
5047 const QString msg = QString::fromNSString(err.localizedDescription);
5052 *entryPoint = mslSource.entryPoint();
5059 return [lib newFunctionWithName:[NSString stringWithUTF8String:entryPoint.constData()]];
5064 MTLRenderPipelineDescriptor *rpDesc =
reinterpret_cast<MTLRenderPipelineDescriptor *>(metalRpDesc);
5068 rpDesc.colorAttachments[0].pixelFormat = MTLPixelFormat(rpD
->colorFormat[0]);
5069 rpDesc.colorAttachments[0].writeMask = MTLColorWriteMaskAll;
5070 rpDesc.colorAttachments[0].blendingEnabled =
false;
5072 Q_ASSERT(m_targetBlends.count() == rpD->colorAttachmentCount
5073 || (m_targetBlends.isEmpty() && rpD->colorAttachmentCount == 1));
5075 for (uint i = 0, ie = uint(m_targetBlends.count()); i != ie; ++i) {
5076 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[
int(i)]);
5077 rpDesc.colorAttachments[i].pixelFormat = MTLPixelFormat(rpD
->colorFormat[i]);
5078 rpDesc.colorAttachments[i].blendingEnabled = b.enable;
5079 rpDesc.colorAttachments[i].sourceRGBBlendFactor = toMetalBlendFactor(b.srcColor);
5080 rpDesc.colorAttachments[i].destinationRGBBlendFactor = toMetalBlendFactor(b.dstColor);
5081 rpDesc.colorAttachments[i].rgbBlendOperation = toMetalBlendOp(b.opColor);
5082 rpDesc.colorAttachments[i].sourceAlphaBlendFactor = toMetalBlendFactor(b.srcAlpha);
5083 rpDesc.colorAttachments[i].destinationAlphaBlendFactor = toMetalBlendFactor(b.dstAlpha);
5084 rpDesc.colorAttachments[i].alphaBlendOperation = toMetalBlendOp(b.opAlpha);
5085 rpDesc.colorAttachments[i].writeMask = toMetalColorWriteMask(b.colorWrite);
5092 MTLPixelFormat fmt = MTLPixelFormat(rpD
->dsFormat);
5093 rpDesc.depthAttachmentPixelFormat = fmt;
5094#if defined(Q_OS_MACOS)
5095 if (fmt != MTLPixelFormatDepth16Unorm && fmt != MTLPixelFormatDepth32Float)
5097 if (fmt != MTLPixelFormatDepth32Float)
5099 rpDesc.stencilAttachmentPixelFormat = fmt;
5103 rpDesc.rasterSampleCount = NSUInteger(rhiD->effectiveSampleCount(m_sampleCount));
5108 MTLDepthStencilDescriptor *dsDesc =
reinterpret_cast<MTLDepthStencilDescriptor *>(metalDsDesc);
5110 dsDesc.depthCompareFunction = m_depthTest ? toMetalCompareOp(m_depthOp) : MTLCompareFunctionAlways;
5111 dsDesc.depthWriteEnabled = m_depthWrite;
5112 if (m_stencilTest) {
5113 dsDesc.frontFaceStencil = [[MTLStencilDescriptor alloc] init];
5114 dsDesc.frontFaceStencil.stencilFailureOperation = toMetalStencilOp(m_stencilFront.failOp);
5115 dsDesc.frontFaceStencil.depthFailureOperation = toMetalStencilOp(m_stencilFront.depthFailOp);
5116 dsDesc.frontFaceStencil.depthStencilPassOperation = toMetalStencilOp(m_stencilFront.passOp);
5117 dsDesc.frontFaceStencil.stencilCompareFunction = toMetalCompareOp(m_stencilFront.compareOp);
5118 dsDesc.frontFaceStencil.readMask = m_stencilReadMask;
5119 dsDesc.frontFaceStencil.writeMask = m_stencilWriteMask;
5121 dsDesc.backFaceStencil = [[MTLStencilDescriptor alloc] init];
5122 dsDesc.backFaceStencil.stencilFailureOperation = toMetalStencilOp(m_stencilBack.failOp);
5123 dsDesc.backFaceStencil.depthFailureOperation = toMetalStencilOp(m_stencilBack.depthFailOp);
5124 dsDesc.backFaceStencil.depthStencilPassOperation = toMetalStencilOp(m_stencilBack.passOp);
5125 dsDesc.backFaceStencil.stencilCompareFunction = toMetalCompareOp(m_stencilBack.compareOp);
5126 dsDesc.backFaceStencil.readMask = m_stencilReadMask;
5127 dsDesc.backFaceStencil.writeMask = m_stencilWriteMask;
5133 d->winding = m_frontFace == CCW ? MTLWindingCounterClockwise : MTLWindingClockwise;
5134 d->cullMode = toMetalCullMode(m_cullMode);
5135 d->triangleFillMode = toMetalTriangleFillMode(m_polygonMode);
5136 d->depthClipMode = m_depthClamp ? MTLDepthClipModeClamp : MTLDepthClipModeClip;
5137 d->depthBias =
float(m_depthBias);
5138 d->slopeScaledDepthBias = m_slopeScaledDepthBias;
5148 for (
auto it = vertexInputLayout.cbeginAttributes(), itEnd = vertexInputLayout.cendAttributes();
5151 const uint loc = uint(it->location());
5152 desc.attributes[loc].format =
decltype(desc.attributes[loc].format)(toMetalAttributeFormat(it->format()));
5153 desc.attributes[loc].offset = NSUInteger(it->offset());
5154 desc.attributes[loc].bufferIndex = NSUInteger(firstVertexBinding + it->binding());
5156 int bindingIndex = 0;
5157 const NSUInteger viewCount = qMax<NSUInteger>(1, q->multiViewCount());
5158 for (
auto it = vertexInputLayout.cbeginBindings(), itEnd = vertexInputLayout.cendBindings();
5159 it != itEnd; ++it, ++bindingIndex)
5161 const uint layoutIdx = uint(firstVertexBinding + bindingIndex);
5162 desc.layouts[layoutIdx].stepFunction =
5163 it->classification() == QRhiVertexInputBinding::PerInstance
5164 ? MTLVertexStepFunctionPerInstance : MTLVertexStepFunctionPerVertex;
5165 desc.layouts[layoutIdx].stepRate = NSUInteger(it->instanceStepRate());
5166 if (desc.layouts[layoutIdx].stepFunction == MTLVertexStepFunctionPerInstance)
5167 desc.layouts[layoutIdx].stepRate *= viewCount;
5168 desc.layouts[layoutIdx].stride = it->stride();
5179 for (
auto it = vertexInputLayout.cbeginAttributes(), itEnd = vertexInputLayout.cendAttributes();
5182 const uint loc = uint(it->location());
5183 desc.attributes[loc].format =
decltype(desc.attributes[loc].format)(toMetalAttributeFormat(it->format()));
5184 desc.attributes[loc].offset = NSUInteger(it->offset());
5185 desc.attributes[loc].bufferIndex = NSUInteger(firstVertexBinding + it->binding());
5187 int bindingIndex = 0;
5188 for (
auto it = vertexInputLayout.cbeginBindings(), itEnd = vertexInputLayout.cendBindings();
5189 it != itEnd; ++it, ++bindingIndex)
5191 const uint layoutIdx = uint(firstVertexBinding + bindingIndex);
5192 if (desc.indexBufferIndex) {
5193 desc.layouts[layoutIdx].stepFunction =
5194 it->classification() == QRhiVertexInputBinding::PerInstance
5195 ? MTLStepFunctionThreadPositionInGridY : MTLStepFunctionThreadPositionInGridXIndexed;
5197 desc.layouts[layoutIdx].stepFunction =
5198 it->classification() == QRhiVertexInputBinding::PerInstance
5199 ? MTLStepFunctionThreadPositionInGridY : MTLStepFunctionThreadPositionInGridX;
5201 desc.layouts[layoutIdx].stepRate = NSUInteger(it->instanceStepRate());
5202 desc.layouts[layoutIdx].stride = it->stride();
5209 NSArray *binArchArray = [NSArray arrayWithObjects: binArch, nil];
5210 rpDesc.binaryArchives = binArchArray;
5218 if (![binArch addRenderPipelineFunctionsWithDescriptor: rpDesc error: &err]) {
5219 const QString msg = QString::fromNSString(err.localizedDescription);
5220 qWarning(
"Failed to collect render pipeline functions to binary archive: %s", qPrintable(msg));
5229 MTLVertexDescriptor *vertexDesc = [MTLVertexDescriptor vertexDescriptor];
5230 d->setupVertexInputDescriptor(vertexDesc);
5232 MTLRenderPipelineDescriptor *rpDesc = [[MTLRenderPipelineDescriptor alloc] init];
5233 rpDesc.vertexDescriptor = vertexDesc;
5241 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
5242 auto cacheIt = rhiD->d->shaderCache.constFind(shaderStage);
5243 if (cacheIt != rhiD->d->shaderCache.constEnd()) {
5244 switch (shaderStage.type()) {
5245 case QRhiShaderStage::Vertex:
5248 [d->vs.func retain];
5249 rpDesc.vertexFunction = d->vs.func;
5251 case QRhiShaderStage::Fragment:
5254 [d->fs.func retain];
5255 rpDesc.fragmentFunction = d->fs.func;
5261 const QShader shader = shaderStage.shader();
5263 QByteArray entryPoint;
5264 QShaderKey activeKey;
5265 id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, shaderStage.shaderVariant(),
5266 &error, &entryPoint, &activeKey);
5268 qWarning(
"MSL shader compilation failed: %s", qPrintable(error));
5271 id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
5273 qWarning(
"MSL function for entry point %s not found", entryPoint.constData());
5277 if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) {
5279 for (QMetalShader &s : rhiD->d->shaderCache)
5281 rhiD->d->shaderCache.clear();
5283 switch (shaderStage.type()) {
5284 case QRhiShaderStage::Vertex:
5287 d->vs.nativeResourceBindingMap = shader.nativeResourceBindingMap(activeKey);
5288 d->vs.desc = shader.description();
5289 d->vs.nativeShaderInfo = shader.nativeShaderInfo(activeKey);
5290 rhiD->d->shaderCache.insert(shaderStage, d->vs);
5292 [d->vs.func retain];
5293 rpDesc.vertexFunction = func;
5295 case QRhiShaderStage::Fragment:
5298 d->fs.nativeResourceBindingMap = shader.nativeResourceBindingMap(activeKey);
5299 d->fs.desc = shader.description();
5300 d->fs.nativeShaderInfo = shader.nativeShaderInfo(activeKey);
5301 rhiD->d->shaderCache.insert(shaderStage, d->fs);
5303 [d->fs.func retain];
5304 rpDesc.fragmentFunction = func;
5317 if (m_multiViewCount >= 2)
5318 rpDesc.inputPrimitiveTopology = toMetalPrimitiveTopologyClass(m_topology);
5320 rhiD
->d->trySeedingRenderPipelineFromBinaryArchive(rpDesc);
5322 if (rhiD->rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5323 rhiD
->d->addRenderPipelineToBinaryArchive(rpDesc);
5326 d->ps = [rhiD->d->dev newRenderPipelineStateWithDescriptor: rpDesc error: &err];
5329 const QString msg = QString::fromNSString(err.localizedDescription);
5330 qWarning(
"Failed to create render pipeline state: %s", qPrintable(msg));
5334 MTLDepthStencilDescriptor *dsDesc = [[MTLDepthStencilDescriptor alloc] init];
5336 d->ds = [rhiD->d->dev newDepthStencilStateWithDescriptor: dsDesc];
5339 d->primitiveType = toMetalPrimitiveType(m_topology);
5347 switch (vertexCompVariant) {
5348 case QShader::NonIndexedVertexAsComputeShader:
5350 case QShader::UInt32IndexedVertexAsComputeShader:
5352 case QShader::UInt16IndexedVertexAsComputeShader:
5362 const int varIndex = vsCompVariantToIndex(vertexCompVariant);
5363 if (varIndex >= 0 && vertexComputeState[varIndex])
5364 return vertexComputeState[varIndex];
5366 id<MTLFunction> func = nil;
5368 func = compVs[varIndex].func;
5371 qWarning(
"No compute function found for vertex shader translated for tessellation, this should not happen");
5375 const QMap<
int,
int> &ebb(compVs[varIndex].nativeShaderInfo.extraBufferBindings);
5376 const int indexBufferBinding = ebb.value(QShaderPrivate::MslTessVertIndicesBufferBinding, -1);
5378 MTLComputePipelineDescriptor *cpDesc = [MTLComputePipelineDescriptor
new];
5379 cpDesc.computeFunction = func;
5380 cpDesc.threadGroupSizeIsMultipleOfThreadExecutionWidth = YES;
5381 cpDesc.stageInputDescriptor = [MTLStageInputOutputDescriptor stageInputOutputDescriptor];
5382 if (indexBufferBinding >= 0) {
5383 if (vertexCompVariant == QShader::UInt32IndexedVertexAsComputeShader) {
5384 cpDesc.stageInputDescriptor.indexType = MTLIndexTypeUInt32;
5385 cpDesc.stageInputDescriptor.indexBufferIndex = indexBufferBinding;
5386 }
else if (vertexCompVariant == QShader::UInt16IndexedVertexAsComputeShader) {
5387 cpDesc.stageInputDescriptor.indexType = MTLIndexTypeUInt16;
5388 cpDesc.stageInputDescriptor.indexBufferIndex = indexBufferBinding;
5391 q->setupStageInputDescriptor(cpDesc.stageInputDescriptor);
5393 rhiD
->d->trySeedingComputePipelineFromBinaryArchive(cpDesc);
5395 if (rhiD->rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5396 rhiD
->d->addComputePipelineToBinaryArchive(cpDesc);
5399 id<MTLComputePipelineState> ps = [rhiD->d->dev newComputePipelineStateWithDescriptor: cpDesc
5400 options: MTLPipelineOptionNone
5405 const QString msg = QString::fromNSString(err.localizedDescription);
5406 qWarning(
"Failed to create compute pipeline state: %s", qPrintable(msg));
5408 vertexComputeState[varIndex] = ps;
5416 if (tessControlComputeState)
5417 return tessControlComputeState;
5419 MTLComputePipelineDescriptor *cpDesc = [MTLComputePipelineDescriptor
new];
5420 cpDesc.computeFunction = compTesc.func;
5422 rhiD
->d->trySeedingComputePipelineFromBinaryArchive(cpDesc);
5424 if (rhiD->rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5425 rhiD
->d->addComputePipelineToBinaryArchive(cpDesc);
5428 id<MTLComputePipelineState> ps = [rhiD->d->dev newComputePipelineStateWithDescriptor: cpDesc
5429 options: MTLPipelineOptionNone
5434 const QString msg = QString::fromNSString(err.localizedDescription);
5435 qWarning(
"Failed to create compute pipeline state: %s", qPrintable(msg));
5437 tessControlComputeState = ps;
5445 return (indices >> index) & 0x1;
5448static inline void takeIndex(quint32 index, quint64 &indices)
5450 indices |= 1 << index;
5459 static const int maxVertexAttributes = 31;
5461 for (
int index = 0; index < maxVertexAttributes; ++index) {
5462 if (!indexTaken(index, indices))
5466 Q_UNREACHABLE_RETURN(-1);
5469static inline int aligned(quint32 offset, quint32 alignment)
5471 return ((offset + alignment - 1) / alignment) * alignment;
5479 for (
const int dim : variable.arrayDims)
5482 if (variable.type == QShaderDescription::VariableType::Struct) {
5483 for (
int element = 0; element < elements; ++element) {
5484 for (
const auto &member : variable.structMembers) {
5485 addUnusedVertexAttribute(member, rhiD, offset, vertexAlignment);
5489 const QRhiVertexInputAttribute::Format format = rhiD->shaderDescVariableFormatToVertexInputFormat(variable.type);
5490 const quint32 size = rhiD->byteSizePerVertexForVertexInputFormat(format);
5493 const quint32 alignment = size;
5494 vertexAlignment =
std::max(vertexAlignment, alignment);
5496 for (
int element = 0; element < elements; ++element) {
5498 offset = aligned(offset, alignment);
5505static void addVertexAttribute(
const T &variable,
int binding,
QRhiMetal *rhiD,
int &index, quint32 &offset, MTLVertexAttributeDescriptorArray *attributes, quint64 &indices, quint32 &vertexAlignment)
5509 for (
const int dim : variable.arrayDims)
5512 if (variable.type == QShaderDescription::VariableType::Struct) {
5513 for (
int element = 0; element < elements; ++element) {
5514 for (
const auto &member : variable.structMembers) {
5515 addVertexAttribute(member, binding, rhiD, index, offset, attributes, indices, vertexAlignment);
5519 const QRhiVertexInputAttribute::Format format = rhiD->shaderDescVariableFormatToVertexInputFormat(variable.type);
5520 const quint32 size = rhiD->byteSizePerVertexForVertexInputFormat(format);
5523 const quint32 alignment = size;
5524 vertexAlignment =
std::max(vertexAlignment, alignment);
5526 for (
int element = 0; element < elements; ++element) {
5527 Q_ASSERT(!indexTaken(index, indices));
5530 offset = aligned(offset, alignment);
5532 attributes[index].bufferIndex = binding;
5533 attributes[index].format = toMetalAttributeFormat(format);
5534 attributes[index].offset = offset;
5536 takeIndex(index, indices);
5538 if (indexTaken(index, indices))
5539 index = nextAttributeIndex(indices);
5546static inline bool matches(
const QList<QShaderDescription::BlockVariable> &a,
const QList<QShaderDescription::BlockVariable> &b)
5548 if (a.size() == b.size()) {
5550 for (
int i = 0; i < a.size() && match; ++i) {
5551 match &= a[i].type == b[i].type
5552 && a[i].arrayDims == b[i].arrayDims
5553 && matches(a[i].structMembers, b[i].structMembers);
5561static inline bool matches(
const QShaderDescription::InOutVariable &a,
const QShaderDescription::InOutVariable &b)
5563 return a.location == b.location
5565 && a.perPatch == b.perPatch
5566 && matches(a.structMembers, b.structMembers);
5615 if (pipeline
->d->ps)
5616 return pipeline
->d->ps;
5618 MTLRenderPipelineDescriptor *rpDesc = [[MTLRenderPipelineDescriptor alloc] init];
5619 MTLVertexDescriptor *vertexDesc = [MTLVertexDescriptor vertexDescriptor];
5622 const QMap<
int,
int> &ebb(compTesc.nativeShaderInfo.extraBufferBindings);
5623 const int tescOutputBufferBinding = ebb.value(QShaderPrivate::MslTessVertTescOutputBufferBinding, -1);
5624 const int tescPatchOutputBufferBinding = ebb.value(QShaderPrivate::MslTessTescPatchOutputBufferBinding, -1);
5625 const int tessFactorBufferBinding = ebb.value(QShaderPrivate::MslTessTescTessLevelBufferBinding, -1);
5626 quint32 offsetInTescOutput = 0;
5627 quint32 offsetInTescPatchOutput = 0;
5628 quint32 offsetInTessFactorBuffer = 0;
5629 quint32 tescOutputAlignment = 0;
5630 quint32 tescPatchOutputAlignment = 0;
5631 quint32 tessFactorAlignment = 0;
5632 QSet<
int> usedBuffers;
5635 QMap<
int, QShaderDescription::InOutVariable> tescOutVars;
5636 for (
const auto &tescOutVar : compTesc.desc.outputVariables())
5637 tescOutVars[tescOutVar.location] = tescOutVar;
5640 QMap<
int, QShaderDescription::InOutVariable> teseInVars;
5641 for (
const auto &teseInVar : vertTese.desc.inputVariables())
5642 teseInVars[teseInVar.location] = teseInVar;
5645 quint64 indices = 0;
5647 for (QShaderDescription::InOutVariable &tescOutVar : tescOutVars) {
5649 int index = tescOutVar.location;
5651 quint32 *offset =
nullptr;
5652 quint32 *alignment =
nullptr;
5654 if (tescOutVar.perPatch) {
5655 binding = tescPatchOutputBufferBinding;
5656 offset = &offsetInTescPatchOutput;
5657 alignment = &tescPatchOutputAlignment;
5659 tescOutVar.arrayDims.removeLast();
5660 binding = tescOutputBufferBinding;
5661 offset = &offsetInTescOutput;
5662 alignment = &tescOutputAlignment;
5665 if (teseInVars.contains(index)) {
5667 if (!matches(teseInVars[index], tescOutVar)) {
5668 qWarning() <<
"mismatched tessellation control output -> tesssellation evaluation input at location" << index;
5669 qWarning() <<
" tesc out:" << tescOutVar;
5670 qWarning() <<
" tese in:" << teseInVars[index];
5673 if (binding != -1) {
5674 addVertexAttribute(tescOutVar, binding, rhiD, index, *offset, vertexDesc.attributes, indices, *alignment);
5675 usedBuffers << binding;
5677 qWarning() <<
"baked tessellation control shader missing output buffer binding information";
5678 addUnusedVertexAttribute(tescOutVar, rhiD, *offset, *alignment);
5682 qWarning() <<
"missing tessellation evaluation input for tessellation control output:" << tescOutVar;
5683 addUnusedVertexAttribute(tescOutVar, rhiD, *offset, *alignment);
5686 teseInVars.remove(tescOutVar.location);
5689 for (
const QShaderDescription::InOutVariable &teseInVar : teseInVars)
5690 qWarning() <<
"missing tessellation control output for tessellation evaluation input:" << teseInVar;
5693 QMap<QShaderDescription::BuiltinType, QShaderDescription::BuiltinVariable> tescOutBuiltins;
5694 for (
const auto &tescOutBuiltin : compTesc.desc.outputBuiltinVariables())
5695 tescOutBuiltins[tescOutBuiltin.type] = tescOutBuiltin;
5698 QMap<QShaderDescription::BuiltinType, QShaderDescription::BuiltinVariable> teseInBuiltins;
5699 for (
const auto &teseInBuiltin : vertTese.desc.inputBuiltinVariables())
5700 teseInBuiltins[teseInBuiltin.type] = teseInBuiltin;
5702 const bool trianglesMode = vertTese.desc.tessellationMode() == QShaderDescription::TrianglesTessellationMode;
5703 bool tessLevelAdded =
false;
5705 for (
const QShaderDescription::BuiltinVariable &builtin : tescOutBuiltins) {
5707 QShaderDescription::InOutVariable variable;
5709 quint32 *offset =
nullptr;
5710 quint32 *alignment =
nullptr;
5712 switch (builtin.type) {
5713 case QShaderDescription::BuiltinType::PositionBuiltin:
5714 variable.type = QShaderDescription::VariableType::Vec4;
5715 binding = tescOutputBufferBinding;
5716 offset = &offsetInTescOutput;
5717 alignment = &tescOutputAlignment;
5719 case QShaderDescription::BuiltinType::PointSizeBuiltin:
5720 variable.type = QShaderDescription::VariableType::Float;
5721 binding = tescOutputBufferBinding;
5722 offset = &offsetInTescOutput;
5723 alignment = &tescOutputAlignment;
5725 case QShaderDescription::BuiltinType::ClipDistanceBuiltin:
5726 variable.type = QShaderDescription::VariableType::Float;
5727 variable.arrayDims = builtin.arrayDims;
5728 binding = tescOutputBufferBinding;
5729 offset = &offsetInTescOutput;
5730 alignment = &tescOutputAlignment;
5732 case QShaderDescription::BuiltinType::TessLevelOuterBuiltin:
5733 variable.type = QShaderDescription::VariableType::Half4;
5734 binding = tessFactorBufferBinding;
5735 offset = &offsetInTessFactorBuffer;
5736 tessLevelAdded = trianglesMode;
5737 alignment = &tessFactorAlignment;
5739 case QShaderDescription::BuiltinType::TessLevelInnerBuiltin:
5740 if (trianglesMode) {
5741 if (!tessLevelAdded) {
5742 variable.type = QShaderDescription::VariableType::Half4;
5743 binding = tessFactorBufferBinding;
5744 offsetInTessFactorBuffer = 0;
5745 offset = &offsetInTessFactorBuffer;
5746 alignment = &tessFactorAlignment;
5747 tessLevelAdded =
true;
5749 teseInBuiltins.remove(builtin.type);
5753 variable.type = QShaderDescription::VariableType::Half2;
5754 binding = tessFactorBufferBinding;
5755 offsetInTessFactorBuffer = 8;
5756 offset = &offsetInTessFactorBuffer;
5757 alignment = &tessFactorAlignment;
5765 if (teseInBuiltins.contains(builtin.type)) {
5766 if (binding != -1) {
5767 int index = nextAttributeIndex(indices);
5768 addVertexAttribute(variable, binding, rhiD, index, *offset, vertexDesc.attributes, indices, *alignment);
5769 usedBuffers << binding;
5771 qWarning() <<
"baked tessellation control shader missing output buffer binding information";
5772 addUnusedVertexAttribute(variable, rhiD, *offset, *alignment);
5775 addUnusedVertexAttribute(variable, rhiD, *offset, *alignment);
5778 teseInBuiltins.remove(builtin.type);
5781 for (
const QShaderDescription::BuiltinVariable &builtin : teseInBuiltins) {
5782 switch (builtin.type) {
5783 case QShaderDescription::BuiltinType::PositionBuiltin:
5784 case QShaderDescription::BuiltinType::PointSizeBuiltin:
5785 case QShaderDescription::BuiltinType::ClipDistanceBuiltin:
5786 qWarning() <<
"missing tessellation control output for tessellation evaluation builtin input:" << builtin;
5793 if (usedBuffers.contains(tescOutputBufferBinding)) {
5794 vertexDesc.layouts[tescOutputBufferBinding].stepFunction = MTLVertexStepFunctionPerPatchControlPoint;
5795 vertexDesc.layouts[tescOutputBufferBinding].stride = aligned(offsetInTescOutput, tescOutputAlignment);
5798 if (usedBuffers.contains(tescPatchOutputBufferBinding)) {
5799 vertexDesc.layouts[tescPatchOutputBufferBinding].stepFunction = MTLVertexStepFunctionPerPatch;
5800 vertexDesc.layouts[tescPatchOutputBufferBinding].stride = aligned(offsetInTescPatchOutput, tescPatchOutputAlignment);
5803 if (usedBuffers.contains(tessFactorBufferBinding)) {
5804 vertexDesc.layouts[tessFactorBufferBinding].stepFunction = MTLVertexStepFunctionPerPatch;
5805 vertexDesc.layouts[tessFactorBufferBinding].stride = trianglesMode ?
sizeof(MTLTriangleTessellationFactorsHalf) :
sizeof(MTLQuadTessellationFactorsHalf);
5808 rpDesc.vertexDescriptor = vertexDesc;
5809 rpDesc.vertexFunction = vertTese.func;
5810 rpDesc.fragmentFunction = pipeline
->d->fs.func;
5816 rpDesc.tessellationOutputWindingOrder = toMetalTessellationWindingOrder(vertTese.desc.tessellationWindingOrder());
5818 rpDesc.tessellationPartitionMode = toMetalTessellationPartitionMode(vertTese.desc.tessellationPartitioning());
5823 rhiD
->d->trySeedingRenderPipelineFromBinaryArchive(rpDesc);
5825 if (rhiD->rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5826 rhiD
->d->addRenderPipelineToBinaryArchive(rpDesc);
5829 id<MTLRenderPipelineState> ps = [rhiD->d->dev newRenderPipelineStateWithDescriptor: rpDesc error: &err];
5832 const QString msg = QString::fromNSString(err.localizedDescription);
5833 qWarning(
"Failed to create render pipeline state for tessellation: %s", qPrintable(msg));
5837 pipeline->d->ps = ps;
5844 QVector<QMetalBuffer *> *workBuffers = type == WorkBufType::DeviceLocal ? &deviceLocalWorkBuffers : &hostVisibleWorkBuffers;
5847 for (QMetalBuffer *workBuf : *workBuffers) {
5848 if (workBuf && workBuf->lastActiveFrameSlot == -1 && workBuf->size() >= size) {
5849 workBuf->lastActiveFrameSlot = rhiD->currentFrameSlot;
5857 for (QMetalBuffer *workBuf : *workBuffers) {
5858 if (workBuf && workBuf->lastActiveFrameSlot == -1) {
5859 workBuf->setSize(size);
5860 if (workBuf->create()) {
5861 workBuf->lastActiveFrameSlot = rhiD->currentFrameSlot;
5872 buf =
new QMetalBuffer(rhiD, QRhiBuffer::Static, QRhiBuffer::UsageFlags(QMetalBuffer::WorkBufPoolUsage), size);
5875 buf =
new QMetalBuffer(rhiD, QRhiBuffer::Dynamic, QRhiBuffer::UsageFlags(QMetalBuffer::WorkBufPoolUsage), size);
5879 workBuffers->append(buf);
5883 qWarning(
"Failed to acquire work buffer of size %u", size);
5891 QByteArray entryPoint;
5892 QShaderKey activeKey;
5894 const QShaderDescription tescDesc = tesc.description();
5895 const QShaderDescription teseDesc = tese.description();
5896 d->tess.inControlPointCount = uint(m_patchControlPointCount);
5897 d->tess.outControlPointCount = tescDesc.tessellationOutputVertexCount();
5898 if (!
d->tess.outControlPointCount)
5899 d->tess.outControlPointCount = teseDesc.tessellationOutputVertexCount();
5901 if (!
d->tess.outControlPointCount) {
5902 qWarning(
"Failed to determine output vertex count from the tessellation control or evaluation shader, cannot tessellate");
5903 d->tess.enabled =
false;
5904 d->tess.failed =
true;
5908 if (m_multiViewCount >= 2)
5909 qWarning(
"Multiview is not supported with tessellation");
5917 bool variantsPresent[3] = {};
5918 const QVector<QShaderKey> tessVertKeys = tessVert.availableShaders();
5919 for (
const QShaderKey &k : tessVertKeys) {
5920 switch (k.sourceVariant()) {
5921 case QShader::NonIndexedVertexAsComputeShader:
5922 variantsPresent[0] =
true;
5924 case QShader::UInt32IndexedVertexAsComputeShader:
5925 variantsPresent[1] =
true;
5927 case QShader::UInt16IndexedVertexAsComputeShader:
5928 variantsPresent[2] =
true;
5934 if (!(variantsPresent[0] && variantsPresent[1] && variantsPresent[2])) {
5935 qWarning(
"Vertex shader is not prepared for Metal tessellation. Cannot tessellate. "
5936 "Perhaps the relevant variants (UInt32IndexedVertexAsComputeShader et al) were not generated? "
5937 "Try passing --msltess to qsb.");
5938 d->tess.enabled =
false;
5939 d->tess.failed =
true;
5944 for (QShader::Variant variant : {
5945 QShader::NonIndexedVertexAsComputeShader,
5946 QShader::UInt32IndexedVertexAsComputeShader,
5947 QShader::UInt16IndexedVertexAsComputeShader })
5949 id<MTLLibrary> lib = rhiD->d->createMetalLib(tessVert, variant, &error, &entryPoint, &activeKey);
5951 qWarning(
"MSL shader compilation failed for vertex-as-compute shader %d: %s",
int(variant), qPrintable(error));
5952 d->tess.enabled =
false;
5953 d->tess.failed =
true;
5956 id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
5958 qWarning(
"MSL function for entry point %s not found", entryPoint.constData());
5960 d->tess.enabled =
false;
5961 d->tess.failed =
true;
5964 QMetalShader &compVs(d->tess.compVs[varIndex]);
5967 compVs.desc = tessVert.description();
5968 compVs.nativeResourceBindingMap = tessVert.nativeResourceBindingMap(activeKey);
5969 compVs.nativeShaderInfo = tessVert.nativeShaderInfo(activeKey);
5972 if (!d->tess.vsCompPipeline(rhiD, variant)) {
5973 qWarning(
"Failed to pre-generate compute pipeline for vertex compute shader (tessellation variant %d)",
int(variant));
5974 d->tess.enabled =
false;
5975 d->tess.failed =
true;
5983 id<MTLLibrary> tessControlLib = rhiD
->d->createMetalLib(tesc, QShader::StandardShader, &error, &entryPoint, &activeKey);
5984 if (!tessControlLib) {
5985 qWarning(
"MSL shader compilation failed for tessellation control compute shader: %s", qPrintable(error));
5986 d->tess.enabled =
false;
5987 d->tess.failed =
true;
5990 id<MTLFunction> tessControlFunc = rhiD
->d->createMSLShaderFunction(tessControlLib, entryPoint);
5991 if (!tessControlFunc) {
5992 qWarning(
"MSL function for entry point %s not found", entryPoint.constData());
5993 [tessControlLib release];
5994 d->tess.enabled =
false;
5995 d->tess.failed =
true;
5998 d->tess.compTesc.lib = tessControlLib;
5999 d->tess.compTesc.func = tessControlFunc;
6000 d->tess.compTesc.desc = tesc.description();
6001 d->tess.compTesc.nativeResourceBindingMap = tesc.nativeResourceBindingMap(activeKey);
6002 d->tess.compTesc.nativeShaderInfo = tesc.nativeShaderInfo(activeKey);
6003 if (!
d->tess.tescCompPipeline(rhiD)) {
6004 qWarning(
"Failed to pre-generate compute pipeline for tessellation control shader");
6005 d->tess.enabled =
false;
6006 d->tess.failed =
true;
6011 id<MTLLibrary> tessEvalLib = rhiD
->d->createMetalLib(tese, QShader::StandardShader, &error, &entryPoint, &activeKey);
6013 qWarning(
"MSL shader compilation failed for tessellation evaluation vertex shader: %s", qPrintable(error));
6014 d->tess.enabled =
false;
6015 d->tess.failed =
true;
6018 id<MTLFunction> tessEvalFunc = rhiD
->d->createMSLShaderFunction(tessEvalLib, entryPoint);
6019 if (!tessEvalFunc) {
6020 qWarning(
"MSL function for entry point %s not found", entryPoint.constData());
6021 [tessEvalLib release];
6022 d->tess.enabled =
false;
6023 d->tess.failed =
true;
6026 d->tess.vertTese.lib = tessEvalLib;
6027 d->tess.vertTese.func = tessEvalFunc;
6028 d->tess.vertTese.desc = tese.description();
6029 d->tess.vertTese.nativeResourceBindingMap = tese.nativeResourceBindingMap(activeKey);
6030 d->tess.vertTese.nativeShaderInfo = tese.nativeShaderInfo(activeKey);
6032 id<MTLLibrary> fragLib = rhiD
->d->createMetalLib(tessFrag, QShader::StandardShader, &error, &entryPoint, &activeKey);
6034 qWarning(
"MSL shader compilation failed for fragment shader: %s", qPrintable(error));
6035 d->tess.enabled =
false;
6036 d->tess.failed =
true;
6039 id<MTLFunction> fragFunc = rhiD
->d->createMSLShaderFunction(fragLib, entryPoint);
6041 qWarning(
"MSL function for entry point %s not found", entryPoint.constData());
6043 d->tess.enabled =
false;
6044 d->tess.failed =
true;
6047 d->fs.lib = fragLib;
6048 d->fs.func = fragFunc;
6049 d->fs.desc = tessFrag.description();
6050 d->fs.nativeShaderInfo = tessFrag.nativeShaderInfo(activeKey);
6051 d->fs.nativeResourceBindingMap = tessFrag.nativeResourceBindingMap(activeKey);
6053 if (!
d->tess.teseFragRenderPipeline(rhiD,
this)) {
6054 qWarning(
"Failed to pre-generate render pipeline for tessellation evaluation + fragment shader");
6055 d->tess.enabled =
false;
6056 d->tess.failed =
true;
6060 MTLDepthStencilDescriptor *dsDesc = [[MTLDepthStencilDescriptor alloc] init];
6062 d->ds = [rhiD->d->dev newDepthStencilStateWithDescriptor: dsDesc];
6076 rhiD->pipelineCreationStart();
6077 if (!rhiD->sanityCheckGraphicsPipeline(
this))
6085 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6086 switch (shaderStage.type()) {
6087 case QRhiShaderStage::Vertex:
6088 tessVert = shaderStage.shader();
6090 case QRhiShaderStage::TessellationControl:
6091 tesc = shaderStage.shader();
6093 case QRhiShaderStage::TessellationEvaluation:
6094 tese = shaderStage.shader();
6096 case QRhiShaderStage::Fragment:
6097 tessFrag = shaderStage.shader();
6103 d->tess.enabled = tesc.isValid() && tese.isValid() && m_topology == Patches && m_patchControlPointCount > 0;
6104 d->tess.failed =
false;
6106 bool ok = d->tess.enabled ? createTessellationPipelines(tessVert, tesc, tese, tessFrag) : createVertexFragmentPipeline();
6112 QVarLengthArray<QMetalShader *, 6> shaders;
6113 if (
d->tess.enabled) {
6114 shaders.append(&
d->tess.compVs[0]);
6115 shaders.append(&
d->tess.compVs[1]);
6116 shaders.append(&
d->tess.compVs[2]);
6117 shaders.append(&
d->tess.compTesc);
6118 shaders.append(&
d->tess.vertTese);
6120 shaders.append(&
d->vs);
6122 shaders.append(&
d->fs);
6124 for (QMetalShader *shader : shaders) {
6125 if (shader->nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding)) {
6126 const int binding = shader->nativeShaderInfo.extraBufferBindings[QShaderPrivate::MslBufferSizeBufferBinding];
6127 shader->nativeResourceBindingMap[binding] = {binding, -1};
6128 int maxNativeBinding = 0;
6129 for (
const QShaderDescription::StorageBlock &block : shader->desc.storageBlocks())
6130 maxNativeBinding = qMax(maxNativeBinding, shader->nativeResourceBindingMap[block.binding].first);
6134 buffers += ((maxNativeBinding + 1 + 7) / 8) * 8;
6139 if (!d->bufferSizeBuffer)
6140 d->bufferSizeBuffer =
new QMetalBuffer(rhiD, QRhiBuffer::Static, QRhiBuffer::StorageBuffer, buffers *
sizeof(
int));
6146 rhiD->pipelineCreationEnd();
6149 rhiD->registerResource(
this);
6178 e.computePipeline.pipelineState =
d->ps;
6183 rhiD
->d->releaseQueue.append(e);
6184 rhiD->unregisterResource(
this);
6191 NSArray *binArchArray = [NSArray arrayWithObjects: binArch, nil];
6192 cpDesc.binaryArchives = binArchArray;
6200 if (![binArch addComputePipelineFunctionsWithDescriptor: cpDesc error: &err]) {
6201 const QString msg = QString::fromNSString(err.localizedDescription);
6202 qWarning(
"Failed to collect compute pipeline functions to binary archive: %s", qPrintable(msg));
6213 rhiD->pipelineCreationStart();
6215 auto cacheIt = rhiD
->d->shaderCache.constFind(m_shaderStage);
6216 if (cacheIt != rhiD
->d->shaderCache.constEnd()) {
6219 const QShader shader = m_shaderStage.shader();
6221 QByteArray entryPoint;
6222 QShaderKey activeKey;
6223 id<MTLLibrary> lib = rhiD
->d->createMetalLib(shader, m_shaderStage.shaderVariant(),
6224 &error, &entryPoint, &activeKey);
6226 qWarning(
"MSL shader compilation failed: %s", qPrintable(error));
6229 id<MTLFunction> func = rhiD
->d->createMSLShaderFunction(lib, entryPoint);
6231 qWarning(
"MSL function for entry point %s not found", entryPoint.constData());
6237 d->cs.localSize = shader.description().computeShaderLocalSize();
6238 d->cs.nativeResourceBindingMap = shader.nativeResourceBindingMap(activeKey);
6239 d->cs.desc = shader.description();
6240 d->cs.nativeShaderInfo = shader.nativeShaderInfo(activeKey);
6243 if (
d->cs.nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding)) {
6244 const int binding = d->cs.nativeShaderInfo.extraBufferBindings[QShaderPrivate::MslBufferSizeBufferBinding];
6245 d->cs.nativeResourceBindingMap[binding] = {binding, -1};
6248 if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) {
6249 for (QMetalShader &s : rhiD->d->shaderCache)
6251 rhiD
->d->shaderCache.clear();
6253 rhiD
->d->shaderCache.insert(m_shaderStage,
d->cs);
6257 [d->cs.func retain];
6259 d->localSize = MTLSizeMake(
d->cs.localSize[0],
d->cs.localSize[1],
d->cs.localSize[2]);
6261 MTLComputePipelineDescriptor *cpDesc = [MTLComputePipelineDescriptor
new];
6262 cpDesc.computeFunction =
d->cs.func;
6264 rhiD
->d->trySeedingComputePipelineFromBinaryArchive(cpDesc);
6266 if (rhiD->rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
6267 rhiD
->d->addComputePipelineToBinaryArchive(cpDesc);
6270 d->ps = [rhiD->d->dev newComputePipelineStateWithDescriptor: cpDesc
6271 options: MTLPipelineOptionNone
6276 const QString msg = QString::fromNSString(err.localizedDescription);
6277 qWarning(
"Failed to create compute pipeline state: %s", qPrintable(msg));
6282 if (
d->cs.nativeShaderInfo.extraBufferBindings.contains(QShaderPrivate::MslBufferSizeBufferBinding)) {
6284 for (
const QShaderDescription::StorageBlock &block : d->cs.desc.storageBlocks())
6285 buffers = qMax(buffers, d->cs.nativeResourceBindingMap[block.binding].first);
6289 if (!d->bufferSizeBuffer)
6290 d->bufferSizeBuffer =
new QMetalBuffer(rhiD, QRhiBuffer::Static, QRhiBuffer::StorageBuffer, buffers *
sizeof(
int));
6296 rhiD->pipelineCreationEnd();
6299 rhiD->registerResource(
this);
6323 nativeHandlesStruct.commandBuffer = (MTLCommandBuffer *) d->cb;
6324 nativeHandlesStruct.encoder = (MTLRenderCommandEncoder *) d->currentRenderPassEncoder;
6325 return &nativeHandlesStruct;
6331 d->currentRenderPassEncoder = nil;
6332 d->currentComputePassEncoder = nil;
6333 d->tessellationComputeEncoder = nil;
6334 d->currentPassRpDesc = nil;
6341 currentTarget =
nullptr;
6349 currentPipelineGeneration = 0;
6352 currentSrbGeneration = 0;
6355 currentIndexOffset = 0;
6356 currentIndexFormat = QRhiCommandBuffer::IndexUInt16;
6361 currentDepthBiasValues = { 0.0f, 0.0f };
6363 currentViewport = {};
6365 d->currentShaderResourceBindingState = {};
6366 d->currentDepthStencilState = nil;
6368 d->currentVertexInputsBuffers.clear();
6369 d->currentVertexInputOffsets.clear();
6379 d->sem[i] =
nullptr;
6380 d->msaaTex[i] = nil;
6400 dispatch_release(
d->sem[i]);
6401 d->sem[i] =
nullptr;
6406 [d->msaaTex[i] release];
6407 d->msaaTex[i] = nil;
6413 [d->curDrawable release];
6414 d->curDrawable = nil;
6418 rhiD->swapchains.remove(
this);
6419 rhiD->unregisterResource(
this);
6439 CALayer *layer =
nullptr;
6441 if (
auto *cocoaWindow = window->nativeInterface<QNativeInterface::Private::QCocoaWindow>())
6442 layer = cocoaWindow->contentLayer();
6444 layer =
reinterpret_cast<UIView *>(window->winId()).layer;
6447 return static_cast<CAMetalLayer *>(layer);
6456 d.reserved[0] = layerForWindow(window);
6463 CAMetalLayer *layer =
d->layer;
6465 layer = qrhi_objectFromProxyData<CAMetalLayer>(&m_proxyData, m_window, QRhi::Metal, 0);
6468 int height = (
int)layer.bounds.size.height;
6469 int width = (
int)layer.bounds.size.width;
6470 width *= layer.contentsScale;
6471 height *= layer.contentsScale;
6472 return QSize(width, height);
6477 if (f == HDRExtendedSrgbLinear) {
6479 }
else if (f == HDR10) {
6481 }
else if (f == HDRExtendedDisplayP3Linear) {
6495 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
6501 rpD->dsFormat = rhiD->d->dev.depth24Stencil8PixelFormatSupported
6502 ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8;
6504 rpD->dsFormat = MTLPixelFormatDepth32Float_Stencil8;
6507 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
6511 rhiD->registerResource(rpD,
false);
6518 samples = rhiD->effectiveSampleCount(m_sampleCount);
6520 if (m_format == HDRExtendedSrgbLinear || m_format == HDRExtendedDisplayP3Linear) {
6521 d->colorFormat = MTLPixelFormatRGBA16Float;
6522 d->rhiColorFormat = QRhiTexture::RGBA16F;
6525 if (m_format == HDR10) {
6526 d->colorFormat = MTLPixelFormatRGB10A2Unorm;
6527 d->rhiColorFormat = QRhiTexture::RGB10A2;
6530 d->colorFormat = m_flags.testFlag(sRGB) ? MTLPixelFormatBGRA8Unorm_sRGB : MTLPixelFormatBGRA8Unorm;
6531 d->rhiColorFormat = QRhiTexture::BGRA8;
6540 dispatch_semaphore_t sem =
d->sem[slot];
6541 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
6542 dispatch_semaphore_signal(sem);
6549 const bool needsRegistration = !window || window != m_window;
6551 if (window && window != m_window)
6556 if (needsRegistration || !rhiD->swapchains.contains(
this))
6557 rhiD->swapchains.insert(
this);
6561 if (window->surfaceType() != QSurface::MetalSurface) {
6562 qWarning(
"QMetalSwapChain only supports MetalSurface windows");
6566 d->layer = qrhi_objectFromProxyData<CAMetalLayer>(&m_proxyData, window, QRhi::Metal, 0);
6570 if (
d->colorFormat !=
d->layer.pixelFormat)
6571 d->layer.pixelFormat =
d->colorFormat;
6573 if (m_format == HDRExtendedSrgbLinear) {
6574 d->layer.colorspace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedLinearSRGB);
6575 d->layer.wantsExtendedDynamicRangeContent = YES;
6576 }
else if (m_format == HDR10) {
6577 d->layer.colorspace = CGColorSpaceCreateWithName(kCGColorSpaceITUR_2100_PQ);
6578 d->layer.wantsExtendedDynamicRangeContent = YES;
6579 }
else if (m_format == HDRExtendedDisplayP3Linear) {
6580 d->layer.colorspace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedLinearDisplayP3);
6581 d->layer.wantsExtendedDynamicRangeContent = YES;
6584 if (m_flags.testFlag(UsedAsTransferSource))
6585 d->layer.framebufferOnly = NO;
6588 if (m_flags.testFlag(NoVSync))
6589 d->layer.displaySyncEnabled = NO;
6592 if (m_flags.testFlag(SurfaceHasPreMulAlpha)) {
6593 d->layer.opaque = NO;
6594 }
else if (m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
6599 d->layer.opaque = NO;
6601 d->layer.opaque = YES;
6607 int width = (
int)
d->layer.bounds.size.width;
6608 int height = (
int)
d->layer.bounds.size.height;
6609 CGSize layerSize = CGSizeMake(width, height);
6610 const float scaleFactor =
d->layer.contentsScale;
6611 layerSize.width *= scaleFactor;
6612 layerSize.height *= scaleFactor;
6613 d->layer.drawableSize = layerSize;
6615 m_currentPixelSize = QSizeF::fromCGSize(layerSize).toSize();
6616 pixelSize = m_currentPixelSize;
6618 [d->layer setDevice: rhiD->d->dev];
6620 [d->curDrawable release];
6621 d->curDrawable = nil;
6632 ds = m_depthStencil ?
QRHI_RES(QMetalRenderBuffer, m_depthStencil) :
nullptr;
6633 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
6634 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
6635 m_depthStencil->sampleCount(), m_sampleCount);
6637 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
6638 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
6639 m_depthStencil->setPixelSize(pixelSize);
6640 if (!m_depthStencil->create())
6641 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
6642 pixelSize.width(), pixelSize.height());
6644 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the layer size (%dx%d). Expect problems.",
6645 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
6646 pixelSize.width(), pixelSize.height());
6650 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
6651 rtWrapper.d->pixelSize = pixelSize;
6657 qCDebug(QRHI_LOG_INFO,
"got CAMetalLayer, pixel size %dx%d (scale %.2f)",
6658 pixelSize.width(), pixelSize.height(), scaleFactor);
6661 MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc] init];
6662 desc.textureType = MTLTextureType2DMultisample;
6663 desc.pixelFormat =
d->colorFormat;
6664 desc.width = NSUInteger(pixelSize.width());
6665 desc.height = NSUInteger(pixelSize.height());
6666 desc.sampleCount = NSUInteger(
samples);
6667 desc.resourceOptions = MTLResourceStorageModePrivate;
6668 desc.storageMode = MTLStorageModePrivate;
6669 desc.usage = MTLTextureUsageRenderTarget;
6671 if (
d->msaaTex[i]) {
6675 e.renderbuffer.texture =
d->msaaTex[i];
6676 rhiD
->d->releaseQueue.append(e);
6678 d->msaaTex[i] = [rhiD->d->dev newTextureWithDescriptor: desc];
6683 rhiD->registerResource(
this);
6699#if defined(Q_OS_MACOS)
6700 NSView *view =
reinterpret_cast<NSView *>(m_window->winId());
6701 NSScreen *screen = view.window.screen;
6702 info.limits.colorComponentValue.maxColorComponentValue = screen.maximumExtendedDynamicRangeColorComponentValue;
6703 info.limits.colorComponentValue.maxPotentialColorComponentValue = screen.maximumPotentialExtendedDynamicRangeColorComponentValue;
6704#elif defined(Q_OS_IOS)
6705 UIView *view =
reinterpret_cast<UIView *>(m_window->winId());
6706 UIScreen *screen = view.window.windowScene.screen;
6707 info.limits.colorComponentValue.maxColorComponentValue =
6708 view.window.windowScene.screen.currentEDRHeadroom;
6709 info.limits.colorComponentValue.maxPotentialColorComponentValue =
6710 screen.potentialEDRHeadroom;
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
Int aligned(Int v, Int byteAlign)
\variable QRhiVulkanQueueSubmitParams::waitSemaphoreCount
id< MTLTexture > viewForLevel(int level)
id< MTLTexture > perLevelViews[QRhi::MAX_MIP_LEVELS]
id< MTLBuffer > stagingBuf[QMTL_FRAMES_IN_FLIGHT]
QMetalTextureData(QMetalTexture *t)
~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.
id< MTLComputePipelineState > pipelineState
id< MTLDepthStencilState > depthStencilState
std::array< id< MTLComputePipelineState >, 3 > tessVertexComputeState
id< MTLRasterizationRateMap > rateMap
id< MTLSamplerState > samplerState
id< MTLBuffer > stagingBuffers[QMTL_FRAMES_IN_FLIGHT]
id< MTLComputePipelineState > tessTessControlComputeState
id< MTLRenderPipelineState > pipelineState
id< MTLBuffer > buffers[QMTL_FRAMES_IN_FLIGHT]
id< MTLTexture > views[QRhi::MAX_MIP_LEVELS]
QRhiReadbackDescription desc
QRhiReadbackResult * result
QRhiTexture::Format format
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
float maxPotentialColorComponentValue
LuminanceBehavior luminanceBehavior
float maxColorComponentValue
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h