MVKPipeline: Add builtins that are read but not written to tessellation pipelines.
It is always legal in Vulkan to read a builtin, particularly `BuiltInPosition`, even if it weren't written by the previous stage. The CTS tests that this scenario works in the driver. Update SPIRV-Cross to pull in a change required for this. Fixes 8 CTS tests under `dEQP-VK.pipeline.*.no_position`. (Eight other tests worked solely by accident without this change.)
This commit is contained in:
parent
013a192466
commit
fafcc4b844
@ -1 +1 @@
|
||||
61c603f3baa5270e04bcfb6acf83c654e3c57679
|
||||
f6ca6178251c3c886d99781c5437df919fc21734
|
||||
|
@ -293,7 +293,8 @@ public:
|
||||
~MVKGraphicsPipeline() override;
|
||||
|
||||
protected:
|
||||
typedef MVKSmallVector<SPIRVShaderOutput, 32> SPIRVShaderOutputs;
|
||||
typedef MVKSmallVector<SPIRVShaderInterfaceVariable, 32> SPIRVShaderOutputs;
|
||||
typedef MVKSmallVector<SPIRVShaderInterfaceVariable, 32> SPIRVShaderInputs;
|
||||
|
||||
id<MTLRenderPipelineState> getOrCompilePipeline(MTLRenderPipelineDescriptor* plDesc, id<MTLRenderPipelineState>& plState);
|
||||
id<MTLComputePipelineState> getOrCompilePipeline(MTLComputePipelineDescriptor* plDesc, id<MTLComputePipelineState>& plState, const char* compilerType);
|
||||
@ -302,14 +303,15 @@ protected:
|
||||
void initShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
|
||||
void initReservedVertexAttributeBufferCount(const VkGraphicsPipelineCreateInfo* pCreateInfo);
|
||||
void addVertexInputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo);
|
||||
void addNextStageInputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderInputs& inputs);
|
||||
void addPrevStageOutputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& outputs);
|
||||
MTLRenderPipelineDescriptor* newMTLRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
|
||||
MTLComputePipelineDescriptor* newMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig);
|
||||
MTLComputePipelineDescriptor* newMTLTessControlStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig);
|
||||
MTLRenderPipelineDescriptor* newMTLTessRasterStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig);
|
||||
bool addVertexShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig);
|
||||
bool addVertexShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig);
|
||||
bool addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput);
|
||||
bool addVertexShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderInputs& nextInputs);
|
||||
bool addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, SPIRVShaderInputs& nextInputs);
|
||||
bool addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput);
|
||||
bool addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput);
|
||||
template<class T>
|
||||
|
@ -669,8 +669,21 @@ MTLComputePipelineDescriptor* MVKGraphicsPipeline::newMTLTessVertexStageDescript
|
||||
SPIRVToMSLConversionConfiguration& shaderConfig) {
|
||||
MTLComputePipelineDescriptor* plDesc = [MTLComputePipelineDescriptor new]; // retained
|
||||
|
||||
SPIRVShaderInputs tcInputs;
|
||||
std::string errorLog;
|
||||
if (!getShaderInputs(((MVKShaderModule*)_pTessCtlSS->module)->getSPIRV(), spv::ExecutionModelTessellationControl, _pTessCtlSS->pName, tcInputs, errorLog) ) {
|
||||
setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get tessellation control inputs: %s", errorLog.c_str()));
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Filter out anything but builtins. We couldn't do this before because we needed to make sure
|
||||
// locations were assigned correctly.
|
||||
tcInputs.erase(std::remove_if(tcInputs.begin(), tcInputs.end(), [](const SPIRVShaderInterfaceVariable& var) {
|
||||
return var.builtin != spv::BuiltInPosition && var.builtin != spv::BuiltInPointSize && var.builtin != spv::BuiltInClipDistance && var.builtin != spv::BuiltInCullDistance;
|
||||
}), tcInputs.end());
|
||||
|
||||
// Add shader stages.
|
||||
if (!addVertexShaderToPipeline(plDesc, pCreateInfo, shaderConfig)) { return nil; }
|
||||
if (!addVertexShaderToPipeline(plDesc, pCreateInfo, shaderConfig, tcInputs)) { return nil; }
|
||||
|
||||
// Vertex input
|
||||
plDesc.stageInputDescriptor = [MTLStageInputOutputDescriptor stageInputOutputDescriptor];
|
||||
@ -794,14 +807,25 @@ MTLComputePipelineDescriptor* MVKGraphicsPipeline::newMTLTessControlStageDescrip
|
||||
MTLComputePipelineDescriptor* plDesc = [MTLComputePipelineDescriptor new]; // retained
|
||||
|
||||
SPIRVShaderOutputs vtxOutputs;
|
||||
SPIRVShaderInputs teInputs;
|
||||
std::string errorLog;
|
||||
if (!getShaderOutputs(((MVKShaderModule*)_pVertexSS->module)->getSPIRV(), spv::ExecutionModelVertex, _pVertexSS->pName, vtxOutputs, errorLog) ) {
|
||||
setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get vertex 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;
|
||||
}
|
||||
|
||||
// Filter out anything but builtins. We couldn't do this before because we needed to make sure
|
||||
// locations were assigned correctly.
|
||||
teInputs.erase(std::remove_if(teInputs.begin(), teInputs.end(), [](const SPIRVShaderInterfaceVariable& var) {
|
||||
return var.builtin != spv::BuiltInPosition && var.builtin != spv::BuiltInPointSize && var.builtin != spv::BuiltInClipDistance && var.builtin != spv::BuiltInCullDistance;
|
||||
}), teInputs.end());
|
||||
|
||||
// Add shader stages.
|
||||
if (!addTessCtlShaderToPipeline(plDesc, pCreateInfo, shaderConfig, vtxOutputs)) {
|
||||
if (!addTessCtlShaderToPipeline(plDesc, pCreateInfo, shaderConfig, vtxOutputs, teInputs)) {
|
||||
[plDesc release];
|
||||
return nil;
|
||||
}
|
||||
@ -822,11 +846,16 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::newMTLTessRasterStageDescripto
|
||||
MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new]; // retained
|
||||
|
||||
SPIRVShaderOutputs tcOutputs, teOutputs;
|
||||
SPIRVShaderInputs teInputs;
|
||||
std::string errorLog;
|
||||
if (!getShaderOutputs(((MVKShaderModule*)_pTessCtlSS->module)->getSPIRV(), spv::ExecutionModelTessellationControl, _pTessCtlSS->pName, tcOutputs, errorLog) ) {
|
||||
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;
|
||||
@ -840,13 +869,38 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::newMTLTessRasterStageDescripto
|
||||
|
||||
// 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 (!shaderConfig.isShaderInputLocationUsed(output.location)) {
|
||||
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);
|
||||
@ -1014,7 +1068,8 @@ bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLRenderPipelineDescriptor*
|
||||
// Adds a vertex shader compiled as a compute kernel to the pipeline description.
|
||||
bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLComputePipelineDescriptor* plDesc,
|
||||
const VkGraphicsPipelineCreateInfo* pCreateInfo,
|
||||
SPIRVToMSLConversionConfiguration& shaderConfig) {
|
||||
SPIRVToMSLConversionConfiguration& shaderConfig,
|
||||
SPIRVShaderInputs& tcInputs) {
|
||||
shaderConfig.options.entryPointStage = spv::ExecutionModelVertex;
|
||||
shaderConfig.options.entryPointName = _pVertexSS->pName;
|
||||
shaderConfig.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageVertex];
|
||||
@ -1026,6 +1081,7 @@ bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLComputePipelineDescriptor
|
||||
shaderConfig.options.mslOptions.vertex_for_tessellation = true;
|
||||
shaderConfig.options.mslOptions.disable_rasterization = true;
|
||||
addVertexInputToShaderConversionConfig(shaderConfig, pCreateInfo);
|
||||
addNextStageInputToShaderConversionConfig(shaderConfig, tcInputs);
|
||||
|
||||
static const CompilerMSL::Options::IndexType indexTypes[] = {
|
||||
CompilerMSL::Options::IndexType::None,
|
||||
@ -1078,7 +1134,8 @@ bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLComputePipelineDescriptor
|
||||
bool MVKGraphicsPipeline::addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc,
|
||||
const VkGraphicsPipelineCreateInfo* pCreateInfo,
|
||||
SPIRVToMSLConversionConfiguration& shaderConfig,
|
||||
SPIRVShaderOutputs& vtxOutputs) {
|
||||
SPIRVShaderOutputs& vtxOutputs,
|
||||
SPIRVShaderInputs& teInputs) {
|
||||
shaderConfig.options.entryPointStage = spv::ExecutionModelTessellationControl;
|
||||
shaderConfig.options.entryPointName = _pTessCtlSS->pName;
|
||||
shaderConfig.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageTessCtl];
|
||||
@ -1093,6 +1150,7 @@ bool MVKGraphicsPipeline::addTessCtlShaderToPipeline(MTLComputePipelineDescripto
|
||||
shaderConfig.options.mslOptions.multi_patch_workgroup = true;
|
||||
shaderConfig.options.mslOptions.fixed_subgroup_size = mvkIsAnyFlagEnabled(_pTessCtlSS->flags, VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT) ? 0 : _device->_pMetalFeatures->maxSubgroupSize;
|
||||
addPrevStageOutputToShaderConversionConfig(shaderConfig, vtxOutputs);
|
||||
addNextStageInputToShaderConversionConfig(shaderConfig, teInputs);
|
||||
|
||||
MVKMTLFunction func = ((MVKShaderModule*)_pTessCtlSS->module)->getMTLFunction(&shaderConfig, _pTessCtlSS->pSpecializationInfo, _pipelineCache);
|
||||
id<MTLFunction> mtlFunc = func.getMTLFunction();
|
||||
@ -1695,7 +1753,7 @@ void MVKGraphicsPipeline::addVertexInputToShaderConversionConfig(SPIRVToMSLConve
|
||||
|
||||
// Set binding and offset from Vulkan vertex attribute
|
||||
mvk::MSLShaderInput si;
|
||||
si.shaderInput.location = pVKVA->location;
|
||||
si.shaderVar.location = pVKVA->location;
|
||||
si.binding = pVKVA->binding;
|
||||
|
||||
// Metal can't do signedness conversions on vertex buffers (rdar://45922847). If the shader
|
||||
@ -1705,11 +1763,11 @@ void MVKGraphicsPipeline::addVertexInputToShaderConversionConfig(SPIRVToMSLConve
|
||||
// declared type. Programs that try to invoke undefined behavior are on their own.
|
||||
switch (getPixelFormats()->getFormatType(pVKVA->format) ) {
|
||||
case kMVKFormatColorUInt8:
|
||||
si.shaderInput.format = MSL_VERTEX_FORMAT_UINT8;
|
||||
si.shaderVar.format = MSL_VERTEX_FORMAT_UINT8;
|
||||
break;
|
||||
|
||||
case kMVKFormatColorUInt16:
|
||||
si.shaderInput.format = MSL_VERTEX_FORMAT_UINT16;
|
||||
si.shaderVar.format = MSL_VERTEX_FORMAT_UINT16;
|
||||
break;
|
||||
|
||||
case kMVKFormatDepthStencil:
|
||||
@ -1719,7 +1777,7 @@ void MVKGraphicsPipeline::addVertexInputToShaderConversionConfig(SPIRVToMSLConve
|
||||
case VK_FORMAT_D16_UNORM_S8_UINT:
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||
si.shaderInput.format = MSL_VERTEX_FORMAT_UINT8;
|
||||
si.shaderVar.format = MSL_VERTEX_FORMAT_UINT8;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1736,6 +1794,49 @@ void MVKGraphicsPipeline::addVertexInputToShaderConversionConfig(SPIRVToMSLConve
|
||||
}
|
||||
}
|
||||
|
||||
// Initializes the shader outputs in a shader conversion config from the next stage input.
|
||||
void MVKGraphicsPipeline::addNextStageInputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig,
|
||||
SPIRVShaderInputs& shaderInputs) {
|
||||
// Set the shader conversion configuration output variable information
|
||||
shaderConfig.shaderOutputs.clear();
|
||||
uint32_t soCnt = (uint32_t)shaderInputs.size();
|
||||
for (uint32_t soIdx = 0; soIdx < soCnt; soIdx++) {
|
||||
if (!shaderInputs[soIdx].isUsed) { continue; }
|
||||
|
||||
mvk::MSLShaderInterfaceVariable so;
|
||||
so.shaderVar.location = shaderInputs[soIdx].location;
|
||||
so.shaderVar.component = shaderInputs[soIdx].component;
|
||||
so.shaderVar.builtin = shaderInputs[soIdx].builtin;
|
||||
so.shaderVar.vecsize = shaderInputs[soIdx].vecWidth;
|
||||
|
||||
switch (getPixelFormats()->getFormatType(mvkFormatFromOutput(shaderInputs[soIdx]) ) ) {
|
||||
case kMVKFormatColorUInt8:
|
||||
so.shaderVar.format = MSL_SHADER_INPUT_FORMAT_UINT8;
|
||||
break;
|
||||
|
||||
case kMVKFormatColorUInt16:
|
||||
so.shaderVar.format = MSL_SHADER_INPUT_FORMAT_UINT16;
|
||||
break;
|
||||
|
||||
case kMVKFormatColorHalf:
|
||||
case kMVKFormatColorInt16:
|
||||
so.shaderVar.format = MSL_SHADER_INPUT_FORMAT_ANY16;
|
||||
break;
|
||||
|
||||
case kMVKFormatColorFloat:
|
||||
case kMVKFormatColorInt32:
|
||||
case kMVKFormatColorUInt32:
|
||||
so.shaderVar.format = MSL_SHADER_INPUT_FORMAT_ANY32;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
shaderConfig.shaderOutputs.push_back(so);
|
||||
}
|
||||
}
|
||||
|
||||
// Initializes the shader inputs in a shader conversion config from the previous stage output.
|
||||
void MVKGraphicsPipeline::addPrevStageOutputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig,
|
||||
SPIRVShaderOutputs& shaderOutputs) {
|
||||
@ -1746,29 +1847,29 @@ void MVKGraphicsPipeline::addPrevStageOutputToShaderConversionConfig(SPIRVToMSLC
|
||||
if (!shaderOutputs[siIdx].isUsed) { continue; }
|
||||
|
||||
mvk::MSLShaderInput si;
|
||||
si.shaderInput.location = shaderOutputs[siIdx].location;
|
||||
si.shaderInput.component = shaderOutputs[siIdx].component;
|
||||
si.shaderInput.builtin = shaderOutputs[siIdx].builtin;
|
||||
si.shaderInput.vecsize = shaderOutputs[siIdx].vecWidth;
|
||||
si.shaderVar.location = shaderOutputs[siIdx].location;
|
||||
si.shaderVar.component = shaderOutputs[siIdx].component;
|
||||
si.shaderVar.builtin = shaderOutputs[siIdx].builtin;
|
||||
si.shaderVar.vecsize = shaderOutputs[siIdx].vecWidth;
|
||||
|
||||
switch (getPixelFormats()->getFormatType(mvkFormatFromOutput(shaderOutputs[siIdx]) ) ) {
|
||||
case kMVKFormatColorUInt8:
|
||||
si.shaderInput.format = MSL_SHADER_INPUT_FORMAT_UINT8;
|
||||
si.shaderVar.format = MSL_SHADER_INPUT_FORMAT_UINT8;
|
||||
break;
|
||||
|
||||
case kMVKFormatColorUInt16:
|
||||
si.shaderInput.format = MSL_SHADER_INPUT_FORMAT_UINT16;
|
||||
si.shaderVar.format = MSL_SHADER_INPUT_FORMAT_UINT16;
|
||||
break;
|
||||
|
||||
case kMVKFormatColorHalf:
|
||||
case kMVKFormatColorInt16:
|
||||
si.shaderInput.format = MSL_SHADER_INPUT_FORMAT_ANY16;
|
||||
si.shaderVar.format = MSL_SHADER_INPUT_FORMAT_ANY16;
|
||||
break;
|
||||
|
||||
case kMVKFormatColorFloat:
|
||||
case kMVKFormatColorInt32:
|
||||
case kMVKFormatColorUInt32:
|
||||
si.shaderInput.format = MSL_SHADER_INPUT_FORMAT_ANY32;
|
||||
si.shaderVar.format = MSL_SHADER_INPUT_FORMAT_ANY32;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -2251,7 +2352,7 @@ namespace SPIRV_CROSS_NAMESPACE {
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive, MSLShaderInput& si) {
|
||||
void serialize(Archive & archive, MSLShaderInterfaceVariable& si) {
|
||||
archive(si.location,
|
||||
si.component,
|
||||
si.format,
|
||||
@ -2331,8 +2432,8 @@ namespace mvk {
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive, MSLShaderInput& si) {
|
||||
archive(si.shaderInput,
|
||||
void serialize(Archive & archive, MSLShaderInterfaceVariable& si) {
|
||||
archive(si.shaderVar,
|
||||
si.binding,
|
||||
si.outIsUsedByShader);
|
||||
}
|
||||
@ -2357,6 +2458,7 @@ namespace mvk {
|
||||
void serialize(Archive & archive, SPIRVToMSLConversionConfiguration& ctx) {
|
||||
archive(ctx.options,
|
||||
ctx.shaderInputs,
|
||||
ctx.shaderOutputs,
|
||||
ctx.resourceBindings,
|
||||
ctx.discreteDescriptorSets);
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ MVKMTLFunction MVKShaderModule::getMTLFunction(SPIRVToMSLConversionConfiguration
|
||||
_device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.shaderLibraryFromCache, startTime);
|
||||
} else {
|
||||
mvkLib->setEntryPointName(pShaderConfig->options.entryPointName);
|
||||
pShaderConfig->markAllInputsAndResourcesUsed();
|
||||
pShaderConfig->markAllInterfaceVarsAndResourcesUsed();
|
||||
}
|
||||
|
||||
return mvkLib ? mvkLib->getMTLFunction(pSpecializationInfo, this) : MVKMTLFunctionNull;
|
||||
|
@ -62,6 +62,7 @@ class MVKSmallVectorImpl
|
||||
Allocator alc;
|
||||
|
||||
public:
|
||||
using value_type = Type;
|
||||
class iterator
|
||||
{
|
||||
const MVKSmallVectorImpl *vector;
|
||||
@ -115,6 +116,7 @@ public:
|
||||
bool is_valid() const { return index < vector->alc.size(); }
|
||||
size_t get_position() const { return index; }
|
||||
};
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
|
||||
private:
|
||||
// this is the growth strategy -> adjust to your needs
|
||||
@ -293,6 +295,9 @@ public:
|
||||
iterator begin() const { return iterator( 0, *this ); }
|
||||
iterator end() const { return iterator( alc.num_elements_used, *this ); }
|
||||
|
||||
reverse_iterator rbegin() const { return reverse_iterator( end() ); }
|
||||
reverse_iterator rend() const { return reverse_iterator( begin() ); }
|
||||
|
||||
const MVKArrayRef<Type> contents() const { return MVKArrayRef<Type>(data(), size()); }
|
||||
MVKArrayRef<Type> contents() { return MVKArrayRef<Type>(data(), size()); }
|
||||
|
||||
@ -521,6 +526,7 @@ class MVKSmallVectorImpl<Type*, Allocator>
|
||||
Allocator alc;
|
||||
|
||||
public:
|
||||
using value_type = Type*;
|
||||
class iterator
|
||||
{
|
||||
MVKSmallVectorImpl *vector;
|
||||
@ -572,6 +578,7 @@ public:
|
||||
bool is_valid() const { return index < vector->alc.size(); }
|
||||
size_t get_position() const { return index; }
|
||||
};
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
|
||||
private:
|
||||
// this is the growth strategy -> adjust to your needs
|
||||
@ -728,6 +735,9 @@ public:
|
||||
iterator begin() { return iterator( 0, *this ); }
|
||||
iterator end() { return iterator( alc.num_elements_used, *this ); }
|
||||
|
||||
reverse_iterator rbegin() { return reverse_iterator( end() ); }
|
||||
reverse_iterator rend() { return reverse_iterator( rbegin() ); }
|
||||
|
||||
const MVKArrayRef<Type*> contents() const { return MVKArrayRef<Type*>(data(), size()); }
|
||||
MVKArrayRef<Type*> contents() { return MVKArrayRef<Type*>(data(), size()); }
|
||||
|
||||
|
@ -54,41 +54,42 @@ namespace mvk {
|
||||
};
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark SPIRVShaderOutputData
|
||||
#pragma mark SPIRVShaderInterfaceVariable
|
||||
|
||||
/**
|
||||
* Reflection data on a single output of a shader.
|
||||
* Reflection data on a single interface variable of a shader.
|
||||
* This contains the information needed to construct a
|
||||
* stage-input descriptor for the next stage of a pipeline.
|
||||
*/
|
||||
struct SPIRVShaderOutput {
|
||||
/** The type of the output. */
|
||||
struct SPIRVShaderInterfaceVariable {
|
||||
/** The type of the variable. */
|
||||
SPIRV_CROSS_NAMESPACE::SPIRType::BaseType baseType;
|
||||
|
||||
/** The vector size, if a vector. */
|
||||
uint32_t vecWidth;
|
||||
|
||||
/** The location number of the output. */
|
||||
/** The location number of the variable. */
|
||||
uint32_t location;
|
||||
|
||||
/** The component index of the output. */
|
||||
/** The component index of the variable. */
|
||||
uint32_t component;
|
||||
|
||||
/**
|
||||
* If this is the first member of a struct, this will contain the alignment
|
||||
* of the struct containing this output, otherwise this will be zero.
|
||||
* of the struct containing this variable, otherwise this will be zero.
|
||||
*/
|
||||
uint32_t firstStructMemberAlignment;
|
||||
|
||||
/** If this is a builtin, the kind of builtin this is. */
|
||||
spv::BuiltIn builtin;
|
||||
|
||||
/** Whether this is a per-patch or per-vertex output. Only meaningful for tessellation control shaders. */
|
||||
/** Whether this is a per-patch or per-vertex variable. Only meaningful for tessellation shaders. */
|
||||
bool perPatch;
|
||||
|
||||
/** Whether this output is actually used (populated) by the shader. */
|
||||
/** Whether this variable is actually used (read or written) by the shader. */
|
||||
bool isUsed;
|
||||
};
|
||||
typedef SPIRVShaderInterfaceVariable SPIRVShaderOutput;
|
||||
|
||||
|
||||
#pragma mark -
|
||||
@ -190,13 +191,13 @@ namespace mvk {
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Returns the size in bytes of the output. */
|
||||
static inline uint32_t getShaderOutputSize(const SPIRVShaderOutput& output) {
|
||||
if ( !output.isUsed ) { return 0; } // Unused outputs consume no buffer space.
|
||||
/** Returns the size in bytes of the interface variable. */
|
||||
static inline uint32_t getShaderInterfaceVariableSize(const SPIRVShaderInterfaceVariable& var) {
|
||||
if ( !var.isUsed ) { return 0; } // Unused variables consume no buffer space.
|
||||
|
||||
uint32_t vecWidth = output.vecWidth;
|
||||
uint32_t vecWidth = var.vecWidth;
|
||||
if (vecWidth == 3) { vecWidth = 4; } // Metal 3-vectors consume same as 4-vectors.
|
||||
switch (output.baseType) {
|
||||
switch (var.baseType) {
|
||||
case SPIRV_CROSS_NAMESPACE::SPIRType::SByte:
|
||||
case SPIRV_CROSS_NAMESPACE::SPIRType::UByte:
|
||||
return 1 * vecWidth;
|
||||
@ -211,29 +212,35 @@ namespace mvk {
|
||||
return 4 * vecWidth;
|
||||
}
|
||||
}
|
||||
static inline uint32_t getShaderOutputSize(const SPIRVShaderOutput& output) {
|
||||
return getShaderInterfaceVariableSize(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alignment of the shader output, which typically matches the size of the output,
|
||||
* but the first member of a nested output struct may inherit special alignment from the struct.
|
||||
* Returns the alignment of the shader interface variable, which typically matches the size of the variable,
|
||||
* but the first member of a nested struct may inherit special alignment from the struct.
|
||||
*/
|
||||
static inline uint32_t getShaderOutputAlignment(const SPIRVShaderOutput& output) {
|
||||
if(output.firstStructMemberAlignment && output.isUsed) {
|
||||
return output.firstStructMemberAlignment;
|
||||
static inline uint32_t getShaderInterfaceVariableAlignment(const SPIRVShaderInterfaceVariable& var) {
|
||||
if(var.firstStructMemberAlignment && var.isUsed) {
|
||||
return var.firstStructMemberAlignment;
|
||||
} else {
|
||||
return getShaderOutputSize(output);
|
||||
return getShaderOutputSize(var);
|
||||
}
|
||||
}
|
||||
static inline uint32_t getShaderOutputAlignment(const SPIRVShaderOutput& output) {
|
||||
return getShaderInterfaceVariableAlignment(output);
|
||||
}
|
||||
|
||||
auto addSat = [](uint32_t a, uint32_t b) { return a == uint32_t(-1) ? a : a + b; };
|
||||
|
||||
template<typename Vo>
|
||||
static inline uint32_t getShaderOutputStructMembers(const SPIRV_CROSS_NAMESPACE::CompilerReflection& reflect,
|
||||
Vo& outputs, SPIRVShaderOutput* pParentFirstMember,
|
||||
template<typename Vi>
|
||||
static inline uint32_t getShaderInterfaceStructMembers(const SPIRV_CROSS_NAMESPACE::CompilerReflection& reflect,
|
||||
Vi& vars, SPIRVShaderInterfaceVariable* pParentFirstMember,
|
||||
const SPIRV_CROSS_NAMESPACE::SPIRType* structType, spv::StorageClass storage,
|
||||
bool patch, uint32_t loc) {
|
||||
bool isUsed = true;
|
||||
auto biType = spv::BuiltInMax;
|
||||
SPIRVShaderOutput* pFirstMember = nullptr;
|
||||
SPIRVShaderInterfaceVariable* pFirstMember = nullptr;
|
||||
size_t mbrCnt = structType->member_types.size();
|
||||
for (uint32_t mbrIdx = 0; mbrIdx < mbrCnt; mbrIdx++) {
|
||||
// Each member may have a location decoration. If not, each member
|
||||
@ -252,12 +259,12 @@ namespace mvk {
|
||||
uint32_t elemCnt = (type->array.empty() ? 1 : type->array[0]) * type->columns;
|
||||
for (uint32_t elemIdx = 0; elemIdx < elemCnt; elemIdx++) {
|
||||
if (type->basetype == SPIRV_CROSS_NAMESPACE::SPIRType::Struct)
|
||||
loc = getShaderOutputStructMembers(reflect, outputs, pFirstMember, type, storage, patch, loc);
|
||||
loc = getShaderInterfaceStructMembers(reflect, vars, pFirstMember, type, storage, patch, loc);
|
||||
else {
|
||||
// The alignment of a structure is the same as the largest member of the structure.
|
||||
// Consequently, the first flattened member of a structure should align with structure itself.
|
||||
outputs.push_back({type->basetype, type->vecsize, loc, cmp, 0, biType, patch, isUsed});
|
||||
auto& currOutput = outputs.back();
|
||||
vars.push_back({type->basetype, type->vecsize, loc, cmp, 0, biType, patch, isUsed});
|
||||
auto& currOutput = vars.back();
|
||||
if ( !pFirstMember ) { pFirstMember = &currOutput; }
|
||||
pFirstMember->firstStructMemberAlignment = std::max(pFirstMember->firstStructMemberAlignment, getShaderOutputSize(currOutput));
|
||||
loc = addSat(loc, 1);
|
||||
@ -274,11 +281,18 @@ namespace mvk {
|
||||
|
||||
return loc;
|
||||
}
|
||||
template<typename Vo>
|
||||
static inline uint32_t getShaderOutputStructMembers(const SPIRV_CROSS_NAMESPACE::CompilerReflection& reflect,
|
||||
Vo& outputs, SPIRVShaderOutput* pParentFirstMember,
|
||||
const SPIRV_CROSS_NAMESPACE::SPIRType* structType, spv::StorageClass storage,
|
||||
bool patch, uint32_t loc) {
|
||||
return getShaderInterfaceStructMembers(reflect, outputs, pParentFirstMember, structType, storage, patch, loc);
|
||||
}
|
||||
|
||||
/** Given a shader in SPIR-V format, returns output reflection data. */
|
||||
template<typename Vs, typename Vo>
|
||||
static inline bool getShaderOutputs(const Vs& spirv, spv::ExecutionModel model, const std::string& entryName,
|
||||
Vo& outputs, std::string& errorLog) {
|
||||
/** Given a shader in SPIR-V format, returns interface reflection data. */
|
||||
template<typename Vs, typename Vi>
|
||||
static inline bool getShaderInterfaceVariables(const Vs& spirv, spv::StorageClass storage, spv::ExecutionModel model,
|
||||
const std::string& entryName, Vi& vars, std::string& errorLog) {
|
||||
#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
|
||||
try {
|
||||
#endif
|
||||
@ -291,11 +305,10 @@ namespace mvk {
|
||||
reflect.compile();
|
||||
reflect.update_active_builtins();
|
||||
|
||||
outputs.clear();
|
||||
vars.clear();
|
||||
|
||||
for (auto varID : reflect.get_active_interface_variables()) {
|
||||
spv::StorageClass storage = reflect.get_storage_class(varID);
|
||||
if (storage != spv::StorageClassOutput) { continue; }
|
||||
if (storage != reflect.get_storage_class(varID)) { continue; }
|
||||
|
||||
bool isUsed = true;
|
||||
const auto* type = &reflect.get_type(reflect.get_type_from_variable(varID).parent_type);
|
||||
@ -313,29 +326,33 @@ namespace mvk {
|
||||
if (reflect.has_decoration(varID, spv::DecorationComponent)) {
|
||||
cmp = reflect.get_decoration(varID, spv::DecorationComponent);
|
||||
}
|
||||
if (model == spv::ExecutionModelTessellationControl && !patch)
|
||||
// For tessellation shaders, peel away the initial array type. SPIRV-Cross adds the array back automatically.
|
||||
// Only some builtins will be arrayed here.
|
||||
if ((model == spv::ExecutionModelTessellationControl || (model == spv::ExecutionModelTessellationEvaluation && storage == spv::StorageClassInput)) && !patch &&
|
||||
(biType == spv::BuiltInMax || biType == spv::BuiltInPosition || biType == spv::BuiltInPointSize ||
|
||||
biType == spv::BuiltInClipDistance || biType == spv::BuiltInCullDistance))
|
||||
type = &reflect.get_type(type->parent_type);
|
||||
|
||||
uint32_t elemCnt = (type->array.empty() ? 1 : type->array[0]) * type->columns;
|
||||
for (uint32_t i = 0; i < elemCnt; i++) {
|
||||
if (type->basetype == SPIRV_CROSS_NAMESPACE::SPIRType::Struct) {
|
||||
SPIRVShaderOutput* pFirstMember = nullptr;
|
||||
loc = getShaderOutputStructMembers(reflect, outputs, pFirstMember, type, storage, patch, loc);
|
||||
SPIRVShaderInterfaceVariable* pFirstMember = nullptr;
|
||||
loc = getShaderInterfaceStructMembers(reflect, vars, pFirstMember, type, storage, patch, loc);
|
||||
} else {
|
||||
outputs.push_back({type->basetype, type->vecsize, loc, cmp, 0, biType, patch, isUsed});
|
||||
vars.push_back({type->basetype, type->vecsize, loc, cmp, 0, biType, patch, isUsed});
|
||||
loc = addSat(loc, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort outputs by ascending location.
|
||||
std::stable_sort(outputs.begin(), outputs.end(), [](const SPIRVShaderOutput& a, const SPIRVShaderOutput& b) {
|
||||
// Sort variables by ascending location.
|
||||
std::stable_sort(vars.begin(), vars.end(), [](const SPIRVShaderInterfaceVariable& a, const SPIRVShaderInterfaceVariable& b) {
|
||||
return a.location < b.location;
|
||||
});
|
||||
// Assign locations to outputs that don't have one.
|
||||
// Assign locations to variables that don't have one.
|
||||
uint32_t loc = -1;
|
||||
for (SPIRVShaderOutput& out : outputs) {
|
||||
if (out.location == uint32_t(-1)) { out.location = loc + 1; }
|
||||
loc = out.location;
|
||||
for (SPIRVShaderInterfaceVariable& var : vars) {
|
||||
if (var.location == uint32_t(-1)) { var.location = loc + 1; }
|
||||
loc = var.location;
|
||||
}
|
||||
return true;
|
||||
#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
|
||||
@ -345,6 +362,16 @@ namespace mvk {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
template<typename Vs, typename Vo>
|
||||
static inline bool getShaderOutputs(const Vs& spirv, spv::ExecutionModel model, const std::string& entryName,
|
||||
Vo& outputs, std::string& errorLog) {
|
||||
return getShaderInterfaceVariables(spirv, spv::StorageClassOutput, model, entryName, outputs, errorLog);
|
||||
}
|
||||
template<typename Vs, typename Vo>
|
||||
static inline bool getShaderInputs(const Vs& spirv, spv::ExecutionModel model, const std::string& entryName,
|
||||
Vo& outputs, std::string& errorLog) {
|
||||
return getShaderInterfaceVariables(spirv, spv::StorageClassInput, model, entryName, outputs, errorLog);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
@ -94,17 +94,17 @@ MVK_PUBLIC_SYMBOL SPIRVToMSLConversionOptions::SPIRVToMSLConversionOptions() {
|
||||
mslOptions.pad_fragment_output_components = true;
|
||||
}
|
||||
|
||||
MVK_PUBLIC_SYMBOL bool mvk::MSLShaderInput::matches(const mvk::MSLShaderInput& other) const {
|
||||
if (memcmp(&shaderInput, &other.shaderInput, sizeof(shaderInput)) != 0) { return false; }
|
||||
MVK_PUBLIC_SYMBOL bool mvk::MSLShaderInterfaceVariable::matches(const mvk::MSLShaderInterfaceVariable& other) const {
|
||||
if (memcmp(&shaderVar, &other.shaderVar, sizeof(shaderVar)) != 0) { return false; }
|
||||
if (binding != other.binding) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
MVK_PUBLIC_SYMBOL mvk::MSLShaderInput::MSLShaderInput() {
|
||||
// Explicitly set shaderInput to defaults over cleared memory to ensure all instances
|
||||
MVK_PUBLIC_SYMBOL mvk::MSLShaderInterfaceVariable::MSLShaderInterfaceVariable() {
|
||||
// Explicitly set shaderVar to defaults over cleared memory to ensure all instances
|
||||
// have exactly the same memory layout when using memory comparison in matches().
|
||||
memset(&shaderInput, 0, sizeof(shaderInput));
|
||||
shaderInput = SPIRV_CROSS_NAMESPACE::MSLShaderInput();
|
||||
memset(&shaderVar, 0, sizeof(shaderVar));
|
||||
shaderVar = SPIRV_CROSS_NAMESPACE::MSLShaderInterfaceVariable();
|
||||
}
|
||||
|
||||
// If requiresConstExprSampler is false, constExprSampler can be ignored
|
||||
@ -143,7 +143,21 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConversionConfiguration::stageSupportsVertexAtt
|
||||
// Check them all in case inactive VA's duplicate locations used by active VA's.
|
||||
MVK_PUBLIC_SYMBOL bool SPIRVToMSLConversionConfiguration::isShaderInputLocationUsed(uint32_t location) const {
|
||||
for (auto& si : shaderInputs) {
|
||||
if ((si.shaderInput.location == location) && si.outIsUsedByShader) { return true; }
|
||||
if ((si.shaderVar.location == location) && si.outIsUsedByShader) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MVK_PUBLIC_SYMBOL bool SPIRVToMSLConversionConfiguration::isShaderInputBuiltInUsed(spv::BuiltIn builtin) const {
|
||||
for (auto& si : shaderInputs) {
|
||||
if ((si.shaderVar.builtin == builtin) && si.outIsUsedByShader) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MVK_PUBLIC_SYMBOL bool SPIRVToMSLConversionConfiguration::isShaderOutputLocationUsed(uint32_t location) const {
|
||||
for (auto& so : shaderOutputs) {
|
||||
if ((so.shaderVar.location == location) && so.outIsUsedByShader) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -166,8 +180,9 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConversionConfiguration::isResourceUsed(Executi
|
||||
return false;
|
||||
}
|
||||
|
||||
MVK_PUBLIC_SYMBOL void SPIRVToMSLConversionConfiguration::markAllInputsAndResourcesUsed() {
|
||||
MVK_PUBLIC_SYMBOL void SPIRVToMSLConversionConfiguration::markAllInterfaceVarsAndResourcesUsed() {
|
||||
for (auto& si : shaderInputs) { si.outIsUsedByShader = true; }
|
||||
for (auto& so : shaderOutputs) { so.outIsUsedByShader = true; }
|
||||
for (auto& rb : resourceBindings) { rb.outIsUsedByShader = true; }
|
||||
}
|
||||
|
||||
@ -175,7 +190,7 @@ MVK_PUBLIC_SYMBOL void SPIRVToMSLConversionConfiguration::markAllInputsAndResour
|
||||
// and the resources can be spread across these shader stages. To improve cache hits when using
|
||||
// this function to find a cached shader for a particular shader stage, only consider the resources
|
||||
// that are used in that shader stage. By contrast, discreteDescriptorSet apply across all stages,
|
||||
// and shaderInputs are populated before each stage, so neither needs to be filtered by stage here.
|
||||
// and shaderInputs and shaderOutputs are populated before each stage, so neither needs to be filtered by stage here.
|
||||
MVK_PUBLIC_SYMBOL bool SPIRVToMSLConversionConfiguration::matches(const SPIRVToMSLConversionConfiguration& other) const {
|
||||
|
||||
if ( !options.matches(other.options) ) { return false; }
|
||||
@ -184,6 +199,10 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConversionConfiguration::matches(const SPIRVToM
|
||||
if (si.outIsUsedByShader && !containsMatching(other.shaderInputs, si)) { return false; }
|
||||
}
|
||||
|
||||
for (const auto& so : shaderOutputs) {
|
||||
if (so.outIsUsedByShader && !containsMatching(other.shaderOutputs, so)) { return false; }
|
||||
}
|
||||
|
||||
for (const auto& rb : resourceBindings) {
|
||||
if (rb.resourceBinding.stage == options.entryPointStage &&
|
||||
rb.outIsUsedByShader &&
|
||||
@ -212,6 +231,13 @@ MVK_PUBLIC_SYMBOL void SPIRVToMSLConversionConfiguration::alignWith(const SPIRVT
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& so : shaderOutputs) {
|
||||
so.outIsUsedByShader = false;
|
||||
for (auto& srcSO : srcContext.shaderOutputs) {
|
||||
if (so.matches(srcSO)) { so.outIsUsedByShader = srcSO.outIsUsedByShader; }
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& rb : resourceBindings) {
|
||||
rb.outIsUsedByShader = false;
|
||||
for (auto& srcRB : srcContext.resourceBindings) {
|
||||
@ -281,9 +307,13 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverter::convert(SPIRVToMSLConversionConfigur
|
||||
scOpts.vertex.flip_vert_y = shaderConfig.options.shouldFlipVertexY;
|
||||
pMSLCompiler->set_common_options(scOpts);
|
||||
|
||||
// Add shader inputs
|
||||
// Add shader inputs and outputs
|
||||
for (auto& si : shaderConfig.shaderInputs) {
|
||||
pMSLCompiler->add_msl_shader_input(si.shaderInput);
|
||||
pMSLCompiler->add_msl_shader_input(si.shaderVar);
|
||||
}
|
||||
|
||||
for (auto& so : shaderConfig.shaderOutputs) {
|
||||
pMSLCompiler->add_msl_shader_output(so.shaderVar);
|
||||
}
|
||||
|
||||
// Add resource bindings and hardcoded constexpr samplers
|
||||
@ -352,7 +382,18 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverter::convert(SPIRVToMSLConversionConfigur
|
||||
}
|
||||
|
||||
for (auto& ctxSI : shaderConfig.shaderInputs) {
|
||||
ctxSI.outIsUsedByShader = pMSLCompiler->is_msl_shader_input_used(ctxSI.shaderInput.location);
|
||||
if (ctxSI.shaderVar.builtin != spv::BuiltInMax) {
|
||||
ctxSI.outIsUsedByShader = pMSLCompiler->has_active_builtin(ctxSI.shaderVar.builtin, spv::StorageClassInput);
|
||||
} else {
|
||||
ctxSI.outIsUsedByShader = pMSLCompiler->is_msl_shader_input_used(ctxSI.shaderVar.location);
|
||||
}
|
||||
}
|
||||
for (auto& ctxSO : shaderConfig.shaderOutputs) {
|
||||
if (ctxSO.shaderVar.builtin != spv::BuiltInMax) {
|
||||
ctxSO.outIsUsedByShader = pMSLCompiler->has_active_builtin(ctxSO.shaderVar.builtin, spv::StorageClassOutput);
|
||||
} else {
|
||||
ctxSO.outIsUsedByShader = pMSLCompiler->is_msl_shader_output_used(ctxSO.shaderVar.location);
|
||||
}
|
||||
}
|
||||
for (auto& ctxRB : shaderConfig.resourceBindings) {
|
||||
if (ctxRB.resourceBinding.stage == shaderConfig.options.entryPointStage) {
|
||||
|
@ -61,30 +61,30 @@ namespace mvk {
|
||||
} SPIRVToMSLConversionOptions;
|
||||
|
||||
/**
|
||||
* Defines MSL characteristics of a vertex attribute at a particular location.
|
||||
* Defines MSL characteristics of a shader interface variable at a particular location.
|
||||
*
|
||||
* The outIsUsedByShader flag is set to true during conversion of SPIR-V to MSL if the shader
|
||||
* makes use of this vertex attribute. This allows a pipeline to be optimized, and for two
|
||||
* makes use of this interface variable. This allows a pipeline to be optimized, and for two
|
||||
* shader conversion configurations to be compared only against the attributes that are
|
||||
* actually used by the shader.
|
||||
*
|
||||
* THIS STRUCT IS STREAMED OUT AS PART OF THE PIPELINE CACHE.
|
||||
* CHANGES TO THIS STRUCT SHOULD BE CAPTURED IN THE STREAMING LOGIC OF THE PIPELINE CACHE.
|
||||
*/
|
||||
typedef struct MSLShaderInput {
|
||||
SPIRV_CROSS_NAMESPACE::MSLShaderInput shaderInput;
|
||||
typedef struct MSLShaderInterfaceVariable {
|
||||
SPIRV_CROSS_NAMESPACE::MSLShaderInterfaceVariable shaderVar;
|
||||
uint32_t binding = 0;
|
||||
bool outIsUsedByShader = false;
|
||||
|
||||
/**
|
||||
* Returns whether the specified vertex attribute match this one.
|
||||
* Returns whether the specified interface variable match this one.
|
||||
* It does if all corresponding elements except outIsUsedByShader are equal.
|
||||
*/
|
||||
bool matches(const MSLShaderInput& other) const;
|
||||
bool matches(const MSLShaderInterfaceVariable& other) const;
|
||||
|
||||
MSLShaderInput();
|
||||
MSLShaderInterfaceVariable();
|
||||
|
||||
} MSLShaderInput;
|
||||
} MSLShaderInterfaceVariable, MSLShaderInput;
|
||||
|
||||
/**
|
||||
* Matches the binding index of a MSL resource for a binding within a descriptor set.
|
||||
@ -146,7 +146,8 @@ namespace mvk {
|
||||
*/
|
||||
typedef struct SPIRVToMSLConversionConfiguration {
|
||||
SPIRVToMSLConversionOptions options;
|
||||
std::vector<MSLShaderInput> shaderInputs;
|
||||
std::vector<MSLShaderInterfaceVariable> shaderInputs;
|
||||
std::vector<MSLShaderInterfaceVariable> shaderOutputs;
|
||||
std::vector<MSLResourceBinding> resourceBindings;
|
||||
std::vector<uint32_t> discreteDescriptorSets;
|
||||
std::vector<DescriptorBinding> dynamicBufferDescriptors;
|
||||
@ -157,17 +158,23 @@ namespace mvk {
|
||||
/** Returns whether the shader input variable at the specified location is used by the shader. */
|
||||
bool isShaderInputLocationUsed(uint32_t location) const;
|
||||
|
||||
/** Returns whether the specified built-in shader input variable is used by the shader. */
|
||||
bool isShaderInputBuiltInUsed(spv::BuiltIn builtin) const;
|
||||
|
||||
/** Returns the number of shader input variables bound to the specified Vulkan buffer binding, and used by the shader. */
|
||||
uint32_t countShaderInputsAt(uint32_t binding) const;
|
||||
|
||||
/** Returns whether the shader output variable at the specified location is used by the shader. */
|
||||
bool isShaderOutputLocationUsed(uint32_t location) const;
|
||||
|
||||
/** Returns whether the vertex buffer at the specified Vulkan binding is used by the shader. */
|
||||
bool isVertexBufferUsed(uint32_t binding) const { return countShaderInputsAt(binding) > 0; }
|
||||
|
||||
/** Returns whether the resource at the specified descriptor set binding is used by the shader. */
|
||||
bool isResourceUsed(spv::ExecutionModel stage, uint32_t descSet, uint32_t binding) const;
|
||||
|
||||
/** Marks all input variables and resources as being used by the shader. */
|
||||
void markAllInputsAndResourcesUsed();
|
||||
/** Marks all interface variables and resources as being used by the shader. */
|
||||
void markAllInterfaceVarsAndResourcesUsed();
|
||||
|
||||
/**
|
||||
* Returns whether this configuration matches the other configuration. It does if
|
||||
|
Loading…
x
Reference in New Issue
Block a user