11// Copyright (c) 2018 Google LLC.
22// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
33// reserved.
4+ // Copyright (C) 2026 Qualcomm Technologies, Inc.
45//
56// Licensed under the Apache License, Version 2.0 (the "License");
67// you may not use this file except in compliance with the License.
@@ -123,7 +124,7 @@ typedef enum VUIDError_ {
123124 VUIDErrorMax,
124125} VUIDError;
125126
126- const static uint32_t NumVUIDBuiltins = 42 ;
127+ const static uint32_t NumVUIDBuiltins = 45 ;
127128
128129typedef struct {
129130 spv::BuiltIn builtIn;
@@ -176,7 +177,9 @@ std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
176177 {spv::BuiltIn::PrimitiveTriangleIndicesEXT, {7053 , 7055 , 7056 }},
177178 {spv::BuiltIn::CullPrimitiveEXT, {7034 , 7035 , 7036 }},
178179 {spv::BuiltIn::HitTriangleVertexPositionsKHR, {8747 , 8748 , 8749 }},
179-
180+ {spv::BuiltIn::TileOffsetQCOM, {10626 , 10627 , 10628 }},
181+ {spv::BuiltIn::TileDimensionQCOM, {10629 , 10630 , 10631 }},
182+ {spv::BuiltIn::TileApronSizeQCOM, {10632 , 10633 , 10634 }},
180183 // clang-format on
181184}};
182185
@@ -380,6 +383,9 @@ class BuiltInsValidator {
380383 spv_result_t ValidateMeshShadingEXTBuiltinsAtDefinition (
381384 const Decoration& decoration, const Instruction& inst);
382385
386+ spv_result_t ValidateTileQCOMBuiltinAtDefinition (const Decoration& decoration,
387+ const Instruction& inst);
388+
383389 // Used as a common method for validating MeshEXT builtins
384390 spv_result_t ValidateMeshBuiltinInterfaceRules (
385391 const Decoration& decoration, const Instruction& inst,
@@ -587,6 +593,11 @@ class BuiltInsValidator {
587593 const Instruction& referenced_inst,
588594 const Instruction& referenced_from_inst);
589595
596+ spv_result_t ValidateTileQCOMBuiltinAtReference (
597+ const Decoration& decoration, const Instruction& built_in_inst,
598+ const Instruction& referenced_inst,
599+ const Instruction& referenced_from_inst);
600+
590601 // Validates that |built_in_inst| is not (even indirectly) referenced from
591602 // within a function which can be called with |execution_model|.
592603 //
@@ -623,6 +634,10 @@ class BuiltInsValidator {
623634 const Decoration& decoration, const Instruction& inst,
624635 uint32_t num_components,
625636 const std::function<spv_result_t (const std::string& message)>& diag);
637+ spv_result_t ValidateU32Vec (
638+ const Decoration& decoration, const Instruction& inst,
639+ uint32_t num_components,
640+ const std::function<spv_result_t (const std::string& message)>& diag);
626641 spv_result_t ValidateI32Arr (
627642 const Decoration& decoration, const Instruction& inst,
628643 const std::function<spv_result_t (const std::string& message)>& diag);
@@ -789,6 +804,9 @@ class BuiltInsValidator {
789804 // Execution models with which the current function can be called.
790805 std::set<spv::ExecutionModel> execution_models_;
791806
807+ // Execution modes with which the current function can be called.
808+ std::set<spv::ExecutionMode> execution_modes_;
809+
792810 // For Builtin that can only be declared once in an entry point, keep track if
793811 // the entry point has it already
794812 std::set<uint32_t > cull_primitive_entry_points_;
@@ -801,13 +819,17 @@ void BuiltInsValidator::Update(const Instruction& inst) {
801819 assert (function_id_ == 0 );
802820 function_id_ = inst.id ();
803821 execution_models_.clear ();
822+ execution_modes_.clear ();
804823 entry_points_ = &_.FunctionEntryPoints (function_id_);
805824 // Collect execution models from all entry points from which the current
806825 // function can be called.
807826 for (const uint32_t entry_point : *entry_points_) {
808827 if (const auto * models = _.GetExecutionModels (entry_point)) {
809828 execution_models_.insert (models->begin (), models->end ());
810829 }
830+ if (const auto * modes = _.GetExecutionModes (entry_point)) {
831+ execution_modes_.insert (modes->begin (), modes->end ());
832+ }
811833 }
812834 }
813835
@@ -817,6 +839,7 @@ void BuiltInsValidator::Update(const Instruction& inst) {
817839 function_id_ = 0 ;
818840 entry_points_ = &no_entry_points;
819841 execution_models_.clear ();
842+ execution_modes_.clear ();
820843 }
821844}
822845
@@ -1103,6 +1126,40 @@ spv_result_t BuiltInsValidator::ValidateI32Vec(
11031126 return SPV_SUCCESS ;
11041127}
11051128
1129+ spv_result_t BuiltInsValidator::ValidateU32Vec (
1130+ const Decoration& decoration, const Instruction& inst,
1131+ uint32_t num_components,
1132+ const std::function<spv_result_t (const std::string& message)>& diag) {
1133+ uint32_t underlying_type = 0 ;
1134+ if (spv_result_t error =
1135+ GetUnderlyingType (_, decoration, inst, &underlying_type)) {
1136+ return error;
1137+ }
1138+
1139+ if (!_.IsUnsignedIntVectorType (underlying_type)) {
1140+ return diag (GetDefinitionDesc (decoration, inst) +
1141+ " is not an unsigned int vector." );
1142+ }
1143+
1144+ const uint32_t actual = _.GetDimension (underlying_type);
1145+ if (actual != num_components) {
1146+ std::ostringstream ss;
1147+ ss << GetDefinitionDesc (decoration, inst) << " has " << actual
1148+ << " components." ;
1149+ return diag (ss.str ());
1150+ }
1151+
1152+ const uint32_t bit_width = _.GetBitWidth (underlying_type);
1153+ if (bit_width != 32 ) {
1154+ std::ostringstream ss;
1155+ ss << GetDefinitionDesc (decoration, inst)
1156+ << " has components with bit width " << bit_width << " ." ;
1157+ return diag (ss.str ());
1158+ }
1159+
1160+ return SPV_SUCCESS ;
1161+ }
1162+
11061163spv_result_t BuiltInsValidator::ValidateArrayedI32Vec (
11071164 const Decoration& decoration, const Instruction& inst,
11081165 uint32_t num_components,
@@ -3792,6 +3849,8 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference(
37923849 const Instruction& referenced_inst,
37933850 const Instruction& referenced_from_inst) {
37943851 if (spvIsVulkanEnv (_.context ()->target_env )) {
3852+ const spv::StorageClass storage_class =
3853+ GetStorageClass (referenced_from_inst);
37953854 for (const spv::ExecutionModel execution_model : execution_models_) {
37963855 if (execution_model != spv::ExecutionModel::GLCompute &&
37973856 execution_model != spv::ExecutionModel::TaskNV &&
@@ -3810,6 +3869,19 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference(
38103869 referenced_from_inst, execution_model);
38113870 }
38123871 }
3872+ if (execution_modes_.count (spv::ExecutionMode::TileShadingRateQCOM) &&
3873+ storage_class != spv::StorageClass::Max &&
3874+ storage_class != spv::StorageClass::Input) {
3875+ return _.diag (SPV_ERROR_INVALID_DATA , &referenced_from_inst)
3876+ << _.VkErrorID (10635 )
3877+ << spvLogStringForEnv (_.context ()->target_env )
3878+ << " spec allows BuiltIn WorkgroupSize to be only used for "
3879+ " variables with Input storage class when "
3880+ " TileShadingRateQCOM Execution Mode is used. "
3881+ << GetReferenceDesc (decoration, built_in_inst, referenced_inst,
3882+ referenced_from_inst)
3883+ << " " << GetStorageClassDesc (referenced_from_inst);
3884+ }
38133885 }
38143886
38153887 if (function_id_ == 0 ) {
@@ -4905,6 +4977,76 @@ spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference(
49054977 return SPV_SUCCESS ;
49064978}
49074979
4980+ spv_result_t BuiltInsValidator::ValidateTileQCOMBuiltinAtDefinition (
4981+ const Decoration& decoration, const Instruction& inst) {
4982+ const spv::BuiltIn builtin = decoration.builtin ();
4983+ const uint32_t num_components =
4984+ (builtin == spv::BuiltIn::TileDimensionQCOM) ? 3 : 2 ;
4985+ if (spv_result_t error = ValidateU32Vec (
4986+ decoration, inst, num_components,
4987+ [this , &inst, builtin,
4988+ num_components](const std::string& msg) -> spv_result_t {
4989+ uint32_t vuid = GetVUIDForBuiltin (builtin, VUIDErrorType);
4990+ return _.diag (SPV_ERROR_INVALID_DATA , &inst)
4991+ << _.VkErrorID (vuid)
4992+ << " According to the Vulkan spec BuiltIn "
4993+ << _.grammar ().lookupOperandName (
4994+ SPV_OPERAND_TYPE_BUILT_IN ,
4995+ static_cast <uint32_t >(builtin))
4996+ << " variable must be a " << num_components
4997+ << " -component 32-bit unsigned int vector. " << msg;
4998+ })) {
4999+ return error;
5000+ }
5001+
5002+ return ValidateTileQCOMBuiltinAtReference (decoration, inst, inst, inst);
5003+ }
5004+
5005+ spv_result_t BuiltInsValidator::ValidateTileQCOMBuiltinAtReference (
5006+ const Decoration& decoration, const Instruction& built_in_inst,
5007+ const Instruction& referenced_inst,
5008+ const Instruction& referenced_from_inst) {
5009+ if (spvIsVulkanEnv (_.context ()->target_env )) {
5010+ const spv::BuiltIn builtin = decoration.builtin ();
5011+ const spv::StorageClass sc = GetStorageClass (referenced_from_inst);
5012+ if (sc != spv::StorageClass::Max && sc != spv::StorageClass::Input) {
5013+ uint32_t vuid = GetVUIDForBuiltin (builtin, VUIDErrorStorageClass);
5014+ return _.diag (SPV_ERROR_INVALID_DATA , &referenced_from_inst)
5015+ << _.VkErrorID (vuid) << " Vulkan spec allows BuiltIn "
5016+ << _.grammar ().lookupOperandName (SPV_OPERAND_TYPE_BUILT_IN ,
5017+ static_cast <uint32_t >(builtin))
5018+ << " to be only used for variables with Input storage class. "
5019+ << GetReferenceDesc (decoration, built_in_inst, referenced_inst,
5020+ referenced_from_inst)
5021+ << " " << GetStorageClassDesc (referenced_from_inst);
5022+ }
5023+
5024+ for (const spv::ExecutionModel model : execution_models_) {
5025+ if (model != spv::ExecutionModel::Fragment &&
5026+ model != spv::ExecutionModel::GLCompute) {
5027+ uint32_t vuid = GetVUIDForBuiltin (builtin, VUIDErrorExecutionModel);
5028+ return _.diag (SPV_ERROR_INVALID_DATA , &referenced_from_inst)
5029+ << _.VkErrorID (vuid) << " Vulkan spec allows BuiltIn "
5030+ << _.grammar ().lookupOperandName (SPV_OPERAND_TYPE_BUILT_IN ,
5031+ static_cast <uint32_t >(builtin))
5032+ << " to be used only with Fragment or GLCompute execution "
5033+ " model. "
5034+ << GetReferenceDesc (decoration, built_in_inst, referenced_inst,
5035+ referenced_from_inst, model);
5036+ }
5037+ }
5038+ }
5039+
5040+ if (function_id_ == 0 ) {
5041+ id_to_at_reference_checks_[referenced_from_inst.id ()].push_back (
5042+ std::bind (&BuiltInsValidator::ValidateTileQCOMBuiltinAtReference, this ,
5043+ decoration, built_in_inst, referenced_from_inst,
5044+ std::placeholders::_1));
5045+ }
5046+
5047+ return SPV_SUCCESS ;
5048+ }
5049+
49085050spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition (
49095051 const Decoration& decoration, const Instruction& inst) {
49105052 const spv::BuiltIn label = decoration.builtin ();
@@ -5095,6 +5237,11 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinitionVulkan(
50955237 case spv::BuiltIn::ResourceHeapEXT: {
50965238 return ValidateDescriptorHeapAtDefinition (decoration, inst);
50975239 }
5240+ case spv::BuiltIn::TileOffsetQCOM:
5241+ case spv::BuiltIn::TileDimensionQCOM:
5242+ case spv::BuiltIn::TileApronSizeQCOM: {
5243+ return ValidateTileQCOMBuiltinAtDefinition (decoration, inst);
5244+ }
50985245 default :
50995246 // No validation rules (for the moment).
51005247 break ;
0 commit comments