validate_ray_tracing_reorder.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. // Copyright (c) 2022 The Khronos Group Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Validates ray tracing instructions from SPV_NV_shader_execution_reorder
  15. #include "source/opcode.h"
  16. #include "source/val/instruction.h"
  17. #include "source/val/validate.h"
  18. #include "source/val/validation_state.h"
  19. #include <limits>
  20. namespace spvtools {
  21. namespace val {
  22. static const uint32_t KRayParamInvalidId = std::numeric_limits<uint32_t>::max();
  23. uint32_t GetArrayLength(ValidationState_t& _, const Instruction* array_type) {
  24. assert(array_type->opcode() == spv::Op::OpTypeArray);
  25. uint32_t const_int_id = array_type->GetOperandAs<uint32_t>(2U);
  26. Instruction* array_length_inst = _.FindDef(const_int_id);
  27. uint32_t array_length = 0;
  28. if (array_length_inst->opcode() == spv::Op::OpConstant) {
  29. array_length = array_length_inst->GetOperandAs<uint32_t>(2);
  30. }
  31. return array_length;
  32. }
  33. spv_result_t ValidateHitObjectPointer(ValidationState_t& _,
  34. const Instruction* inst,
  35. uint32_t hit_object_index) {
  36. const uint32_t hit_object_id = inst->GetOperandAs<uint32_t>(hit_object_index);
  37. auto variable = _.FindDef(hit_object_id);
  38. const auto var_opcode = variable->opcode();
  39. if (!variable || (var_opcode != spv::Op::OpVariable &&
  40. var_opcode != spv::Op::OpFunctionParameter &&
  41. var_opcode != spv::Op::OpAccessChain)) {
  42. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  43. << "Hit Object must be a memory object declaration";
  44. }
  45. auto pointer = _.FindDef(variable->GetOperandAs<uint32_t>(0));
  46. if (!pointer || pointer->opcode() != spv::Op::OpTypePointer) {
  47. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  48. << "Hit Object must be a pointer";
  49. }
  50. auto type = _.FindDef(pointer->GetOperandAs<uint32_t>(2));
  51. if (!type || type->opcode() != spv::Op::OpTypeHitObjectNV) {
  52. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  53. << "Type must be OpTypeHitObjectNV";
  54. }
  55. return SPV_SUCCESS;
  56. }
  57. spv_result_t ValidateHitObjectInstructionCommonParameters(
  58. ValidationState_t& _, const Instruction* inst,
  59. uint32_t acceleration_struct_index, uint32_t instance_id_index,
  60. uint32_t primtive_id_index, uint32_t geometry_index,
  61. uint32_t ray_flags_index, uint32_t cull_mask_index, uint32_t hit_kind_index,
  62. uint32_t sbt_index, uint32_t sbt_offset_index, uint32_t sbt_stride_index,
  63. uint32_t sbt_record_offset_index, uint32_t sbt_record_stride_index,
  64. uint32_t miss_index, uint32_t ray_origin_index, uint32_t ray_tmin_index,
  65. uint32_t ray_direction_index, uint32_t ray_tmax_index,
  66. uint32_t payload_index, uint32_t hit_object_attr_index) {
  67. auto isValidId = [](uint32_t spvid) { return spvid < KRayParamInvalidId; };
  68. if (isValidId(acceleration_struct_index) &&
  69. _.GetIdOpcode(_.GetOperandTypeId(inst, acceleration_struct_index)) !=
  70. spv::Op::OpTypeAccelerationStructureKHR) {
  71. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  72. << "Expected Acceleration Structure to be of type "
  73. "OpTypeAccelerationStructureKHR";
  74. }
  75. if (isValidId(instance_id_index)) {
  76. const uint32_t instance_id = _.GetOperandTypeId(inst, instance_id_index);
  77. if (!_.IsIntScalarType(instance_id) || _.GetBitWidth(instance_id) != 32) {
  78. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  79. << "Instance Id must be a 32-bit int scalar";
  80. }
  81. }
  82. if (isValidId(primtive_id_index)) {
  83. const uint32_t primitive_id = _.GetOperandTypeId(inst, primtive_id_index);
  84. if (!_.IsIntScalarType(primitive_id) || _.GetBitWidth(primitive_id) != 32) {
  85. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  86. << "Primitive Id must be a 32-bit int scalar";
  87. }
  88. }
  89. if (isValidId(geometry_index)) {
  90. const uint32_t geometry_index_id = _.GetOperandTypeId(inst, geometry_index);
  91. if (!_.IsIntScalarType(geometry_index_id) ||
  92. _.GetBitWidth(geometry_index_id) != 32) {
  93. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  94. << "Geometry Index must be a 32-bit int scalar";
  95. }
  96. }
  97. if (isValidId(miss_index)) {
  98. const uint32_t miss_index_id = _.GetOperandTypeId(inst, miss_index);
  99. if (!_.IsUnsignedIntScalarType(miss_index_id) ||
  100. _.GetBitWidth(miss_index_id) != 32) {
  101. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  102. << "Miss Index must be a 32-bit int scalar";
  103. }
  104. }
  105. if (isValidId(cull_mask_index)) {
  106. const uint32_t cull_mask_id = _.GetOperandTypeId(inst, cull_mask_index);
  107. if (!_.IsUnsignedIntScalarType(cull_mask_id) ||
  108. _.GetBitWidth(cull_mask_id) != 32) {
  109. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  110. << "Cull mask must be a 32-bit int scalar";
  111. }
  112. }
  113. if (isValidId(sbt_index)) {
  114. const uint32_t sbt_index_id = _.GetOperandTypeId(inst, sbt_index);
  115. if (!_.IsUnsignedIntScalarType(sbt_index_id) ||
  116. _.GetBitWidth(sbt_index_id) != 32) {
  117. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  118. << "SBT Index must be a 32-bit unsigned int scalar";
  119. }
  120. }
  121. if (isValidId(sbt_offset_index)) {
  122. const uint32_t sbt_offset_id = _.GetOperandTypeId(inst, sbt_offset_index);
  123. if (!_.IsUnsignedIntScalarType(sbt_offset_id) ||
  124. _.GetBitWidth(sbt_offset_id) != 32) {
  125. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  126. << "SBT Offset must be a 32-bit unsigned int scalar";
  127. }
  128. }
  129. if (isValidId(sbt_stride_index)) {
  130. const uint32_t sbt_stride_index_id =
  131. _.GetOperandTypeId(inst, sbt_stride_index);
  132. if (!_.IsUnsignedIntScalarType(sbt_stride_index_id) ||
  133. _.GetBitWidth(sbt_stride_index_id) != 32) {
  134. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  135. << "SBT Stride must be a 32-bit unsigned int scalar";
  136. }
  137. }
  138. if (isValidId(sbt_record_offset_index)) {
  139. const uint32_t sbt_record_offset_index_id =
  140. _.GetOperandTypeId(inst, sbt_record_offset_index);
  141. if (!_.IsUnsignedIntScalarType(sbt_record_offset_index_id) ||
  142. _.GetBitWidth(sbt_record_offset_index_id) != 32) {
  143. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  144. << "SBT record offset must be a 32-bit unsigned int scalar";
  145. }
  146. }
  147. if (isValidId(sbt_record_stride_index)) {
  148. const uint32_t sbt_record_stride_index_id =
  149. _.GetOperandTypeId(inst, sbt_record_stride_index);
  150. if (!_.IsUnsignedIntScalarType(sbt_record_stride_index_id) ||
  151. _.GetBitWidth(sbt_record_stride_index_id) != 32) {
  152. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  153. << "SBT record stride must be a 32-bit unsigned int scalar";
  154. }
  155. }
  156. if (isValidId(ray_origin_index)) {
  157. const uint32_t ray_origin_id = _.GetOperandTypeId(inst, ray_origin_index);
  158. if (!_.IsFloatVectorType(ray_origin_id) ||
  159. _.GetDimension(ray_origin_id) != 3 ||
  160. _.GetBitWidth(ray_origin_id) != 32) {
  161. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  162. << "Ray Origin must be a 32-bit float 3-component vector";
  163. }
  164. }
  165. if (isValidId(ray_tmin_index)) {
  166. const uint32_t ray_tmin_id = _.GetOperandTypeId(inst, ray_tmin_index);
  167. if (!_.IsFloatScalarType(ray_tmin_id) || _.GetBitWidth(ray_tmin_id) != 32) {
  168. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  169. << "Ray TMin must be a 32-bit float scalar";
  170. }
  171. }
  172. if (isValidId(ray_direction_index)) {
  173. const uint32_t ray_direction_id =
  174. _.GetOperandTypeId(inst, ray_direction_index);
  175. if (!_.IsFloatVectorType(ray_direction_id) ||
  176. _.GetDimension(ray_direction_id) != 3 ||
  177. _.GetBitWidth(ray_direction_id) != 32) {
  178. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  179. << "Ray Direction must be a 32-bit float 3-component vector";
  180. }
  181. }
  182. if (isValidId(ray_tmax_index)) {
  183. const uint32_t ray_tmax_id = _.GetOperandTypeId(inst, ray_tmax_index);
  184. if (!_.IsFloatScalarType(ray_tmax_id) || _.GetBitWidth(ray_tmax_id) != 32) {
  185. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  186. << "Ray TMax must be a 32-bit float scalar";
  187. }
  188. }
  189. if (isValidId(ray_flags_index)) {
  190. const uint32_t ray_flags_id = _.GetOperandTypeId(inst, ray_flags_index);
  191. if (!_.IsIntScalarType(ray_flags_id) || _.GetBitWidth(ray_flags_id) != 32) {
  192. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  193. << "Ray Flags must be a 32-bit int scalar";
  194. }
  195. }
  196. if (isValidId(payload_index)) {
  197. const uint32_t payload_id = inst->GetOperandAs<uint32_t>(payload_index);
  198. auto variable = _.FindDef(payload_id);
  199. const auto var_opcode = variable->opcode();
  200. if (!variable || var_opcode != spv::Op::OpVariable ||
  201. (variable->GetOperandAs<spv::StorageClass>(2) !=
  202. spv::StorageClass::RayPayloadKHR &&
  203. variable->GetOperandAs<spv::StorageClass>(2) !=
  204. spv::StorageClass::IncomingRayPayloadKHR)) {
  205. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  206. << "payload must be a OpVariable of storage "
  207. "class RayPayloadKHR or IncomingRayPayloadKHR";
  208. }
  209. }
  210. if (isValidId(hit_kind_index)) {
  211. const uint32_t hit_kind_id = _.GetOperandTypeId(inst, hit_kind_index);
  212. if (!_.IsUnsignedIntScalarType(hit_kind_id) ||
  213. _.GetBitWidth(hit_kind_id) != 32) {
  214. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  215. << "Hit Kind must be a 32-bit unsigned int scalar";
  216. }
  217. }
  218. if (isValidId(hit_object_attr_index)) {
  219. const uint32_t hit_object_attr_id =
  220. inst->GetOperandAs<uint32_t>(hit_object_attr_index);
  221. auto variable = _.FindDef(hit_object_attr_id);
  222. const auto var_opcode = variable->opcode();
  223. if (!variable || var_opcode != spv::Op::OpVariable ||
  224. (variable->GetOperandAs<spv::StorageClass>(2)) !=
  225. spv::StorageClass::HitObjectAttributeNV) {
  226. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  227. << "Hit Object Attributes id must be a OpVariable of storage "
  228. "class HitObjectAttributeNV";
  229. }
  230. }
  231. return SPV_SUCCESS;
  232. }
  233. spv_result_t RayReorderNVPass(ValidationState_t& _, const Instruction* inst) {
  234. const spv::Op opcode = inst->opcode();
  235. const uint32_t result_type = inst->type_id();
  236. auto RegisterOpcodeForValidModel = [](ValidationState_t& vs,
  237. const Instruction* rtinst) {
  238. std::string opcode_name = spvOpcodeString(rtinst->opcode());
  239. vs.function(rtinst->function()->id())
  240. ->RegisterExecutionModelLimitation(
  241. [opcode_name](spv::ExecutionModel model, std::string* message) {
  242. if (model != spv::ExecutionModel::RayGenerationKHR &&
  243. model != spv::ExecutionModel::ClosestHitKHR &&
  244. model != spv::ExecutionModel::MissKHR) {
  245. if (message) {
  246. *message = opcode_name +
  247. " requires RayGenerationKHR, ClosestHitKHR and "
  248. "MissKHR execution models";
  249. }
  250. return false;
  251. }
  252. return true;
  253. });
  254. return;
  255. };
  256. switch (opcode) {
  257. case spv::Op::OpHitObjectIsMissNV:
  258. case spv::Op::OpHitObjectIsHitNV:
  259. case spv::Op::OpHitObjectIsEmptyNV: {
  260. RegisterOpcodeForValidModel(_, inst);
  261. if (!_.IsBoolScalarType(result_type)) {
  262. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  263. << "expected Result Type to be bool scalar type";
  264. }
  265. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  266. break;
  267. }
  268. case spv::Op::OpHitObjectGetShaderRecordBufferHandleNV: {
  269. RegisterOpcodeForValidModel(_, inst);
  270. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  271. if (!_.IsIntVectorType(result_type) ||
  272. (_.GetDimension(result_type) != 2) ||
  273. (_.GetBitWidth(result_type) != 32))
  274. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  275. << "Expected 32-bit integer type 2-component vector as Result "
  276. "Type: "
  277. << spvOpcodeString(opcode);
  278. break;
  279. }
  280. case spv::Op::OpHitObjectGetHitKindNV:
  281. case spv::Op::OpHitObjectGetPrimitiveIndexNV:
  282. case spv::Op::OpHitObjectGetGeometryIndexNV:
  283. case spv::Op::OpHitObjectGetInstanceIdNV:
  284. case spv::Op::OpHitObjectGetInstanceCustomIndexNV:
  285. case spv::Op::OpHitObjectGetShaderBindingTableRecordIndexNV: {
  286. RegisterOpcodeForValidModel(_, inst);
  287. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  288. if (!_.IsIntScalarType(result_type) || !_.GetBitWidth(result_type))
  289. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  290. << "Expected 32-bit integer type scalar as Result Type: "
  291. << spvOpcodeString(opcode);
  292. break;
  293. }
  294. case spv::Op::OpHitObjectGetCurrentTimeNV:
  295. case spv::Op::OpHitObjectGetRayTMaxNV:
  296. case spv::Op::OpHitObjectGetRayTMinNV: {
  297. RegisterOpcodeForValidModel(_, inst);
  298. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  299. if (!_.IsFloatScalarType(result_type) || _.GetBitWidth(result_type) != 32)
  300. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  301. << "Expected 32-bit floating-point type scalar as Result Type: "
  302. << spvOpcodeString(opcode);
  303. break;
  304. }
  305. case spv::Op::OpHitObjectGetObjectToWorldNV:
  306. case spv::Op::OpHitObjectGetWorldToObjectNV: {
  307. RegisterOpcodeForValidModel(_, inst);
  308. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  309. uint32_t num_rows = 0;
  310. uint32_t num_cols = 0;
  311. uint32_t col_type = 0;
  312. uint32_t component_type = 0;
  313. if (!_.GetMatrixTypeInfo(result_type, &num_rows, &num_cols, &col_type,
  314. &component_type)) {
  315. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  316. << "expected matrix type as Result Type: "
  317. << spvOpcodeString(opcode);
  318. }
  319. if (num_cols != 4) {
  320. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  321. << "expected Result Type matrix to have a Column Count of 4"
  322. << spvOpcodeString(opcode);
  323. }
  324. if (!_.IsFloatScalarType(component_type) ||
  325. _.GetBitWidth(result_type) != 32 || num_rows != 3) {
  326. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  327. << "expected Result Type matrix to have a Column Type of "
  328. "3-component 32-bit float vectors: "
  329. << spvOpcodeString(opcode);
  330. }
  331. break;
  332. }
  333. case spv::Op::OpHitObjectGetObjectRayOriginNV:
  334. case spv::Op::OpHitObjectGetObjectRayDirectionNV:
  335. case spv::Op::OpHitObjectGetWorldRayDirectionNV:
  336. case spv::Op::OpHitObjectGetWorldRayOriginNV: {
  337. RegisterOpcodeForValidModel(_, inst);
  338. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  339. if (!_.IsFloatVectorType(result_type) ||
  340. (_.GetDimension(result_type) != 3) ||
  341. (_.GetBitWidth(result_type) != 32))
  342. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  343. << "Expected 32-bit floating-point type 3-component vector as "
  344. "Result Type: "
  345. << spvOpcodeString(opcode);
  346. break;
  347. }
  348. case spv::Op::OpHitObjectGetAttributesNV: {
  349. RegisterOpcodeForValidModel(_, inst);
  350. if (auto error = ValidateHitObjectPointer(_, inst, 0)) return error;
  351. const uint32_t hit_object_attr_id = inst->GetOperandAs<uint32_t>(1);
  352. auto variable = _.FindDef(hit_object_attr_id);
  353. const auto var_opcode = variable->opcode();
  354. if (!variable || var_opcode != spv::Op::OpVariable ||
  355. variable->GetOperandAs<spv::StorageClass>(2) !=
  356. spv::StorageClass::HitObjectAttributeNV) {
  357. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  358. << "Hit Object Attributes id must be a OpVariable of storage "
  359. "class HitObjectAttributeNV";
  360. }
  361. break;
  362. }
  363. case spv::Op::OpHitObjectExecuteShaderNV: {
  364. RegisterOpcodeForValidModel(_, inst);
  365. if (auto error = ValidateHitObjectPointer(_, inst, 0)) return error;
  366. const uint32_t hit_object_attr_id = inst->GetOperandAs<uint32_t>(1);
  367. auto variable = _.FindDef(hit_object_attr_id);
  368. const auto var_opcode = variable->opcode();
  369. if (!variable || var_opcode != spv::Op::OpVariable ||
  370. (variable->GetOperandAs<spv::StorageClass>(2)) !=
  371. spv::StorageClass::RayPayloadKHR) {
  372. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  373. << "Hit Object Attributes id must be a OpVariable of storage "
  374. "class RayPayloadKHR";
  375. }
  376. break;
  377. }
  378. case spv::Op::OpHitObjectRecordEmptyNV: {
  379. RegisterOpcodeForValidModel(_, inst);
  380. if (auto error = ValidateHitObjectPointer(_, inst, 0)) return error;
  381. break;
  382. }
  383. case spv::Op::OpHitObjectRecordMissNV: {
  384. RegisterOpcodeForValidModel(_, inst);
  385. if (auto error = ValidateHitObjectPointer(_, inst, 0)) return error;
  386. const uint32_t miss_index = _.GetOperandTypeId(inst, 1);
  387. if (!_.IsUnsignedIntScalarType(miss_index) ||
  388. _.GetBitWidth(miss_index) != 32) {
  389. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  390. << "Miss Index must be a 32-bit int scalar";
  391. }
  392. const uint32_t ray_origin = _.GetOperandTypeId(inst, 2);
  393. if (!_.IsFloatVectorType(ray_origin) || _.GetDimension(ray_origin) != 3 ||
  394. _.GetBitWidth(ray_origin) != 32) {
  395. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  396. << "Ray Origin must be a 32-bit float 3-component vector";
  397. }
  398. const uint32_t ray_tmin = _.GetOperandTypeId(inst, 3);
  399. if (!_.IsFloatScalarType(ray_tmin) || _.GetBitWidth(ray_tmin) != 32) {
  400. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  401. << "Ray TMin must be a 32-bit float scalar";
  402. }
  403. const uint32_t ray_direction = _.GetOperandTypeId(inst, 4);
  404. if (!_.IsFloatVectorType(ray_direction) ||
  405. _.GetDimension(ray_direction) != 3 ||
  406. _.GetBitWidth(ray_direction) != 32) {
  407. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  408. << "Ray Direction must be a 32-bit float 3-component vector";
  409. }
  410. const uint32_t ray_tmax = _.GetOperandTypeId(inst, 5);
  411. if (!_.IsFloatScalarType(ray_tmax) || _.GetBitWidth(ray_tmax) != 32) {
  412. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  413. << "Ray TMax must be a 32-bit float scalar";
  414. }
  415. break;
  416. }
  417. case spv::Op::OpHitObjectRecordHitWithIndexNV: {
  418. RegisterOpcodeForValidModel(_, inst);
  419. if (auto error = ValidateHitObjectPointer(_, inst, 0)) return error;
  420. if (auto error = ValidateHitObjectInstructionCommonParameters(
  421. _, inst, 1 /* Acceleration Struct */, 2 /* Instance Id */,
  422. 3 /* Primtive Id */, 4 /* Geometry Index */,
  423. KRayParamInvalidId /* Ray Flags */,
  424. KRayParamInvalidId /* Cull Mask */, 5 /* Hit Kind*/,
  425. 6 /* SBT index */, KRayParamInvalidId /* SBT Offset */,
  426. KRayParamInvalidId /* SBT Stride */,
  427. KRayParamInvalidId /* SBT Record Offset */,
  428. KRayParamInvalidId /* SBT Record Stride */,
  429. KRayParamInvalidId /* Miss Index */, 7 /* Ray Origin */,
  430. 8 /* Ray TMin */, 9 /* Ray Direction */, 10 /* Ray TMax */,
  431. KRayParamInvalidId /* Payload */, 11 /* Hit Object Attribute */))
  432. return error;
  433. break;
  434. }
  435. case spv::Op::OpHitObjectRecordHitNV: {
  436. RegisterOpcodeForValidModel(_, inst);
  437. if (auto error = ValidateHitObjectPointer(_, inst, 0)) return error;
  438. if (auto error = ValidateHitObjectInstructionCommonParameters(
  439. _, inst, 1 /* Acceleration Struct */, 2 /* Instance Id */,
  440. 3 /* Primtive Id */, 4 /* Geometry Index */,
  441. KRayParamInvalidId /* Ray Flags */,
  442. KRayParamInvalidId /* Cull Mask */, 5 /* Hit Kind*/,
  443. KRayParamInvalidId /* SBT index */,
  444. KRayParamInvalidId /* SBT Offset */,
  445. KRayParamInvalidId /* SBT Stride */, 6 /* SBT Record Offset */,
  446. 7 /* SBT Record Stride */, KRayParamInvalidId /* Miss Index */,
  447. 8 /* Ray Origin */, 9 /* Ray TMin */, 10 /* Ray Direction */,
  448. 11 /* Ray TMax */, KRayParamInvalidId /* Payload */,
  449. 12 /* Hit Object Attribute */))
  450. return error;
  451. break;
  452. }
  453. case spv::Op::OpHitObjectTraceRayMotionNV: {
  454. RegisterOpcodeForValidModel(_, inst);
  455. if (auto error = ValidateHitObjectPointer(_, inst, 0)) return error;
  456. if (auto error = ValidateHitObjectInstructionCommonParameters(
  457. _, inst, 1 /* Acceleration Struct */,
  458. KRayParamInvalidId /* Instance Id */,
  459. KRayParamInvalidId /* Primtive Id */,
  460. KRayParamInvalidId /* Geometry Index */, 2 /* Ray Flags */,
  461. 3 /* Cull Mask */, KRayParamInvalidId /* Hit Kind*/,
  462. KRayParamInvalidId /* SBT index */, 4 /* SBT Offset */,
  463. 5 /* SBT Stride */, KRayParamInvalidId /* SBT Record Offset */,
  464. KRayParamInvalidId /* SBT Record Stride */, 6 /* Miss Index */,
  465. 7 /* Ray Origin */, 8 /* Ray TMin */, 9 /* Ray Direction */,
  466. 10 /* Ray TMax */, 12 /* Payload */,
  467. KRayParamInvalidId /* Hit Object Attribute */))
  468. return error;
  469. // Current Time
  470. const uint32_t current_time_id = _.GetOperandTypeId(inst, 11);
  471. if (!_.IsFloatScalarType(current_time_id) ||
  472. _.GetBitWidth(current_time_id) != 32) {
  473. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  474. << "Current Times must be a 32-bit float scalar type";
  475. }
  476. break;
  477. }
  478. case spv::Op::OpHitObjectTraceRayNV: {
  479. RegisterOpcodeForValidModel(_, inst);
  480. if (auto error = ValidateHitObjectPointer(_, inst, 0)) return error;
  481. if (auto error = ValidateHitObjectInstructionCommonParameters(
  482. _, inst, 1 /* Acceleration Struct */,
  483. KRayParamInvalidId /* Instance Id */,
  484. KRayParamInvalidId /* Primtive Id */,
  485. KRayParamInvalidId /* Geometry Index */, 2 /* Ray Flags */,
  486. 3 /* Cull Mask */, KRayParamInvalidId /* Hit Kind*/,
  487. KRayParamInvalidId /* SBT index */, 4 /* SBT Offset */,
  488. 5 /* SBT Stride */, KRayParamInvalidId /* SBT Record Offset */,
  489. KRayParamInvalidId /* SBT Record Stride */, 6 /* Miss Index */,
  490. 7 /* Ray Origin */, 8 /* Ray TMin */, 9 /* Ray Direction */,
  491. 10 /* Ray TMax */, 11 /* Payload */,
  492. KRayParamInvalidId /* Hit Object Attribute */))
  493. return error;
  494. break;
  495. }
  496. case spv::Op::OpReorderThreadWithHitObjectNV: {
  497. std::string opcode_name = spvOpcodeString(inst->opcode());
  498. _.function(inst->function()->id())
  499. ->RegisterExecutionModelLimitation(
  500. [opcode_name](spv::ExecutionModel model, std::string* message) {
  501. if (model != spv::ExecutionModel::RayGenerationKHR) {
  502. if (message) {
  503. *message = opcode_name +
  504. " requires RayGenerationKHR execution model";
  505. }
  506. return false;
  507. }
  508. return true;
  509. });
  510. if (auto error = ValidateHitObjectPointer(_, inst, 0)) return error;
  511. if (inst->operands().size() > 1) {
  512. if (inst->operands().size() != 3) {
  513. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  514. << "Hint and Bits are optional together i.e "
  515. << " Either both Hint and Bits should be provided or neither.";
  516. }
  517. // Validate the optional opreands Hint and Bits
  518. const uint32_t hint_id = _.GetOperandTypeId(inst, 1);
  519. if (!_.IsIntScalarType(hint_id) || _.GetBitWidth(hint_id) != 32) {
  520. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  521. << "Hint must be a 32-bit int scalar";
  522. }
  523. const uint32_t bits_id = _.GetOperandTypeId(inst, 2);
  524. if (!_.IsIntScalarType(bits_id) || _.GetBitWidth(bits_id) != 32) {
  525. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  526. << "bits must be a 32-bit int scalar";
  527. }
  528. }
  529. break;
  530. }
  531. case spv::Op::OpReorderThreadWithHintNV: {
  532. std::string opcode_name = spvOpcodeString(inst->opcode());
  533. _.function(inst->function()->id())
  534. ->RegisterExecutionModelLimitation(
  535. [opcode_name](spv::ExecutionModel model, std::string* message) {
  536. if (model != spv::ExecutionModel::RayGenerationKHR) {
  537. if (message) {
  538. *message = opcode_name +
  539. " requires RayGenerationKHR execution model";
  540. }
  541. return false;
  542. }
  543. return true;
  544. });
  545. const uint32_t hint_id = _.GetOperandTypeId(inst, 0);
  546. if (!_.IsIntScalarType(hint_id) || _.GetBitWidth(hint_id) != 32) {
  547. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  548. << "Hint must be a 32-bit int scalar";
  549. }
  550. const uint32_t bits_id = _.GetOperandTypeId(inst, 1);
  551. if (!_.IsIntScalarType(bits_id) || _.GetBitWidth(bits_id) != 32) {
  552. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  553. << "bits must be a 32-bit int scalar";
  554. }
  555. break;
  556. }
  557. case spv::Op::OpHitObjectGetClusterIdNV: {
  558. RegisterOpcodeForValidModel(_, inst);
  559. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  560. if (!_.IsIntScalarType(result_type) || _.GetBitWidth(result_type) != 32)
  561. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  562. << "Expected 32-bit integer type scalar as Result Type: "
  563. << spvOpcodeString(opcode);
  564. break;
  565. }
  566. case spv::Op::OpHitObjectGetSpherePositionNV: {
  567. RegisterOpcodeForValidModel(_, inst);
  568. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  569. if (!_.IsFloatVectorType(result_type) ||
  570. _.GetDimension(result_type) != 3 ||
  571. _.GetBitWidth(result_type) != 32) {
  572. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  573. << "Expected 32-bit floating point 2 component vector type as "
  574. "Result Type: "
  575. << spvOpcodeString(opcode);
  576. }
  577. break;
  578. }
  579. case spv::Op::OpHitObjectGetSphereRadiusNV: {
  580. RegisterOpcodeForValidModel(_, inst);
  581. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  582. if (!_.IsFloatScalarType(result_type) ||
  583. _.GetBitWidth(result_type) != 32) {
  584. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  585. << "Expected 32-bit floating point scalar as Result Type: "
  586. << spvOpcodeString(opcode);
  587. }
  588. break;
  589. }
  590. case spv::Op::OpHitObjectGetLSSPositionsNV: {
  591. RegisterOpcodeForValidModel(_, inst);
  592. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  593. auto result_id = _.FindDef(result_type);
  594. if ((result_id->opcode() != spv::Op::OpTypeArray) ||
  595. (GetArrayLength(_, result_id) != 2) ||
  596. !_.IsFloatVectorType(_.GetComponentType(result_type)) ||
  597. _.GetDimension(_.GetComponentType(result_type)) != 3) {
  598. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  599. << "Expected 2 element array of 32-bit 3 component float point "
  600. "vector as Result Type: "
  601. << spvOpcodeString(opcode);
  602. }
  603. break;
  604. }
  605. case spv::Op::OpHitObjectGetLSSRadiiNV: {
  606. RegisterOpcodeForValidModel(_, inst);
  607. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  608. if (!_.IsFloatArrayType(result_type) ||
  609. (GetArrayLength(_, _.FindDef(result_type)) != 2) ||
  610. !_.IsFloatScalarType(_.GetComponentType(result_type))) {
  611. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  612. << "Expected 2 element array of 32-bit floating point scalar as "
  613. "Result Type: "
  614. << spvOpcodeString(opcode);
  615. }
  616. break;
  617. }
  618. case spv::Op::OpHitObjectIsSphereHitNV: {
  619. RegisterOpcodeForValidModel(_, inst);
  620. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  621. if (!_.IsBoolScalarType(result_type)) {
  622. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  623. << "Expected Boolean scalar as Result Type: "
  624. << spvOpcodeString(opcode);
  625. }
  626. break;
  627. }
  628. case spv::Op::OpHitObjectIsLSSHitNV: {
  629. RegisterOpcodeForValidModel(_, inst);
  630. if (auto error = ValidateHitObjectPointer(_, inst, 2)) return error;
  631. if (!_.IsBoolScalarType(result_type)) {
  632. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  633. << "Expected Boolean scalar as Result Type: "
  634. << spvOpcodeString(opcode);
  635. }
  636. break;
  637. }
  638. default:
  639. break;
  640. }
  641. return SPV_SUCCESS;
  642. }
  643. } // namespace val
  644. } // namespace spvtools