Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: In-shader vertex loading support #2029

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions ExternalDependencies.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@
/* End PBXAggregateTarget section */

/* Begin PBXBuildFile section */
164DCE072AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 164DCE062AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp */; };
164DCE082AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 164DCE062AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp */; };
164DCE092AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 164DCE062AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp */; };
164DCE0A2AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 164DCE062AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp */; };
2FEA0CDB2490322B00EEF3AD /* spirv_cfg.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A976290921CC60BC00B52A68 /* spirv_cfg.hpp */; };
2FEA0CDC2490322B00EEF3AD /* spirv_cross_parsed_ir.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A976290821CC60BC00B52A68 /* spirv_cross_parsed_ir.hpp */; };
2FEA0CDD2490322B00EEF3AD /* spirv_common.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A976290721CC60BC00B52A68 /* spirv_common.hpp */; };
Expand Down Expand Up @@ -2367,6 +2371,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
164DCE062AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_msl_vertex_loader.cpp; sourceTree = "<group>"; };
2FEA0B4A2490321700EEF3AD /* libglslang.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libglslang.a; sourceTree = BUILT_PRODUCTS_DIR; };
2FEA0CD82490322100EEF3AD /* libSPIRVTools.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSPIRVTools.a; sourceTree = BUILT_PRODUCTS_DIR; };
2FEA0CEF2490322B00EEF3AD /* libSPIRVCross.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSPIRVCross.a; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -3019,6 +3024,7 @@
A976290321CC60BC00B52A68 /* spirv_cross.hpp */,
A976290621CC60BC00B52A68 /* spirv_glsl.cpp */,
A976290A21CC60BC00B52A68 /* spirv_glsl.hpp */,
164DCE062AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp */,
A976290D21CC60BC00B52A68 /* spirv_msl.cpp */,
A976290221CC60BC00B52A68 /* spirv_msl.hpp */,
A976290421CC60BC00B52A68 /* spirv_parser.cpp */,
Expand Down Expand Up @@ -5813,6 +5819,7 @@
2FEA0CE72490322B00EEF3AD /* spirv_cross.cpp in Sources */,
2FEA0CE82490322B00EEF3AD /* spirv_reflect.cpp in Sources */,
2FEA0CE92490322B00EEF3AD /* spirv_glsl.cpp in Sources */,
164DCE082AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp in Sources */,
2FEA0CEA2490322B00EEF3AD /* spirv_cross_parsed_ir.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -6385,6 +6392,7 @@
A976291621CC60BC00B52A68 /* spirv_cross.cpp in Sources */,
450A4F68221C5A95007203D7 /* spirv_reflect.cpp in Sources */,
A976291821CC60BC00B52A68 /* spirv_glsl.cpp in Sources */,
164DCE0A2AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp in Sources */,
A976292821CC60BC00B52A68 /* spirv_cross_parsed_ir.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -6399,6 +6407,7 @@
A976291521CC60BC00B52A68 /* spirv_cross.cpp in Sources */,
450A4F67221C5A95007203D7 /* spirv_reflect.cpp in Sources */,
A976291721CC60BC00B52A68 /* spirv_glsl.cpp in Sources */,
164DCE072AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp in Sources */,
A976292721CC60BC00B52A68 /* spirv_cross_parsed_ir.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -6413,6 +6422,7 @@
DCFD7C9B2A45BA7D007BBBF7 /* spirv_cross.cpp in Sources */,
DCFD7C9C2A45BA7D007BBBF7 /* spirv_reflect.cpp in Sources */,
DCFD7C9D2A45BA7D007BBBF7 /* spirv_glsl.cpp in Sources */,
164DCE092AABA74B00E4B88F /* spirv_msl_vertex_loader.cpp in Sources */,
DCFD7C9E2A45BA7D007BBBF7 /* spirv_cross_parsed_ir.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
1 change: 1 addition & 0 deletions ExternalRevisions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ if you encounter any building errors, you may need to re-add the *SPIRV-Cross* l
spirv_cross.hpp
spirv_glsl.cpp
spirv_glsl.hpp
spirv_msl_vertex_loader.cpp
spirv_msl.cpp
spirv_msl.hpp
spirv_parser.cpp
Expand Down
2 changes: 1 addition & 1 deletion ExternalRevisions/SPIRV-Cross_repo_revision
Original file line number Diff line number Diff line change
@@ -1 +1 @@
bccaa94db814af33d8ef05c153e7c34d8bd4d685
324b9393f2a40d4883d280669886e701f12e22a6
11 changes: 11 additions & 0 deletions MoltenVK/MoltenVK/API/mvk_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,17 @@ typedef struct {
*/
float timestampPeriodLowPassAlpha;

