| 70 | } |
| 71 | |
| 72 | spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) { |
| 73 | const auto entry_point_id = inst->GetOperandAs<uint32_t>(1); |
| 74 | auto entry_point = _.FindDef(entry_point_id); |
| 75 | if (!entry_point || spv::Op::OpFunction != entry_point->opcode()) { |
| 76 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 77 | << "OpEntryPoint Entry Point <id> " << _.getIdName(entry_point_id) |
| 78 | << " is not a function."; |
| 79 | } |
| 80 | |
| 81 | // Only check the shader execution models |
| 82 | const spv::ExecutionModel execution_model = |
| 83 | inst->GetOperandAs<spv::ExecutionModel>(0); |
| 84 | if (execution_model != spv::ExecutionModel::Kernel) { |
| 85 | const auto entry_point_type_id = entry_point->GetOperandAs<uint32_t>(3); |
| 86 | const auto entry_point_type = _.FindDef(entry_point_type_id); |
| 87 | if (!entry_point_type || 3 != entry_point_type->words().size()) { |
| 88 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 89 | << _.VkErrorID(4633) << "OpEntryPoint Entry Point <id> " |
| 90 | << _.getIdName(entry_point_id) |
| 91 | << "s function parameter count is not zero."; |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | auto return_type = _.FindDef(entry_point->type_id()); |
| 96 | if (!return_type || spv::Op::OpTypeVoid != return_type->opcode()) { |
| 97 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 98 | << _.VkErrorID(4633) << "OpEntryPoint Entry Point <id> " |
| 99 | << _.getIdName(entry_point_id) |
| 100 | << "s function return type is not void."; |
| 101 | } |
| 102 | |
| 103 | const auto* execution_modes = _.GetExecutionModes(entry_point_id); |
| 104 | auto has_mode = [&execution_modes](spv::ExecutionMode mode) { |
| 105 | return execution_modes && execution_modes->count(mode); |
| 106 | }; |
| 107 | |
| 108 | if (_.HasCapability(spv::Capability::Shader)) { |
| 109 | switch (execution_model) { |
| 110 | case spv::ExecutionModel::Fragment: |
| 111 | if (has_mode(spv::ExecutionMode::OriginUpperLeft) && |
| 112 | has_mode(spv::ExecutionMode::OriginLowerLeft)) { |
| 113 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 114 | << "Fragment execution model entry points can only specify " |
| 115 | "one of OriginUpperLeft or OriginLowerLeft execution " |
| 116 | "modes."; |
| 117 | } |
| 118 | if (!has_mode(spv::ExecutionMode::OriginUpperLeft) && |
| 119 | !has_mode(spv::ExecutionMode::OriginLowerLeft)) { |
| 120 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 121 | << "Fragment execution model entry points require either an " |
| 122 | "OriginUpperLeft or OriginLowerLeft execution mode."; |
| 123 | } |
| 124 | if (execution_modes && |
| 125 | 1 < std::count_if(execution_modes->begin(), execution_modes->end(), |
| 126 | [](const spv::ExecutionMode& mode) { |
| 127 | switch (mode) { |
| 128 | case spv::ExecutionMode::DepthGreater: |
| 129 | case spv::ExecutionMode::DepthLess: |
no test coverage detected