Merge pull request #1755 from cdavis5e/raw-buffer-tese-input

MVKPipeline: Stop using vertex-style input for tessellation evaluatio…
This commit is contained in:
Bill Hollings 2022-11-10 20:46:24 -05:00 committed by GitHub
commit 5ebeac741d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 18 additions and 113 deletions

View File

@ -1 +1 @@
f09ba2777714871bddb70d049878af34b94fa54d
57639196694a8b5c572c9358f5d9cb443dd341e5

View File

@ -852,10 +852,6 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::newMTLTessRasterStageDescripto
setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get tessellation control outputs: %s", errorLog.c_str()));
return nil;
}
if (!getShaderInputs(((MVKShaderModule*)_pTessEvalSS->module)->getSPIRV(), spv::ExecutionModelTessellationEvaluation, _pTessEvalSS->pName, teInputs, errorLog) ) {
setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get tessellation evaluation inputs: %s", errorLog.c_str()));
return nil;
}
if (!getShaderOutputs(((MVKShaderModule*)_pTessEvalSS->module)->getSPIRV(), spv::ExecutionModelTessellationEvaluation, _pTessEvalSS->pName, teOutputs, errorLog) ) {
setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get tessellation evaluation outputs: %s", errorLog.c_str()));
return nil;
@ -867,112 +863,6 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::newMTLTessRasterStageDescripto
return nil;
}
// Tessellation evaluation stage input
// This needs to happen before compiling the fragment shader, or we'll lose information on shader inputs.
// First, add extra builtins that are in teInputs but not tcOutputs. They can be read
// even if not written.
teInputs.erase(std::remove_if(teInputs.begin(), teInputs.end(), [&tcOutputs](const SPIRVShaderInterfaceVariable& var) {
return var.builtin != spv::BuiltInPosition && var.builtin != spv::BuiltInPointSize && var.builtin != spv::BuiltInClipDistance && var.builtin != spv::BuiltInCullDistance;
}), teInputs.end());
std::remove_copy_if(teInputs.begin(), teInputs.end(), std::back_inserter(tcOutputs), [&tcOutputs](const SPIRVShaderInterfaceVariable& input) {
auto iter = std::find_if(tcOutputs.begin(), tcOutputs.end(), [input](const SPIRVShaderInterfaceVariable& oldVar) {
return oldVar.builtin == input.builtin;
});
if (iter != tcOutputs.end()) {
iter->isUsed = input.isUsed;
}
return iter != tcOutputs.end();
});
auto isBuiltInRead = [&teInputs](spv::BuiltIn builtin) {
for (const auto& input : teInputs) {
if (input.builtin == builtin) {
return input.isUsed;
}
}
return false;
};
plDesc.vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];
uint32_t offset = 0, patchOffset = 0, outerLoc = -1, innerLoc = -1;
bool usedPerVertex = false, usedPerPatch = false;
const SPIRVShaderOutput* firstVertex = nullptr, * firstPatch = nullptr;
for (const SPIRVShaderOutput& output : tcOutputs) {
if (output.builtin == spv::BuiltInPointSize && !reflectData.pointMode) { continue; }
if ((output.builtin != spv::BuiltInMax && !isBuiltInRead(output.builtin)) &&
!shaderConfig.isShaderInputLocationUsed(output.location)) {
if (output.perPatch && !(output.builtin == spv::BuiltInTessLevelOuter || output.builtin == spv::BuiltInTessLevelInner) ) {
if (!firstPatch) { firstPatch = &output; }
patchOffset += getShaderOutputSize(output);
} else if (!output.perPatch) {
if (!firstVertex) { firstVertex = &output; }
offset += getShaderOutputSize(output);
}
continue;
}
if (output.perPatch && (output.builtin == spv::BuiltInTessLevelOuter || output.builtin == spv::BuiltInTessLevelInner) ) {
uint32_t location = output.location;
if (output.builtin == spv::BuiltInTessLevelOuter) {
if (outerLoc != (uint32_t)(-1)) { continue; }
if (innerLoc != (uint32_t)(-1)) {
// For triangle tessellation, we use a single attribute. Don't add it more than once.
if (reflectData.patchKind == spv::ExecutionModeTriangles) { continue; }
// getShaderOutputs() assigned individual elements their own locations. Try to reduce the gap.
location = innerLoc + 1;
}
outerLoc = location;
} else {
if (innerLoc != (uint32_t)(-1)) { continue; }
if (outerLoc != (uint32_t)(-1)) {
if (reflectData.patchKind == spv::ExecutionModeTriangles) { continue; }
location = outerLoc + 1;
}
innerLoc = location;
}
plDesc.vertexDescriptor.attributes[location].bufferIndex = getMetalBufferIndexForVertexAttributeBinding(kMVKTessEvalLevelBufferBinding);
if (reflectData.patchKind == spv::ExecutionModeTriangles || output.builtin == spv::BuiltInTessLevelOuter) {
plDesc.vertexDescriptor.attributes[location].offset = 0;
plDesc.vertexDescriptor.attributes[location].format = MTLVertexFormatHalf4; // FIXME Should use Float4
} else {
plDesc.vertexDescriptor.attributes[location].offset = 8;
plDesc.vertexDescriptor.attributes[location].format = MTLVertexFormatHalf2; // FIXME Should use Float2
}
} else if (output.perPatch) {
patchOffset = (uint32_t)mvkAlignByteCount(patchOffset, getShaderOutputAlignment(output));
plDesc.vertexDescriptor.attributes[output.location].bufferIndex = getMetalBufferIndexForVertexAttributeBinding(kMVKTessEvalPatchInputBufferBinding);
plDesc.vertexDescriptor.attributes[output.location].format = getPixelFormats()->getMTLVertexFormat(mvkFormatFromOutput(output));
plDesc.vertexDescriptor.attributes[output.location].offset = patchOffset;
patchOffset += getShaderOutputSize(output);
if (!firstPatch) { firstPatch = &output; }
usedPerPatch = true;
} else {
offset = (uint32_t)mvkAlignByteCount(offset, getShaderOutputAlignment(output));
plDesc.vertexDescriptor.attributes[output.location].bufferIndex = getMetalBufferIndexForVertexAttributeBinding(kMVKTessEvalInputBufferBinding);
plDesc.vertexDescriptor.attributes[output.location].format = getPixelFormats()->getMTLVertexFormat(mvkFormatFromOutput(output));
plDesc.vertexDescriptor.attributes[output.location].offset = offset;
offset += getShaderOutputSize(output);
if (!firstVertex) { firstVertex = &output; }
usedPerVertex = true;
}
}
if (usedPerVertex) {
uint32_t mtlVBIdx = getMetalBufferIndexForVertexAttributeBinding(kMVKTessEvalInputBufferBinding);
plDesc.vertexDescriptor.layouts[mtlVBIdx].stepFunction = MTLVertexStepFunctionPerPatchControlPoint;
plDesc.vertexDescriptor.layouts[mtlVBIdx].stride = mvkAlignByteCount(offset, getShaderOutputAlignment(*firstVertex));
}
if (usedPerPatch) {
uint32_t mtlVBIdx = getMetalBufferIndexForVertexAttributeBinding(kMVKTessEvalPatchInputBufferBinding);
plDesc.vertexDescriptor.layouts[mtlVBIdx].stepFunction = MTLVertexStepFunctionPerPatch;
plDesc.vertexDescriptor.layouts[mtlVBIdx].stride = mvkAlignByteCount(patchOffset, getShaderOutputAlignment(*firstPatch));
}
if (outerLoc != (uint32_t)(-1) || innerLoc != (uint32_t)(-1)) {
uint32_t mtlVBIdx = getMetalBufferIndexForVertexAttributeBinding(kMVKTessEvalLevelBufferBinding);
plDesc.vertexDescriptor.layouts[mtlVBIdx].stepFunction = MTLVertexStepFunctionPerPatch;
plDesc.vertexDescriptor.layouts[mtlVBIdx].stride =
reflectData.patchKind == spv::ExecutionModeTriangles ? sizeof(MTLTriangleTessellationFactorsHalf) :
sizeof(MTLQuadTessellationFactorsHalf);
}
// Fragment shader - only add if rasterization is enabled
if (!addFragmentShaderToPipeline(plDesc, pCreateInfo, shaderConfig, teOutputs)) {
[plDesc release];
@ -1203,9 +1093,13 @@ bool MVKGraphicsPipeline::addTessEvalShaderToPipeline(MTLRenderPipelineDescripto
shaderConfig.options.entryPointStage = spv::ExecutionModelTessellationEvaluation;
shaderConfig.options.entryPointName = _pTessEvalSS->pName;
shaderConfig.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageTessEval];
shaderConfig.options.mslOptions.shader_input_buffer_index = getMetalBufferIndexForVertexAttributeBinding(kMVKTessEvalInputBufferBinding);
shaderConfig.options.mslOptions.shader_patch_input_buffer_index = getMetalBufferIndexForVertexAttributeBinding(kMVKTessEvalPatchInputBufferBinding);
shaderConfig.options.mslOptions.shader_tess_factor_buffer_index = getMetalBufferIndexForVertexAttributeBinding(kMVKTessEvalLevelBufferBinding);
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.raw_buffer_tese_input = true;
shaderConfig.options.mslOptions.disable_rasterization = !_isRasterizing;
addPrevStageOutputToShaderConversionConfig(shaderConfig, tcOutputs);
@ -1808,6 +1702,7 @@ void MVKGraphicsPipeline::addNextStageInputToShaderConversionConfig(SPIRVToMSLCo
so.shaderVar.component = shaderInputs[soIdx].component;
so.shaderVar.builtin = shaderInputs[soIdx].builtin;
so.shaderVar.vecsize = shaderInputs[soIdx].vecWidth;
so.shaderVar.rate = shaderInputs[soIdx].perPatch ? MSL_SHADER_VARIABLE_RATE_PER_PATCH : MSL_SHADER_VARIABLE_RATE_PER_VERTEX;
switch (getPixelFormats()->getFormatType(mvkFormatFromOutput(shaderInputs[soIdx]) ) ) {
case kMVKFormatColorUInt8:
@ -1851,6 +1746,7 @@ void MVKGraphicsPipeline::addPrevStageOutputToShaderConversionConfig(SPIRVToMSLC
si.shaderVar.component = shaderOutputs[siIdx].component;
si.shaderVar.builtin = shaderOutputs[siIdx].builtin;
si.shaderVar.vecsize = shaderOutputs[siIdx].vecWidth;
si.shaderVar.rate = shaderOutputs[siIdx].perPatch ? MSL_SHADER_VARIABLE_RATE_PER_PATCH : MSL_SHADER_VARIABLE_RATE_PER_VERTEX;
switch (getPixelFormats()->getFormatType(mvkFormatFromOutput(shaderOutputs[siIdx]) ) ) {
case kMVKFormatColorUInt8:
@ -2312,6 +2208,7 @@ namespace SPIRV_CROSS_NAMESPACE {
opt.dynamic_offsets_buffer_index,
opt.shader_input_buffer_index,
opt.shader_index_buffer_index,
opt.shader_patch_input_buffer_index,
opt.shader_input_wg_index,
opt.device_index,
opt.enable_frag_output_mask,
@ -2348,7 +2245,8 @@ namespace SPIRV_CROSS_NAMESPACE {
opt.ios_use_simdgroup_functions,
opt.emulate_subgroups,
opt.vertex_index_type,
opt.force_sample_rate_shading);
opt.force_sample_rate_shading,
opt.raw_buffer_tese_input);
}
template<class Archive>
@ -2357,7 +2255,8 @@ namespace SPIRV_CROSS_NAMESPACE {
si.component,
si.format,
si.builtin,
si.vecsize);
si.vecsize,
si.rate);
}
template<class Archive>

View File

@ -313,6 +313,12 @@ namespace mvk {
bool isUsed = true;
const auto* type = &reflect.get_type(reflect.get_type_from_variable(varID).parent_type);
bool patch = reflect.has_decoration(varID, spv::DecorationPatch);
if (reflect.has_decoration(type->self, spv::DecorationBlock)) {
// In this case, the Patch decoration is on the members.
// FIXME It is theoretically possible for some members of a block to have
// the decoration and some not. What then?
patch = reflect.has_member_decoration(type->self, 0, spv::DecorationPatch);
}
auto biType = spv::BuiltInMax;
if (reflect.has_decoration(varID, spv::DecorationBuiltIn)) {
biType = (spv::BuiltIn)reflect.get_decoration(varID, spv::DecorationBuiltIn);