/**
* Force MoltenVK to always use shader code to load vertices (rather than translate to Metal's vertex descriptors).
* (Default is to only use shader vertex loaders in situations that Metal's descriptors don't support.)
*
* The initial value or this parameter is set by the
* MVK_CONFIG_FORCE_SHADER_VERTEX_LOADER
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, this setting is disabled by default.
*/
VkBool32 forceShaderVertexLoader;

} MVKConfiguration;


Expand Down
1 change: 1 addition & 0 deletions MoltenVK/MoltenVK/API/mvk_private_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ typedef struct {
VkBool32 programmableSamplePositions; /**< If true, programmable MSAA sample positions are supported. */
VkBool32 shaderBarycentricCoordinates; /**< If true, fragment shader barycentric coordinates are supported. */
MTLArgumentBuffersTier argumentBuffersTier; /**< The argument buffer tier available on this device, as a Metal enumeration. */
VkBool32 pixelTypeLoads; /**< Supports loading from types like `device rgb9e5<float3>*` in MSL */
VkBool32 needsSampleDrefLodArrayWorkaround; /**< If true, sampling from arrayed depth images with explicit LoD is broken and needs a workaround. */
VkDeviceSize hostMemoryPageSize; /**< The size of a page of host memory on this platform. */
} MVKPhysicalDeviceMetalFeatures;
Expand Down
12 changes: 0 additions & 12 deletions MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,6 @@
atIndex: pipeline->getOutputBufferIndex().stages[kMVKShaderStageVertex]];
}
[mtlTessCtlEncoder setStageInRegion: MTLRegionMake2D(_firstVertex, _firstInstance, _vertexCount, _instanceCount)];
// If there are vertex bindings with a zero vertex divisor, I need to offset them by
// _firstInstance * stride, since that is the expected behaviour for a divisor of 0.
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance);
id<MTLComputePipelineState> vtxState = pipeline->getTessVertexStageState();
if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) {
#if MVK_MACOS_OR_IOS
Expand Down Expand Up @@ -294,7 +291,6 @@
MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1;
uint32_t instanceCount = _instanceCount * viewCount;
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance);
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
vertexStart: _firstVertex
Expand Down Expand Up @@ -422,9 +418,6 @@
offset: idxBuffOffset
atIndex: pipeline->getIndirectParamsIndex().stages[kMVKShaderStageVertex]];
[mtlTessCtlEncoder setStageInRegion: MTLRegionMake2D(_vertexOffset, _firstInstance, _indexCount, _instanceCount)];
// If there are vertex bindings with a zero vertex divisor, I need to offset them by
// _firstInstance * stride, since that is the expected behaviour for a divisor of 0.
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance);
id<MTLComputePipelineState> vtxState = ibb.mtlIndexType == MTLIndexTypeUInt16 ? pipeline->getTessVertexStageIndex16State() : pipeline->getTessVertexStageIndex32State();
if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) {
#if MVK_MACOS_OR_IOS
Expand Down Expand Up @@ -528,7 +521,6 @@
MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1;
uint32_t instanceCount = _instanceCount * viewCount;
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance);
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
indexCount: _indexCount
Expand Down Expand Up @@ -1230,9 +1222,6 @@
indirectBufferOffset: mtlTempIndBuffOfst];
mtlTempIndBuffOfst += sizeof(MTLStageInRegionIndirectArguments);
}
// If this is a synthetic command that originated in a direct call, and there are vertex bindings with a zero vertex
// divisor, I need to offset them by _firstInstance * stride, since that is the expected behaviour for a divisor of 0.
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _directCmdFirstInstance);
[mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: mtlIndBuff
indirectBufferOffset: mtlTempIndBuffOfst
threadsPerThreadgroup: MTLSizeMake(vtxThreadExecWidth, 1, 1)];
Expand Down Expand Up @@ -1311,7 +1300,6 @@
cmdEncoder->_graphicsResourcesState.beginMetalRenderPass();
cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass();
} else {
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _directCmdFirstInstance);
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
indexType: (MTLIndexType)ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer
Expand Down
3 changes: 0 additions & 3 deletions MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
Original file line number Diff line number Diff line change
Expand Up @@ -556,9 +556,6 @@ class MVKGraphicsResourcesCommandEncoderState : public MVKResourcesCommandEncode
MTLResourceUsage mtlUsage,
MTLRenderStages mtlStages) override;

