Merge pull request #1408 from billhollings/handle-bad-api-pointers

Properly ignore non-null pipeline creation pointers that should be ignored.
This commit is contained in:
Bill Hollings 2021-07-26 18:15:48 -04:00 committed by GitHub
commit 3236796839
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 47 additions and 21 deletions

View File

@ -398,6 +398,9 @@ protected:
bool _needsFragmentBufferSizeBuffer = false;
bool _needsFragmentDynamicOffsetBuffer = false;
bool _needsFragmentViewRangeBuffer = false;
bool _isRasterizing = false;
bool _isRasterizingColor = false;
bool _isRasterizingDepthStencil = false;
};

View File

@ -365,6 +365,13 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
const VkGraphicsPipelineCreateInfo* pCreateInfo) :
MVKPipeline(device, pipelineCache, (MVKPipelineLayout*)pCreateInfo->layout, parent) {
// Determine rasterization early, as various other structs are validated and interpreted in this context.
MVKRenderPass* mvkRendPass = (MVKRenderPass*)pCreateInfo->renderPass;
MVKRenderSubpass* mvkRenderSubpass = mvkRendPass->getSubpass(pCreateInfo->subpass);
_isRasterizing = !isRasterizationDisabled(pCreateInfo);
_isRasterizingColor = _isRasterizing && mvkRenderSubpass->hasColorAttachments();
_isRasterizingDepthStencil = _isRasterizing && mvkRenderSubpass->hasDepthStencilAttachment();
// Get the tessellation shaders, if present. Do this now, because we need to extract
// reflection data from them that informs everything else.
for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
@ -405,8 +412,8 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
}
}
// Blending
if (pCreateInfo->pColorBlendState) {
// Blending - must ignore allowed bad pColorBlendState pointer if rasterization disabled or no color attachments
if (_isRasterizingColor && pCreateInfo->pColorBlendState) {
memcpy(&_blendConstants, &pCreateInfo->pColorBlendState->blendConstants, sizeof(_blendConstants));
}
@ -421,9 +428,9 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
}
}
// Tessellation
// Tessellation - must ignore allowed bad pTessellationState pointer if not tess pipeline
_outputControlPointCount = reflectData.numControlPoints;
mvkSetOrClear(&_tessInfo, pCreateInfo->pTessellationState);
mvkSetOrClear(&_tessInfo, (_pTessCtlSS && _pTessEvalSS) ? pCreateInfo->pTessellationState : nullptr);
// Rasterization
_mtlCullMode = MTLCullModeNone;
@ -448,10 +455,11 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
initMTLRenderPipelineState(pCreateInfo, reflectData);
// Depth stencil content - clearing will disable depth and stencil testing
mvkSetOrClear(&_depthStencilInfo, pCreateInfo->pDepthStencilState);
// Must ignore allowed bad pDepthStencilState pointer if rasterization disabled or no depth attachment
mvkSetOrClear(&_depthStencilInfo, _isRasterizingDepthStencil ? pCreateInfo->pDepthStencilState : nullptr);
// Viewports and scissors
auto pVPState = pCreateInfo->pViewportState;
// Viewports and scissors - must ignore allowed bad pViewportState pointer if rasterization is disabled
auto pVPState = _isRasterizing ? pCreateInfo->pViewportState : nullptr;
if (pVPState) {
uint32_t vpCnt = pVPState->viewportCount;
_viewports.reserve(vpCnt);
@ -920,7 +928,7 @@ bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLRenderPipelineDescriptor*
shaderConfig.options.mslOptions.dynamic_offsets_buffer_index = _dynamicOffsetBufferIndex.stages[kMVKShaderStageVertex];
shaderConfig.options.mslOptions.view_mask_buffer_index = _viewRangeBufferIndex.stages[kMVKShaderStageVertex];
shaderConfig.options.mslOptions.capture_output_to_buffer = false;
shaderConfig.options.mslOptions.disable_rasterization = isRasterizationDisabled(pCreateInfo);
shaderConfig.options.mslOptions.disable_rasterization = !_isRasterizing;
addVertexInputToShaderConversionConfig(shaderConfig, pCreateInfo);
MVKMTLFunction func = ((MVKShaderModule*)_pVertexSS->module)->getMTLFunction(&shaderConfig, _pVertexSS->pSpecializationInfo, _pipelineCache);
@ -1108,7 +1116,7 @@ bool MVKGraphicsPipeline::addTessEvalShaderToPipeline(MTLRenderPipelineDescripto
shaderConfig.options.mslOptions.buffer_size_buffer_index = _bufferSizeBufferIndex.stages[kMVKShaderStageTessEval];
shaderConfig.options.mslOptions.dynamic_offsets_buffer_index = _dynamicOffsetBufferIndex.stages[kMVKShaderStageTessEval];
shaderConfig.options.mslOptions.capture_output_to_buffer = false;
shaderConfig.options.mslOptions.disable_rasterization = isRasterizationDisabled(pCreateInfo);
shaderConfig.options.mslOptions.disable_rasterization = !_isRasterizing;
addPrevStageOutputToShaderConversionConfig(shaderConfig, tcOutputs);
MVKMTLFunction func = ((MVKShaderModule*)_pTessEvalSS->module)->getMTLFunction(&shaderConfig, _pTessEvalSS->pSpecializationInfo, _pipelineCache);
@ -1157,7 +1165,7 @@ bool MVKGraphicsPipeline::addFragmentShaderToPipeline(MTLRenderPipelineDescripto
shaderConfig.options.entryPointName = _pFragmentSS->pName;
shaderConfig.options.mslOptions.capture_output_to_buffer = false;
shaderConfig.options.mslOptions.fixed_subgroup_size = mvkIsAnyFlagEnabled(_pFragmentSS->flags, VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT) ? 0 : _device->_pMetalFeatures->maxSubgroupSize;
if (pCreateInfo->pMultisampleState) {
if (_isRasterizing && pCreateInfo->pMultisampleState) { // Must ignore allowed bad pMultisampleState pointer if rasterization disabled
if (pCreateInfo->pMultisampleState->pSampleMask && pCreateInfo->pMultisampleState->pSampleMask[0] != 0xffffffff) {
shaderConfig.options.mslOptions.additional_fixed_sample_mask = pCreateInfo->pMultisampleState->pSampleMask[0];
}
@ -1444,9 +1452,9 @@ void MVKGraphicsPipeline::addFragmentOutputToPipeline(MTLRenderPipelineDescripto
: mvkMTLPrimitiveTopologyClassFromVkPrimitiveTopology(pCreateInfo->pInputAssemblyState->topology);
}
// Color attachments
// Color attachments - must ignore bad pColorBlendState pointer if rasterization is disabled or subpass has no color attachments
uint32_t caCnt = 0;
if (pCreateInfo->pColorBlendState) {
if (_isRasterizingColor && pCreateInfo->pColorBlendState) {
for (uint32_t caIdx = 0; caIdx < pCreateInfo->pColorBlendState->attachmentCount; caIdx++) {
const VkPipelineColorBlendAttachmentState* pCA = &pCreateInfo->pColorBlendState->pAttachments[caIdx];
@ -1493,8 +1501,8 @@ void MVKGraphicsPipeline::addFragmentOutputToPipeline(MTLRenderPipelineDescripto
colorDesc.writeMask = MTLColorWriteMaskNone;
}
// Multisampling
if (pCreateInfo->pMultisampleState) {
// Multisampling - must ignore allowed bad pMultisampleState pointer if rasterization disabled
if (_isRasterizing && pCreateInfo->pMultisampleState) {
plDesc.sampleCount = mvkSampleCountFromVkSampleCountFlagBits(pCreateInfo->pMultisampleState->rasterizationSamples);
mvkRenderSubpass->setDefaultSampleCount(pCreateInfo->pMultisampleState->rasterizationSamples);
plDesc.alphaToCoverageEnabled = pCreateInfo->pMultisampleState->alphaToCoverageEnable;
@ -1507,8 +1515,9 @@ void MVKGraphicsPipeline::initShaderConversionConfig(SPIRVToMSLConversionConfigu
const VkGraphicsPipelineCreateInfo* pCreateInfo,
const SPIRVTessReflectionData& reflectData) {
// Tessellation - must ignore allowed bad pTessellationState pointer if not tess pipeline
VkPipelineTessellationDomainOriginStateCreateInfo* pTessDomainOriginState = nullptr;
if (pCreateInfo->pTessellationState) {
if (isTessellationPipeline() && pCreateInfo->pTessellationState) {
for (const auto* next = (VkBaseInStructure*)pCreateInfo->pTessellationState->pNext; next; next = next->pNext) {
switch (next->sType) {
case VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO:
@ -1550,9 +1559,10 @@ void MVKGraphicsPipeline::initShaderConversionConfig(SPIRVToMSLConversionConfigu
// fragment shader outputs a color value without a corresponding color attachment.
// However, if alpha-to-coverage is enabled, we must enable the fragment shader first color output,
// even without a color attachment present or in use, so that coverage can be calculated.
bool hasA2C = pCreateInfo->pMultisampleState && pCreateInfo->pMultisampleState->alphaToCoverageEnable;
// Must ignore allowed bad pMultisampleState pointer if rasterization disabled
bool hasA2C = _isRasterizing && pCreateInfo->pMultisampleState && pCreateInfo->pMultisampleState->alphaToCoverageEnable;
shaderConfig.options.mslOptions.enable_frag_output_mask = hasA2C ? 1 : 0;
if (pCreateInfo->pColorBlendState) {
if (_isRasterizingColor && pCreateInfo->pColorBlendState) {
for (uint32_t caIdx = 0; caIdx < pCreateInfo->pColorBlendState->attachmentCount; caIdx++) {
if (mvkRenderSubpass->isColorAttachmentUsed(caIdx)) {
mvkEnableFlags(shaderConfig.options.mslOptions.enable_frag_output_mask, 1 << caIdx);

View File

@ -47,13 +47,19 @@ public:
MVKVulkanAPIObject* getVulkanAPIObject() override;
/** Returns the parent render pass of this subpass. */
inline MVKRenderPass* getRenderPass() { return _renderPass; }
MVKRenderPass* getRenderPass() { return _renderPass; }
/** Returns the index of this subpass in its parent render pass. */
inline uint32_t getSubpassIndex() { return _subpassIndex; }
uint32_t getSubpassIndex() { return _subpassIndex; }
/** Returns whether this subpass has any color attachments. */
bool hasColorAttachments();
/** Returns whether this subpass has a depth/stencil attachment. */
bool hasDepthStencilAttachment() { return _depthStencilAttachment.attachment != VK_ATTACHMENT_UNUSED; }
/** Returns the number of color attachments, which may be zero for depth-only rendering. */
inline uint32_t getColorAttachmentCount() { return uint32_t(_colorAttachments.size()); }
uint32_t getColorAttachmentCount() { return uint32_t(_colorAttachments.size()); }
/** Returns the format of the color attachment at the specified index. */
VkFormat getColorAttachmentFormat(uint32_t colorAttIdx);
@ -74,7 +80,7 @@ public:
bool isMultiview() const { return _viewMask != 0; }
/** Returns the total number of views to be rendered. */
inline uint32_t getViewCount() const { return __builtin_popcount(_viewMask); }
uint32_t getViewCount() const { return __builtin_popcount(_viewMask); }
/** Returns the number of Metal render passes needed to render all views. */
uint32_t getMultiviewMetalPassCount() const;

View File

@ -35,6 +35,13 @@ using namespace std;
MVKVulkanAPIObject* MVKRenderSubpass::getVulkanAPIObject() { return _renderPass->getVulkanAPIObject(); };
bool MVKRenderSubpass::hasColorAttachments() {
for (auto& ca : _colorAttachments) {
if (ca.attachment != VK_ATTACHMENT_UNUSED) { return true; }
}
return false;
}
VkFormat MVKRenderSubpass::getColorAttachmentFormat(uint32_t colorAttIdx) {
if (colorAttIdx < _colorAttachments.size()) {
uint32_t rpAttIdx = _colorAttachments[colorAttIdx].attachment;