/** Offset all buffers for vertex attribute bindings with zero divisors by the given number of strides. */
void offsetZeroDivisorVertexBuffers(MVKGraphicsStage stage, MVKGraphicsPipeline* pipeline, uint32_t firstInstance);

/**
* Marks the buffer binding using the index as having been overridden,
* such as by push constants or internal rendering in some transfers.
Expand Down
34 changes: 0 additions & 34 deletions MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
Original file line number Diff line number Diff line change
Expand Up @@ -733,30 +733,6 @@
encodeBinding<MVKMTLSamplerStateBinding>(shaderStage.samplerStateBindings, shaderStage.areSamplerStateBindingsDirty, bindSampler);
}

void MVKGraphicsResourcesCommandEncoderState::offsetZeroDivisorVertexBuffers(MVKGraphicsStage stage,
MVKGraphicsPipeline* pipeline,
uint32_t firstInstance) {
auto& shaderStage = _shaderStageResourceBindings[kMVKShaderStageVertex];
for (auto& binding : pipeline->getZeroDivisorVertexBindings()) {
uint32_t mtlBuffIdx = pipeline->getMetalBufferIndexForVertexAttributeBinding(binding.first);
auto iter = std::find_if(shaderStage.bufferBindings.begin(), shaderStage.bufferBindings.end(), [mtlBuffIdx](const MVKMTLBufferBinding& b) { return b.index == mtlBuffIdx; });
if (!iter) { continue; }
switch (stage) {
case kMVKGraphicsStageVertex:
[_cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl) setBufferOffset: iter->offset + firstInstance * binding.second
atIndex: mtlBuffIdx];
break;
case kMVKGraphicsStageRasterization:
[_cmdEncoder->_mtlRenderEncoder setVertexBufferOffset: iter->offset + firstInstance * binding.second
atIndex: mtlBuffIdx];
break;
default:
assert(false); // If we hit this, something went wrong.
break;
}
}
}

void MVKGraphicsResourcesCommandEncoderState::endMetalRenderPass() {
MVKResourcesCommandEncoderState::endMetalRenderPass();
_renderUsageStages.clear();
Expand Down Expand Up @@ -831,16 +807,6 @@
offset: b.offset
atIndex: b.index];
}

// Add any translated vertex bindings for this binding
auto xltdVtxBindings = pipeline->getTranslatedVertexBindings();
for (auto& xltdBind : xltdVtxBindings) {
if (b.index == pipeline->getMetalBufferIndexForVertexAttributeBinding(xltdBind.binding)) {
[cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer
offset: b.offset + xltdBind.translationOffset
atIndex: pipeline->getMetalBufferIndexForVertexAttributeBinding(xltdBind.translationBinding)];
}
}
}
} else {
b.isDirty = true; // We haven't written it out, so leave dirty until next time.
Expand Down
3 changes: 3 additions & 0 deletions MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject {
/** Populates the specified structure with the features of this device. */
void getFeatures(VkPhysicalDeviceFeatures2* features);

/** Returns a structure with the features of this device */
const VkPhysicalDeviceFeatures& getFeatures() const { return _features; }

/** Populates the specified structure with the properties of this device. */
void getProperties(VkPhysicalDeviceProperties* properties);

Expand Down
7 changes: 6 additions & 1 deletion MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR: {
auto* portabilityProps = (VkPhysicalDevicePortabilitySubsetPropertiesKHR*)next;
portabilityProps->minVertexInputBindingStrideAlignment = (uint32_t)_metalFeatures.vertexStrideAlignment;
portabilityProps->minVertexInputBindingStrideAlignment = 1; // Shader vertex loader has no restrictions
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT: {
Expand Down Expand Up @@ -1642,6 +1642,7 @@
initMetalFeatures(); // Call second.
initFeatures(); // Call third.
initLimits(); // Call fourth.
_pixelFormats.modifyCapabilitiesFromPhysicalDevice();
initExtensions();
initMemoryProperties();
initExternalMemoryProperties();
Expand Down Expand Up @@ -1861,6 +1862,7 @@
if (supportsMTLFeatureSet(iOS_GPUFamily4_v1)) {
_metalFeatures.postDepthCoverage = true;
_metalFeatures.nonUniformThreadgroups = true;
_metalFeatures.pixelTypeLoads = true;
}

if (supportsMTLFeatureSet(iOS_GPUFamily5_v1)) {
Expand Down Expand Up @@ -2025,6 +2027,9 @@
_metalFeatures.renderLinearTextures = true;
_metalFeatures.tileBasedDeferredRendering = true;

if (supportsMTLGPUFamily(Apple4)) {
_metalFeatures.pixelTypeLoads = true;
}
#if MVK_XCODE_12
if (supportsMTLGPUFamily(Apple6)) {
_metalFeatures.astcHDRTextures = true;
Expand Down
10 changes: 1 addition & 9 deletions MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,6 @@ class MVKGraphicsPipeline : public MVKPipeline {
/** Returns the Metal vertex buffer index to use for the specified vertex attribute binding number. */
uint32_t getMetalBufferIndexForVertexAttributeBinding(uint32_t binding) { return _device->getMetalBufferIndexForVertexAttributeBinding(binding); }

/** Returns the collection of translated vertex bindings. */
MVKArrayRef<MVKTranslatedVertexBinding> getTranslatedVertexBindings() { return _translatedVertexBindings.contents(); }

/** Returns the collection of instance-rate vertex bindings whose divisor is zero, along with their strides. */
MVKArrayRef<MVKZeroDivisorVertexBinding> getZeroDivisorVertexBindings() { return _zeroDivisorVertexBindings.contents(); }

/** Returns the MTLArgumentEncoder for the descriptor set. */
MVKMTLArgumentEncoder& getMTLArgumentEncoder(uint32_t descSetIndex, MVKShaderStage stage) override { return _mtlArgumentEncoders[descSetIndex].stages[stage]; }

Expand Down Expand Up @@ -336,6 +330,7 @@ class MVKGraphicsPipeline : public MVKPipeline {
bool addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, SPIRVShaderInputs& nextInputs, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB);
bool addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo*& pFragmentSS);
bool addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB);
bool canVertexInputUseMetalDescriptor(const VkPipelineVertexInputStateCreateInfo* pVI);
template<class T>
bool addVertexInputToPipeline(T* inputDesc, const VkPipelineVertexInputStateCreateInfo* pVI, const SPIRVToMSLConversionConfiguration& shaderConfig);
void adjustVertexInputForMultiview(MTLVertexDescriptor* inputDesc, const VkPipelineVertexInputStateCreateInfo* pVI, uint32_t viewCount, uint32_t oldViewCount = 1);
Expand All @@ -344,7 +339,6 @@ class MVKGraphicsPipeline : public MVKPipeline {
bool isRenderingPoints(const VkGraphicsPipelineCreateInfo* pCreateInfo);
bool isRasterizationDisabled(const VkGraphicsPipelineCreateInfo* pCreateInfo);
bool verifyImplicitBuffer(bool needsBuffer, MVKShaderImplicitRezBinding& index, MVKShaderStage stage, const char* name);
uint32_t getTranslatedVertexBinding(uint32_t binding, uint32_t translationOffset, uint32_t maxBinding);
uint32_t getImplicitBufferIndex(MVKShaderStage stage, uint32_t bufferIndexOffset);
MVKMTLFunction getMTLFunction(SPIRVToMSLConversionConfiguration& shaderConfig,
const VkPipelineShaderStageCreateInfo* pShaderStage,
Expand All @@ -361,8 +355,6 @@ class MVKGraphicsPipeline : public MVKPipeline {
MVKSmallVector<VkRect2D, kMVKMaxViewportScissorCount> _scissors;
MVKSmallVector<VkDynamicState> _dynamicState;
MVKSmallVector<MTLSamplePosition> _customSamplePositions;
MVKSmallVector<MVKTranslatedVertexBinding> _translatedVertexBindings;
MVKSmallVector<MVKZeroDivisorVertexBinding> _zeroDivisorVertexBindings;
MVKSmallVector<MVKStagedMTLArgumentEncoders> _mtlArgumentEncoders;
MVKSmallVector<MVKStagedDescriptorBindingUse> _descriptorBindingUse;
MVKSmallVector<MVKShaderStage> _stagesUsingPhysicalStorageBufferAddressesCapability;
Expand Down
Loading
Loading