1 // Copyright (c) 2017 Google 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 15 // Validates correctness of image instructions. 16 17 #include "source/val/validate.h" 18 19 #include <string> 20 21 #include "source/diagnostic.h" 22 #include "source/opcode.h" 23 #include "source/spirv_target_env.h" 24 #include "source/util/bitutils.h" 25 #include "source/val/instruction.h" 26 #include "source/val/validate_scopes.h" 27 #include "source/val/validation_state.h" 28 29 namespace spvtools { 30 namespace val { 31 namespace { 32 33 // Performs compile time check that all SpvImageOperandsXXX cases are handled in 34 // this module. If SpvImageOperandsXXX list changes, this function will fail the 35 // build. 36 // For all other purposes this is a dummy function. 37 bool CheckAllImageOperandsHandled() { 38 SpvImageOperandsMask enum_val = SpvImageOperandsBiasMask; 39 40 // Some improvised code to prevent the compiler from considering enum_val 41 // constant and optimizing the switch away. 42 uint32_t stack_var = 0; 43 if (reinterpret_cast<uintptr_t>(&stack_var) % 256) 44 enum_val = SpvImageOperandsLodMask; 45 46 switch (enum_val) { 47 // Please update the validation rules in this module if you are changing 48 // the list of image operands, and add new enum values to this switch. 49 case SpvImageOperandsMaskNone: 50 return false; 51 case SpvImageOperandsBiasMask: 52 case SpvImageOperandsLodMask: 53 case SpvImageOperandsGradMask: 54 case SpvImageOperandsConstOffsetMask: 55 case SpvImageOperandsOffsetMask: 56 case SpvImageOperandsConstOffsetsMask: 57 case SpvImageOperandsSampleMask: 58 case SpvImageOperandsMinLodMask: 59 60 // TODO(dneto): Support image operands related to the Vulkan memory model. 61 // https://gitlab.khronos.org/spirv/spirv-tools/issues/32 62 case SpvImageOperandsMakeTexelAvailableKHRMask: 63 case SpvImageOperandsMakeTexelVisibleKHRMask: 64 case SpvImageOperandsNonPrivateTexelKHRMask: 65 case SpvImageOperandsVolatileTexelKHRMask: 66 return true; 67 } 68 return false; 69 } 70 71 // Used by GetImageTypeInfo. See OpTypeImage spec for more information. 72 struct ImageTypeInfo { 73 uint32_t sampled_type = 0; 74 SpvDim dim = SpvDimMax; 75 uint32_t depth = 0; 76 uint32_t arrayed = 0; 77 uint32_t multisampled = 0; 78 uint32_t sampled = 0; 79 SpvImageFormat format = SpvImageFormatMax; 80 SpvAccessQualifier access_qualifier = SpvAccessQualifierMax; 81 }; 82 83 // Provides information on image type. |id| should be object of either 84 // OpTypeImage or OpTypeSampledImage type. Returns false in case of failure 85 // (not a valid id, failed to parse the instruction, etc). 86 bool GetImageTypeInfo(const ValidationState_t& _, uint32_t id, 87 ImageTypeInfo* info) { 88 if (!id || !info) return false; 89 90 const Instruction* inst = _.FindDef(id); 91 assert(inst); 92 93 if (inst->opcode() == SpvOpTypeSampledImage) { 94 inst = _.FindDef(inst->word(2)); 95 assert(inst); 96 } 97 98 if (inst->opcode() != SpvOpTypeImage) return false; 99 100 const size_t num_words = inst->words().size(); 101 if (num_words != 9 && num_words != 10) return false; 102 103 info->sampled_type = inst->word(2); 104 info->dim = static_cast<SpvDim>(inst->word(3)); 105 info->depth = inst->word(4); 106 info->arrayed = inst->word(5); 107 info->multisampled = inst->word(6); 108 info->sampled = inst->word(7); 109 info->format = static_cast<SpvImageFormat>(inst->word(8)); 110 info->access_qualifier = num_words < 10 111 ? SpvAccessQualifierMax 112 : static_cast<SpvAccessQualifier>(inst->word(9)); 113 return true; 114 } 115 116 bool IsImplicitLod(SpvOp opcode) { 117 switch (opcode) { 118 case SpvOpImageSampleImplicitLod: 119 case SpvOpImageSampleDrefImplicitLod: 120 case SpvOpImageSampleProjImplicitLod: 121 case SpvOpImageSampleProjDrefImplicitLod: 122 case SpvOpImageSparseSampleImplicitLod: 123 case SpvOpImageSparseSampleDrefImplicitLod: 124 case SpvOpImageSparseSampleProjImplicitLod: 125 case SpvOpImageSparseSampleProjDrefImplicitLod: 126 return true; 127 default: 128 break; 129 } 130 return false; 131 } 132 133 bool IsExplicitLod(SpvOp opcode) { 134 switch (opcode) { 135 case SpvOpImageSampleExplicitLod: 136 case SpvOpImageSampleDrefExplicitLod: 137 case SpvOpImageSampleProjExplicitLod: 138 case SpvOpImageSampleProjDrefExplicitLod: 139 case SpvOpImageSparseSampleExplicitLod: 140 case SpvOpImageSparseSampleDrefExplicitLod: 141 case SpvOpImageSparseSampleProjExplicitLod: 142 case SpvOpImageSparseSampleProjDrefExplicitLod: 143 return true; 144 default: 145 break; 146 } 147 return false; 148 } 149 150 // Returns true if the opcode is a Image instruction which applies 151 // homogenous projection to the coordinates. 152 bool IsProj(SpvOp opcode) { 153 switch (opcode) { 154 case SpvOpImageSampleProjImplicitLod: 155 case SpvOpImageSampleProjDrefImplicitLod: 156 case SpvOpImageSparseSampleProjImplicitLod: 157 case SpvOpImageSparseSampleProjDrefImplicitLod: 158 case SpvOpImageSampleProjExplicitLod: 159 case SpvOpImageSampleProjDrefExplicitLod: 160 case SpvOpImageSparseSampleProjExplicitLod: 161 case SpvOpImageSparseSampleProjDrefExplicitLod: 162 return true; 163 default: 164 break; 165 } 166 return false; 167 } 168 169 // Returns the number of components in a coordinate used to access a texel in 170 // a single plane of an image with the given parameters. 171 uint32_t GetPlaneCoordSize(const ImageTypeInfo& info) { 172 uint32_t plane_size = 0; 173 // If this switch breaks your build, please add new values below. 174 switch (info.dim) { 175 case SpvDim1D: 176 case SpvDimBuffer: 177 plane_size = 1; 178 break; 179 case SpvDim2D: 180 case SpvDimRect: 181 case SpvDimSubpassData: 182 plane_size = 2; 183 break; 184 case SpvDim3D: 185 case SpvDimCube: 186 // For Cube direction vector is used instead of UV. 187 plane_size = 3; 188 break; 189 case SpvDimMax: 190 assert(0); 191 break; 192 } 193 194 return plane_size; 195 } 196 197 // Returns minimal number of coordinates based on image dim, arrayed and whether 198 // the instruction uses projection coordinates. 199 uint32_t GetMinCoordSize(SpvOp opcode, const ImageTypeInfo& info) { 200 if (info.dim == SpvDimCube && 201 (opcode == SpvOpImageRead || opcode == SpvOpImageWrite || 202 opcode == SpvOpImageSparseRead)) { 203 // These opcodes use UV for Cube, not direction vector. 204 return 3; 205 } 206 207 return GetPlaneCoordSize(info) + info.arrayed + (IsProj(opcode) ? 1 : 0); 208 } 209 210 // Checks ImageOperand bitfield and respective operands. 211 spv_result_t ValidateImageOperands(ValidationState_t& _, 212 const Instruction* inst, 213 const ImageTypeInfo& info, uint32_t mask, 214 uint32_t word_index) { 215 static const bool kAllImageOperandsHandled = CheckAllImageOperandsHandled(); 216 (void)kAllImageOperandsHandled; 217 218 const SpvOp opcode = inst->opcode(); 219 const size_t num_words = inst->words().size(); 220 221 // NonPrivate and Volatile take no operand words. 222 const uint32_t mask_bits_having_operands = 223 mask & ~uint32_t(SpvImageOperandsNonPrivateTexelKHRMask | 224 SpvImageOperandsVolatileTexelKHRMask); 225 size_t expected_num_image_operand_words = 226 spvtools::utils::CountSetBits(mask_bits_having_operands); 227 if (mask & SpvImageOperandsGradMask) { 228 // Grad uses two words. 229 ++expected_num_image_operand_words; 230 } 231 232 if (expected_num_image_operand_words != num_words - word_index) { 233 return _.diag(SPV_ERROR_INVALID_DATA, inst) 234 << "Number of image operand ids doesn't correspond to the bit mask"; 235 } 236 237 if (spvtools::utils::CountSetBits( 238 mask & (SpvImageOperandsOffsetMask | SpvImageOperandsConstOffsetMask | 239 SpvImageOperandsConstOffsetsMask)) > 1) { 240 return _.diag(SPV_ERROR_INVALID_DATA, inst) 241 << "Image Operands Offset, ConstOffset, ConstOffsets cannot be used " 242 << "together"; 243 } 244 245 const bool is_implicit_lod = IsImplicitLod(opcode); 246 const bool is_explicit_lod = IsExplicitLod(opcode); 247 248 // The checks should be done in the order of definition of OperandImage. 249 250 if (mask & SpvImageOperandsBiasMask) { 251 if (!is_implicit_lod) { 252 return _.diag(SPV_ERROR_INVALID_DATA, inst) 253 << "Image Operand Bias can only be used with ImplicitLod opcodes"; 254 } 255 256 const uint32_t type_id = _.GetTypeId(inst->word(word_index++)); 257 if (!_.IsFloatScalarType(type_id)) { 258 return _.diag(SPV_ERROR_INVALID_DATA, inst) 259 << "Expected Image Operand Bias to be float scalar"; 260 } 261 262 if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D && 263 info.dim != SpvDimCube) { 264 return _.diag(SPV_ERROR_INVALID_DATA, inst) 265 << "Image Operand Bias requires 'Dim' parameter to be 1D, 2D, 3D " 266 "or Cube"; 267 } 268 269 if (info.multisampled != 0) { 270 return _.diag(SPV_ERROR_INVALID_DATA, inst) 271 << "Image Operand Bias requires 'MS' parameter to be 0"; 272 } 273 } 274 275 if (mask & SpvImageOperandsLodMask) { 276 if (!is_explicit_lod && opcode != SpvOpImageFetch && 277 opcode != SpvOpImageSparseFetch) { 278 return _.diag(SPV_ERROR_INVALID_DATA, inst) 279 << "Image Operand Lod can only be used with ExplicitLod opcodes " 280 << "and OpImageFetch"; 281 } 282 283 if (mask & SpvImageOperandsGradMask) { 284 return _.diag(SPV_ERROR_INVALID_DATA, inst) 285 << "Image Operand bits Lod and Grad cannot be set at the same " 286 "time"; 287 } 288 289 const uint32_t type_id = _.GetTypeId(inst->word(word_index++)); 290 if (is_explicit_lod) { 291 if (!_.IsFloatScalarType(type_id)) { 292 return _.diag(SPV_ERROR_INVALID_DATA, inst) 293 << "Expected Image Operand Lod to be float scalar when used " 294 << "with ExplicitLod"; 295 } 296 } else { 297 if (!_.IsIntScalarType(type_id)) { 298 return _.diag(SPV_ERROR_INVALID_DATA, inst) 299 << "Expected Image Operand Lod to be int scalar when used with " 300 << "OpImageFetch"; 301 } 302 } 303 304 if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D && 305 info.dim != SpvDimCube) { 306 return _.diag(SPV_ERROR_INVALID_DATA, inst) 307 << "Image Operand Lod requires 'Dim' parameter to be 1D, 2D, 3D " 308 "or Cube"; 309 } 310 311 if (info.multisampled != 0) { 312 return _.diag(SPV_ERROR_INVALID_DATA, inst) 313 << "Image Operand Lod requires 'MS' parameter to be 0"; 314 } 315 } 316 317 if (mask & SpvImageOperandsGradMask) { 318 if (!is_explicit_lod) { 319 return _.diag(SPV_ERROR_INVALID_DATA, inst) 320 << "Image Operand Grad can only be used with ExplicitLod opcodes"; 321 } 322 323 const uint32_t dx_type_id = _.GetTypeId(inst->word(word_index++)); 324 const uint32_t dy_type_id = _.GetTypeId(inst->word(word_index++)); 325 if (!_.IsFloatScalarOrVectorType(dx_type_id) || 326 !_.IsFloatScalarOrVectorType(dy_type_id)) { 327 return _.diag(SPV_ERROR_INVALID_DATA, inst) 328 << "Expected both Image Operand Grad ids to be float scalars or " 329 << "vectors"; 330 } 331 332 const uint32_t plane_size = GetPlaneCoordSize(info); 333 const uint32_t dx_size = _.GetDimension(dx_type_id); 334 const uint32_t dy_size = _.GetDimension(dy_type_id); 335 if (plane_size != dx_size) { 336 return _.diag(SPV_ERROR_INVALID_DATA, inst) 337 << "Expected Image Operand Grad dx to have " << plane_size 338 << " components, but given " << dx_size; 339 } 340 341 if (plane_size != dy_size) { 342 return _.diag(SPV_ERROR_INVALID_DATA, inst) 343 << "Expected Image Operand Grad dy to have " << plane_size 344 << " components, but given " << dy_size; 345 } 346 347 if (info.multisampled != 0) { 348 return _.diag(SPV_ERROR_INVALID_DATA, inst) 349 << "Image Operand Grad requires 'MS' parameter to be 0"; 350 } 351 } 352 353 if (mask & SpvImageOperandsConstOffsetMask) { 354 if (info.dim == SpvDimCube) { 355 return _.diag(SPV_ERROR_INVALID_DATA, inst) 356 << "Image Operand ConstOffset cannot be used with Cube Image " 357 "'Dim'"; 358 } 359 360 const uint32_t id = inst->word(word_index++); 361 const uint32_t type_id = _.GetTypeId(id); 362 if (!_.IsIntScalarOrVectorType(type_id)) { 363 return _.diag(SPV_ERROR_INVALID_DATA, inst) 364 << "Expected Image Operand ConstOffset to be int scalar or " 365 << "vector"; 366 } 367 368 if (!spvOpcodeIsConstant(_.GetIdOpcode(id))) { 369 return _.diag(SPV_ERROR_INVALID_DATA, inst) 370 << "Expected Image Operand ConstOffset to be a const object"; 371 } 372 373 const uint32_t plane_size = GetPlaneCoordSize(info); 374 const uint32_t offset_size = _.GetDimension(type_id); 375 if (plane_size != offset_size) { 376 return _.diag(SPV_ERROR_INVALID_DATA, inst) 377 << "Expected Image Operand ConstOffset to have " << plane_size 378 << " components, but given " << offset_size; 379 } 380 } 381 382 if (mask & SpvImageOperandsOffsetMask) { 383 if (info.dim == SpvDimCube) { 384 return _.diag(SPV_ERROR_INVALID_DATA, inst) 385 << "Image Operand Offset cannot be used with Cube Image 'Dim'"; 386 } 387 388 const uint32_t id = inst->word(word_index++); 389 const uint32_t type_id = _.GetTypeId(id); 390 if (!_.IsIntScalarOrVectorType(type_id)) { 391 return _.diag(SPV_ERROR_INVALID_DATA, inst) 392 << "Expected Image Operand Offset to be int scalar or " 393 << "vector"; 394 } 395 396 const uint32_t plane_size = GetPlaneCoordSize(info); 397 const uint32_t offset_size = _.GetDimension(type_id); 398 if (plane_size != offset_size) { 399 return _.diag(SPV_ERROR_INVALID_DATA, inst) 400 << "Expected Image Operand Offset to have " << plane_size 401 << " components, but given " << offset_size; 402 } 403 } 404 405 if (mask & SpvImageOperandsConstOffsetsMask) { 406 if (opcode != SpvOpImageGather && opcode != SpvOpImageDrefGather && 407 opcode != SpvOpImageSparseGather && 408 opcode != SpvOpImageSparseDrefGather) { 409 return _.diag(SPV_ERROR_INVALID_DATA, inst) 410 << "Image Operand ConstOffsets can only be used with " 411 "OpImageGather and OpImageDrefGather"; 412 } 413 414 if (info.dim == SpvDimCube) { 415 return _.diag(SPV_ERROR_INVALID_DATA, inst) 416 << "Image Operand ConstOffsets cannot be used with Cube Image " 417 "'Dim'"; 418 } 419 420 const uint32_t id = inst->word(word_index++); 421 const uint32_t type_id = _.GetTypeId(id); 422 const Instruction* type_inst = _.FindDef(type_id); 423 assert(type_inst); 424 425 if (type_inst->opcode() != SpvOpTypeArray) { 426 return _.diag(SPV_ERROR_INVALID_DATA, inst) 427 << "Expected Image Operand ConstOffsets to be an array of size 4"; 428 } 429 430 uint64_t array_size = 0; 431 if (!_.GetConstantValUint64(type_inst->word(3), &array_size)) { 432 assert(0 && "Array type definition is corrupt"); 433 } 434 435 if (array_size != 4) { 436 return _.diag(SPV_ERROR_INVALID_DATA, inst) 437 << "Expected Image Operand ConstOffsets to be an array of size 4"; 438 } 439 440 const uint32_t component_type = type_inst->word(2); 441 if (!_.IsIntVectorType(component_type) || 442 _.GetDimension(component_type) != 2) { 443 return _.diag(SPV_ERROR_INVALID_DATA, inst) 444 << "Expected Image Operand ConstOffsets array componenets to be " 445 "int vectors of size 2"; 446 } 447 448 if (!spvOpcodeIsConstant(_.GetIdOpcode(id))) { 449 return _.diag(SPV_ERROR_INVALID_DATA, inst) 450 << "Expected Image Operand ConstOffsets to be a const object"; 451 } 452 } 453 454 if (mask & SpvImageOperandsSampleMask) { 455 if (opcode != SpvOpImageFetch && opcode != SpvOpImageRead && 456 opcode != SpvOpImageWrite && opcode != SpvOpImageSparseFetch && 457 opcode != SpvOpImageSparseRead) { 458 return _.diag(SPV_ERROR_INVALID_DATA, inst) 459 << "Image Operand Sample can only be used with OpImageFetch, " 460 << "OpImageRead, OpImageWrite, OpImageSparseFetch and " 461 << "OpImageSparseRead"; 462 } 463 464 if (info.multisampled == 0) { 465 return _.diag(SPV_ERROR_INVALID_DATA, inst) 466 << "Image Operand Sample requires non-zero 'MS' parameter"; 467 } 468 469 const uint32_t type_id = _.GetTypeId(inst->word(word_index++)); 470 if (!_.IsIntScalarType(type_id)) { 471 return _.diag(SPV_ERROR_INVALID_DATA, inst) 472 << "Expected Image Operand Sample to be int scalar"; 473 } 474 } 475 476 if (mask & SpvImageOperandsMinLodMask) { 477 if (!is_implicit_lod && !(mask & SpvImageOperandsGradMask)) { 478 return _.diag(SPV_ERROR_INVALID_DATA, inst) 479 << "Image Operand MinLod can only be used with ImplicitLod " 480 << "opcodes or together with Image Operand Grad"; 481 } 482 483 const uint32_t type_id = _.GetTypeId(inst->word(word_index++)); 484 if (!_.IsFloatScalarType(type_id)) { 485 return _.diag(SPV_ERROR_INVALID_DATA, inst) 486 << "Expected Image Operand MinLod to be float scalar"; 487 } 488 489 if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D && 490 info.dim != SpvDimCube) { 491 return _.diag(SPV_ERROR_INVALID_DATA, inst) 492 << "Image Operand MinLod requires 'Dim' parameter to be 1D, 2D, " 493 "3D or Cube"; 494 } 495 496 if (info.multisampled != 0) { 497 return _.diag(SPV_ERROR_INVALID_DATA, inst) 498 << "Image Operand MinLod requires 'MS' parameter to be 0"; 499 } 500 } 501 502 if (mask & SpvImageOperandsMakeTexelAvailableKHRMask) { 503 // Checked elsewhere: capability and memory model are correct. 504 if (opcode != SpvOpImageWrite) { 505 return _.diag(SPV_ERROR_INVALID_DATA, inst) 506 << "Image Operand MakeTexelAvailableKHR can only be used with Op" 507 << spvOpcodeString(SpvOpImageWrite) << ": Op" 508 << spvOpcodeString(opcode); 509 } 510 511 if (!(mask & SpvImageOperandsNonPrivateTexelKHRMask)) { 512 return _.diag(SPV_ERROR_INVALID_DATA, inst) 513 << "Image Operand MakeTexelAvailableKHR requires " 514 "NonPrivateTexelKHR is also specified: Op" 515 << spvOpcodeString(opcode); 516 } 517 518 const auto available_scope = inst->word(word_index++); 519 if (auto error = ValidateMemoryScope(_, inst, available_scope)) 520 return error; 521 } 522 523 if (mask & SpvImageOperandsMakeTexelVisibleKHRMask) { 524 // Checked elsewhere: capability and memory model are correct. 525 if (opcode != SpvOpImageRead && opcode != SpvOpImageSparseRead) { 526 return _.diag(SPV_ERROR_INVALID_DATA, inst) 527 << "Image Operand MakeTexelVisibleKHR can only be used with Op" 528 << spvOpcodeString(SpvOpImageRead) << " or Op" 529 << spvOpcodeString(SpvOpImageSparseRead) << ": Op" 530 << spvOpcodeString(opcode); 531 } 532 533 if (!(mask & SpvImageOperandsNonPrivateTexelKHRMask)) { 534 return _.diag(SPV_ERROR_INVALID_DATA, inst) 535 << "Image Operand MakeTexelVisibleKHR requires NonPrivateTexelKHR " 536 "is also specified: Op" 537 << spvOpcodeString(opcode); 538 } 539 540 const auto visible_scope = inst->word(word_index++); 541 if (auto error = ValidateMemoryScope(_, inst, visible_scope)) return error; 542 } 543 544 return SPV_SUCCESS; 545 } 546 547 // Checks some of the validation rules which are common to multiple opcodes. 548 spv_result_t ValidateImageCommon(ValidationState_t& _, const Instruction* inst, 549 const ImageTypeInfo& info) { 550 const SpvOp opcode = inst->opcode(); 551 if (IsProj(opcode)) { 552 if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D && 553 info.dim != SpvDimRect) { 554 return _.diag(SPV_ERROR_INVALID_DATA, inst) 555 << "Expected Image 'Dim' parameter to be 1D, 2D, 3D or Rect"; 556 } 557 558 if (info.multisampled != 0) { 559 return _.diag(SPV_ERROR_INVALID_DATA, inst) 560 << "Image Image 'MS' parameter to be 0"; 561 } 562 563 if (info.arrayed != 0) { 564 return _.diag(SPV_ERROR_INVALID_DATA, inst) 565 << "Image Image 'arrayed' parameter to be 0"; 566 } 567 } 568 569 if (opcode == SpvOpImageRead || opcode == SpvOpImageSparseRead || 570 opcode == SpvOpImageWrite) { 571 if (info.sampled == 0) { 572 } else if (info.sampled == 2) { 573 if (info.dim == SpvDim1D && !_.HasCapability(SpvCapabilityImage1D)) { 574 return _.diag(SPV_ERROR_INVALID_DATA, inst) 575 << "Capability Image1D is required to access storage image"; 576 } else if (info.dim == SpvDimRect && 577 !_.HasCapability(SpvCapabilityImageRect)) { 578 return _.diag(SPV_ERROR_INVALID_DATA, inst) 579 << "Capability ImageRect is required to access storage image"; 580 } else if (info.dim == SpvDimBuffer && 581 !_.HasCapability(SpvCapabilityImageBuffer)) { 582 return _.diag(SPV_ERROR_INVALID_DATA, inst) 583 << "Capability ImageBuffer is required to access storage image"; 584 } else if (info.dim == SpvDimCube && info.arrayed == 1 && 585 !_.HasCapability(SpvCapabilityImageCubeArray)) { 586 return _.diag(SPV_ERROR_INVALID_DATA, inst) 587 << "Capability ImageCubeArray is required to access " 588 << "storage image"; 589 } 590 591 if (info.multisampled == 1 && 592 !_.HasCapability(SpvCapabilityImageMSArray)) { 593 #if 0 594 // TODO(atgoo (at) github.com) The description of this rule in the spec 595 // is unclear and Glslang doesn't declare ImageMSArray. Need to clarify 596 // and reenable. 597 return _.diag(SPV_ERROR_INVALID_DATA, inst) 598 << "Capability ImageMSArray is required to access storage " 599 << "image"; 600 #endif 601 } 602 } else { 603 return _.diag(SPV_ERROR_INVALID_DATA, inst) 604 << "Expected Image 'Sampled' parameter to be 0 or 2"; 605 } 606 } 607 608 return SPV_SUCCESS; 609 } 610 611 // Returns true if opcode is *ImageSparse*, false otherwise. 612 bool IsSparse(SpvOp opcode) { 613 switch (opcode) { 614 case SpvOpImageSparseSampleImplicitLod: 615 case SpvOpImageSparseSampleExplicitLod: 616 case SpvOpImageSparseSampleDrefImplicitLod: 617 case SpvOpImageSparseSampleDrefExplicitLod: 618 case SpvOpImageSparseSampleProjImplicitLod: 619 case SpvOpImageSparseSampleProjExplicitLod: 620 case SpvOpImageSparseSampleProjDrefImplicitLod: 621 case SpvOpImageSparseSampleProjDrefExplicitLod: 622 case SpvOpImageSparseFetch: 623 case SpvOpImageSparseGather: 624 case SpvOpImageSparseDrefGather: 625 case SpvOpImageSparseTexelsResident: 626 case SpvOpImageSparseRead: { 627 return true; 628 } 629 630 default: { return false; } 631 } 632 633 return false; 634 } 635 636 // Checks sparse image opcode result type and returns the second struct member. 637 // Returns inst.type_id for non-sparse image opcodes. 638 // Not valid for sparse image opcodes which do not return a struct. 639 spv_result_t GetActualResultType(ValidationState_t& _, const Instruction* inst, 640 uint32_t* actual_result_type) { 641 const SpvOp opcode = inst->opcode(); 642 643 if (IsSparse(opcode)) { 644 const Instruction* const type_inst = _.FindDef(inst->type_id()); 645 assert(type_inst); 646 647 if (!type_inst || type_inst->opcode() != SpvOpTypeStruct) { 648 return _.diag(SPV_ERROR_INVALID_DATA, inst) 649 << "Expected Result Type to be OpTypeStruct"; 650 } 651 652 if (type_inst->words().size() != 4 || 653 !_.IsIntScalarType(type_inst->word(2))) { 654 return _.diag(SPV_ERROR_INVALID_DATA, inst) 655 << "Expected Result Type to be a struct containing an int " 656 "scalar and a texel"; 657 } 658 659 *actual_result_type = type_inst->word(3); 660 } else { 661 *actual_result_type = inst->type_id(); 662 } 663 664 return SPV_SUCCESS; 665 } 666 667 // Returns a string describing actual result type of an opcode. 668 // Not valid for sparse image opcodes which do not return a struct. 669 const char* GetActualResultTypeStr(SpvOp opcode) { 670 if (IsSparse(opcode)) return "Result Type's second member"; 671 return "Result Type"; 672 } 673 674 spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { 675 assert(inst->type_id() == 0); 676 677 ImageTypeInfo info; 678 if (!GetImageTypeInfo(_, inst->word(1), &info)) { 679 return _.diag(SPV_ERROR_INVALID_DATA, inst) 680 << "Corrupt image type definition"; 681 } 682 683 if (spvIsVulkanEnv(_.context()->target_env)) { 684 if ((!_.IsFloatScalarType(info.sampled_type) && 685 !_.IsIntScalarType(info.sampled_type)) || 686 32 != _.GetBitWidth(info.sampled_type)) { 687 return _.diag(SPV_ERROR_INVALID_DATA, inst) 688 << "Expected Sampled Type to be a 32-bit int or float " 689 "scalar type for Vulkan environment"; 690 } 691 } else { 692 const SpvOp sampled_type_opcode = _.GetIdOpcode(info.sampled_type); 693 if (sampled_type_opcode != SpvOpTypeVoid && 694 sampled_type_opcode != SpvOpTypeInt && 695 sampled_type_opcode != SpvOpTypeFloat) { 696 return _.diag(SPV_ERROR_INVALID_DATA, inst) 697 << "Expected Sampled Type to be either void or" 698 << " numerical scalar type"; 699 } 700 } 701 702 // Dim is checked elsewhere. 703 704 if (info.depth > 2) { 705 return _.diag(SPV_ERROR_INVALID_DATA, inst) 706 << "Invalid Depth " << info.depth << " (must be 0, 1 or 2)"; 707 } 708 709 if (info.arrayed > 1) { 710 return _.diag(SPV_ERROR_INVALID_DATA, inst) 711 << "Invalid Arrayed " << info.arrayed << " (must be 0 or 1)"; 712 } 713 714 if (info.multisampled > 1) { 715 return _.diag(SPV_ERROR_INVALID_DATA, inst) 716 << "Invalid MS " << info.multisampled << " (must be 0 or 1)"; 717 } 718 719 if (info.sampled > 2) { 720 return _.diag(SPV_ERROR_INVALID_DATA, inst) 721 << "Invalid Sampled " << info.sampled << " (must be 0, 1 or 2)"; 722 } 723 724 if (info.dim == SpvDimSubpassData) { 725 if (info.sampled != 2) { 726 return _.diag(SPV_ERROR_INVALID_DATA, inst) 727 << "Dim SubpassData requires Sampled to be 2"; 728 } 729 730 if (info.format != SpvImageFormatUnknown) { 731 return _.diag(SPV_ERROR_INVALID_DATA, inst) 732 << "Dim SubpassData requires format Unknown"; 733 } 734 } 735 736 // Format and Access Qualifier are checked elsewhere. 737 738 return SPV_SUCCESS; 739 } 740 741 spv_result_t ValidateTypeSampledImage(ValidationState_t& _, 742 const Instruction* inst) { 743 const uint32_t image_type = inst->word(2); 744 if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { 745 return _.diag(SPV_ERROR_INVALID_DATA, inst) 746 << "Expected Image to be of type OpTypeImage"; 747 } 748 return SPV_SUCCESS; 749 } 750 751 spv_result_t ValidateSampledImage(ValidationState_t& _, 752 const Instruction* inst) { 753 if (_.GetIdOpcode(inst->type_id()) != SpvOpTypeSampledImage) { 754 return _.diag(SPV_ERROR_INVALID_DATA, inst) 755 << "Expected Result Type to be OpTypeSampledImage."; 756 } 757 758 const uint32_t image_type = _.GetOperandTypeId(inst, 2); 759 if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { 760 return _.diag(SPV_ERROR_INVALID_DATA, inst) 761 << "Expected Image to be of type OpTypeImage."; 762 } 763 764 ImageTypeInfo info; 765 if (!GetImageTypeInfo(_, image_type, &info)) { 766 return _.diag(SPV_ERROR_INVALID_DATA, inst) 767 << "Corrupt image type definition"; 768 } 769 770 // TODO(atgoo (at) github.com) Check compatibility of result type and received 771 // image. 772 773 if (spvIsVulkanEnv(_.context()->target_env)) { 774 if (info.sampled != 1) { 775 return _.diag(SPV_ERROR_INVALID_DATA, inst) 776 << "Expected Image 'Sampled' parameter to be 1 " 777 << "for Vulkan environment."; 778 } 779 } else { 780 if (info.sampled != 0 && info.sampled != 1) { 781 return _.diag(SPV_ERROR_INVALID_DATA, inst) 782 << "Expected Image 'Sampled' parameter to be 0 or 1"; 783 } 784 } 785 786 if (info.dim == SpvDimSubpassData) { 787 return _.diag(SPV_ERROR_INVALID_DATA, inst) 788 << "Expected Image 'Dim' parameter to be not SubpassData."; 789 } 790 791 if (_.GetIdOpcode(_.GetOperandTypeId(inst, 3)) != SpvOpTypeSampler) { 792 return _.diag(SPV_ERROR_INVALID_DATA, inst) 793 << "Expected Sampler to be of type OpTypeSampler"; 794 } 795 796 // We need to validate 2 things: 797 // * All OpSampledImage instructions must be in the same block in which their 798 // Result <id> are consumed. 799 // * Result <id> from OpSampledImage instructions must not appear as operands 800 // to OpPhi instructions or OpSelect instructions, or any instructions other 801 // than the image lookup and query instructions specified to take an operand 802 // whose type is OpTypeSampledImage. 803 std::vector<uint32_t> consumers = _.getSampledImageConsumers(inst->id()); 804 if (!consumers.empty()) { 805 for (auto consumer_id : consumers) { 806 const auto consumer_instr = _.FindDef(consumer_id); 807 const auto consumer_opcode = consumer_instr->opcode(); 808 if (consumer_instr->block() != inst->block()) { 809 return _.diag(SPV_ERROR_INVALID_ID, inst) 810 << "All OpSampledImage instructions must be in the same block " 811 "in " 812 "which their Result <id> are consumed. OpSampledImage Result " 813 "Type <id> '" 814 << _.getIdName(inst->id()) 815 << "' has a consumer in a different basic " 816 "block. The consumer instruction <id> is '" 817 << _.getIdName(consumer_id) << "'."; 818 } 819 // TODO: The following check is incomplete. We should also check that the 820 // Sampled Image is not used by instructions that should not take 821 // SampledImage as an argument. We could find the list of valid 822 // instructions by scanning for "Sampled Image" in the operand description 823 // field in the grammar file. 824 if (consumer_opcode == SpvOpPhi || consumer_opcode == SpvOpSelect) { 825 return _.diag(SPV_ERROR_INVALID_ID, inst) 826 << "Result <id> from OpSampledImage instruction must not appear " 827 "as " 828 "operands of Op" 829 << spvOpcodeString(static_cast<SpvOp>(consumer_opcode)) << "." 830 << " Found result <id> '" << _.getIdName(inst->id()) 831 << "' as an operand of <id> '" << _.getIdName(consumer_id) 832 << "'."; 833 } 834 } 835 } 836 return SPV_SUCCESS; 837 } 838 839 spv_result_t ValidateImageTexelPointer(ValidationState_t& _, 840 const Instruction* inst) { 841 const auto result_type = _.FindDef(inst->type_id()); 842 if (result_type->opcode() != SpvOpTypePointer) { 843 return _.diag(SPV_ERROR_INVALID_DATA, inst) 844 << "Expected Result Type to be OpTypePointer"; 845 } 846 847 const auto storage_class = result_type->GetOperandAs<uint32_t>(1); 848 if (storage_class != SpvStorageClassImage) { 849 return _.diag(SPV_ERROR_INVALID_DATA, inst) 850 << "Expected Result Type to be OpTypePointer whose Storage Class " 851 "operand is Image"; 852 } 853 854 const auto ptr_type = result_type->GetOperandAs<uint32_t>(2); 855 const auto ptr_opcode = _.GetIdOpcode(ptr_type); 856 if (ptr_opcode != SpvOpTypeInt && ptr_opcode != SpvOpTypeFloat && 857 ptr_opcode != SpvOpTypeVoid) { 858 return _.diag(SPV_ERROR_INVALID_DATA, inst) 859 << "Expected Result Type to be OpTypePointer whose Type operand " 860 "must be a scalar numerical type or OpTypeVoid"; 861 } 862 863 const auto image_ptr = _.FindDef(_.GetOperandTypeId(inst, 2)); 864 if (!image_ptr || image_ptr->opcode() != SpvOpTypePointer) { 865 return _.diag(SPV_ERROR_INVALID_DATA, inst) 866 << "Expected Image to be OpTypePointer"; 867 } 868 869 const auto image_type = image_ptr->GetOperandAs<uint32_t>(2); 870 if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { 871 return _.diag(SPV_ERROR_INVALID_DATA, inst) 872 << "Expected Image to be OpTypePointer with Type OpTypeImage"; 873 } 874 875 ImageTypeInfo info; 876 if (!GetImageTypeInfo(_, image_type, &info)) { 877 return _.diag(SPV_ERROR_INVALID_DATA, inst) 878 << "Corrupt image type definition"; 879 } 880 881 if (info.sampled_type != ptr_type) { 882 return _.diag(SPV_ERROR_INVALID_DATA, inst) 883 << "Expected Image 'Sampled Type' to be the same as the Type " 884 "pointed to by Result Type"; 885 } 886 887 if (info.dim == SpvDimSubpassData) { 888 return _.diag(SPV_ERROR_INVALID_DATA, inst) 889 << "Image Dim SubpassData cannot be used with OpImageTexelPointer"; 890 } 891 892 const uint32_t coord_type = _.GetOperandTypeId(inst, 3); 893 if (!coord_type || !_.IsIntScalarOrVectorType(coord_type)) { 894 return _.diag(SPV_ERROR_INVALID_DATA, inst) 895 << "Expected Coordinate to be integer scalar or vector"; 896 } 897 898 uint32_t expected_coord_size = 0; 899 if (info.arrayed == 0) { 900 expected_coord_size = GetPlaneCoordSize(info); 901 } else if (info.arrayed == 1) { 902 switch (info.dim) { 903 case SpvDim1D: 904 expected_coord_size = 2; 905 break; 906 case SpvDimCube: 907 case SpvDim2D: 908 expected_coord_size = 3; 909 break; 910 default: 911 return _.diag(SPV_ERROR_INVALID_DATA, inst) 912 << "Expected Image 'Dim' must be one of 1D, 2D, or Cube when " 913 "Arrayed is 1"; 914 break; 915 } 916 } 917 918 const uint32_t actual_coord_size = _.GetDimension(coord_type); 919 if (expected_coord_size != actual_coord_size) { 920 return _.diag(SPV_ERROR_INVALID_DATA, inst) 921 << "Expected Coordinate to have " << expected_coord_size 922 << " components, but given " << actual_coord_size; 923 } 924 925 const uint32_t sample_type = _.GetOperandTypeId(inst, 4); 926 if (!sample_type || !_.IsIntScalarType(sample_type)) { 927 return _.diag(SPV_ERROR_INVALID_DATA, inst) 928 << "Expected Sample to be integer scalar"; 929 } 930 931 if (info.multisampled == 0) { 932 uint64_t ms = 0; 933 if (!_.GetConstantValUint64(inst->GetOperandAs<uint32_t>(4), &ms) || 934 ms != 0) { 935 return _.diag(SPV_ERROR_INVALID_DATA, inst) 936 << "Expected Sample for Image with MS 0 to be a valid <id> for " 937 "the value 0"; 938 } 939 } 940 return SPV_SUCCESS; 941 } 942 943 spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) { 944 const SpvOp opcode = inst->opcode(); 945 uint32_t actual_result_type = 0; 946 if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) { 947 return error; 948 } 949 950 if (!_.IsIntVectorType(actual_result_type) && 951 !_.IsFloatVectorType(actual_result_type)) { 952 return _.diag(SPV_ERROR_INVALID_DATA, inst) 953 << "Expected " << GetActualResultTypeStr(opcode) 954 << " to be int or float vector type"; 955 } 956 957 if (_.GetDimension(actual_result_type) != 4) { 958 return _.diag(SPV_ERROR_INVALID_DATA, inst) 959 << "Expected " << GetActualResultTypeStr(opcode) 960 << " to have 4 components"; 961 } 962 963 const uint32_t image_type = _.GetOperandTypeId(inst, 2); 964 if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) { 965 return _.diag(SPV_ERROR_INVALID_DATA, inst) 966 << "Expected Sampled Image to be of type OpTypeSampledImage"; 967 } 968 969 ImageTypeInfo info; 970 if (!GetImageTypeInfo(_, image_type, &info)) { 971 return _.diag(SPV_ERROR_INVALID_DATA, inst) 972 << "Corrupt image type definition"; 973 } 974 975 if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result; 976 977 if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { 978 const uint32_t texel_component_type = 979 _.GetComponentType(actual_result_type); 980 if (texel_component_type != info.sampled_type) { 981 return _.diag(SPV_ERROR_INVALID_DATA, inst) 982 << "Expected Image 'Sampled Type' to be the same as " 983 << GetActualResultTypeStr(opcode) << " components"; 984 } 985 } 986 987 const uint32_t coord_type = _.GetOperandTypeId(inst, 3); 988 if ((opcode == SpvOpImageSampleExplicitLod || 989 opcode == SpvOpImageSparseSampleExplicitLod) && 990 _.HasCapability(SpvCapabilityKernel)) { 991 if (!_.IsFloatScalarOrVectorType(coord_type) && 992 !_.IsIntScalarOrVectorType(coord_type)) { 993 return _.diag(SPV_ERROR_INVALID_DATA, inst) 994 << "Expected Coordinate to be int or float scalar or vector"; 995 } 996 } else { 997 if (!_.IsFloatScalarOrVectorType(coord_type)) { 998 return _.diag(SPV_ERROR_INVALID_DATA, inst) 999 << "Expected Coordinate to be float scalar or vector"; 1000 } 1001 } 1002 1003 const uint32_t min_coord_size = GetMinCoordSize(opcode, info); 1004 const uint32_t actual_coord_size = _.GetDimension(coord_type); 1005 if (min_coord_size > actual_coord_size) { 1006 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1007 << "Expected Coordinate to have at least " << min_coord_size 1008 << " components, but given only " << actual_coord_size; 1009 } 1010 1011 if (inst->words().size() <= 5) { 1012 assert(IsImplicitLod(opcode)); 1013 return SPV_SUCCESS; 1014 } 1015 1016 const uint32_t mask = inst->word(5); 1017 if (spv_result_t result = 1018 ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) 1019 return result; 1020 1021 return SPV_SUCCESS; 1022 } 1023 1024 spv_result_t ValidateImageDrefLod(ValidationState_t& _, 1025 const Instruction* inst) { 1026 const SpvOp opcode = inst->opcode(); 1027 uint32_t actual_result_type = 0; 1028 if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) { 1029 return error; 1030 } 1031 1032 if (!_.IsIntScalarType(actual_result_type) && 1033 !_.IsFloatScalarType(actual_result_type)) { 1034 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1035 << "Expected " << GetActualResultTypeStr(opcode) 1036 << " to be int or float scalar type"; 1037 } 1038 1039 const uint32_t image_type = _.GetOperandTypeId(inst, 2); 1040 if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) { 1041 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1042 << "Expected Sampled Image to be of type OpTypeSampledImage"; 1043 } 1044 1045 ImageTypeInfo info; 1046 if (!GetImageTypeInfo(_, image_type, &info)) { 1047 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1048 << "Corrupt image type definition"; 1049 } 1050 1051 if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result; 1052 1053 if (actual_result_type != info.sampled_type) { 1054 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1055 << "Expected Image 'Sampled Type' to be the same as " 1056 << GetActualResultTypeStr(opcode); 1057 } 1058 1059 const uint32_t coord_type = _.GetOperandTypeId(inst, 3); 1060 if (!_.IsFloatScalarOrVectorType(coord_type)) { 1061 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1062 << "Expected Coordinate to be float scalar or vector"; 1063 } 1064 1065 const uint32_t min_coord_size = GetMinCoordSize(opcode, info); 1066 const uint32_t actual_coord_size = _.GetDimension(coord_type); 1067 if (min_coord_size > actual_coord_size) { 1068 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1069 << "Expected Coordinate to have at least " << min_coord_size 1070 << " components, but given only " << actual_coord_size; 1071 } 1072 1073 const uint32_t dref_type = _.GetOperandTypeId(inst, 4); 1074 if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) { 1075 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1076 << "Expected Dref to be of 32-bit float type"; 1077 } 1078 1079 if (inst->words().size() <= 6) { 1080 assert(IsImplicitLod(opcode)); 1081 return SPV_SUCCESS; 1082 } 1083 1084 const uint32_t mask = inst->word(6); 1085 if (spv_result_t result = 1086 ValidateImageOperands(_, inst, info, mask, /* word_index = */ 7)) 1087 return result; 1088 1089 return SPV_SUCCESS; 1090 } 1091 1092 spv_result_t ValidateImageFetch(ValidationState_t& _, const Instruction* inst) { 1093 uint32_t actual_result_type = 0; 1094 if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) { 1095 return error; 1096 } 1097 1098 const SpvOp opcode = inst->opcode(); 1099 if (!_.IsIntVectorType(actual_result_type) && 1100 !_.IsFloatVectorType(actual_result_type)) { 1101 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1102 << "Expected " << GetActualResultTypeStr(opcode) 1103 << " to be int or float vector type"; 1104 } 1105 1106 if (_.GetDimension(actual_result_type) != 4) { 1107 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1108 << "Expected " << GetActualResultTypeStr(opcode) 1109 << " to have 4 components"; 1110 } 1111 1112 const uint32_t image_type = _.GetOperandTypeId(inst, 2); 1113 if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { 1114 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1115 << "Expected Image to be of type OpTypeImage"; 1116 } 1117 1118 ImageTypeInfo info; 1119 if (!GetImageTypeInfo(_, image_type, &info)) { 1120 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1121 << "Corrupt image type definition"; 1122 } 1123 1124 if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { 1125 const uint32_t result_component_type = 1126 _.GetComponentType(actual_result_type); 1127 if (result_component_type != info.sampled_type) { 1128 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1129 << "Expected Image 'Sampled Type' to be the same as " 1130 << GetActualResultTypeStr(opcode) << " components"; 1131 } 1132 } 1133 1134 if (info.dim == SpvDimCube) { 1135 return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Image 'Dim' cannot be Cube"; 1136 } 1137 1138 if (info.sampled != 1) { 1139 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1140 << "Expected Image 'Sampled' parameter to be 1"; 1141 } 1142 1143 const uint32_t coord_type = _.GetOperandTypeId(inst, 3); 1144 if (!_.IsIntScalarOrVectorType(coord_type)) { 1145 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1146 << "Expected Coordinate to be int scalar or vector"; 1147 } 1148 1149 const uint32_t min_coord_size = GetMinCoordSize(opcode, info); 1150 const uint32_t actual_coord_size = _.GetDimension(coord_type); 1151 if (min_coord_size > actual_coord_size) { 1152 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1153 << "Expected Coordinate to have at least " << min_coord_size 1154 << " components, but given only " << actual_coord_size; 1155 } 1156 1157 if (inst->words().size() <= 5) return SPV_SUCCESS; 1158 1159 const uint32_t mask = inst->word(5); 1160 if (spv_result_t result = 1161 ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) 1162 return result; 1163 1164 return SPV_SUCCESS; 1165 } 1166 1167 spv_result_t ValidateImageGather(ValidationState_t& _, 1168 const Instruction* inst) { 1169 uint32_t actual_result_type = 0; 1170 if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) 1171 return error; 1172 1173 const SpvOp opcode = inst->opcode(); 1174 if (!_.IsIntVectorType(actual_result_type) && 1175 !_.IsFloatVectorType(actual_result_type)) { 1176 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1177 << "Expected " << GetActualResultTypeStr(opcode) 1178 << " to be int or float vector type"; 1179 } 1180 1181 if (_.GetDimension(actual_result_type) != 4) { 1182 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1183 << "Expected " << GetActualResultTypeStr(opcode) 1184 << " to have 4 components"; 1185 } 1186 1187 const uint32_t image_type = _.GetOperandTypeId(inst, 2); 1188 if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) { 1189 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1190 << "Expected Sampled Image to be of type OpTypeSampledImage"; 1191 } 1192 1193 ImageTypeInfo info; 1194 if (!GetImageTypeInfo(_, image_type, &info)) { 1195 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1196 << "Corrupt image type definition"; 1197 } 1198 1199 if (opcode == SpvOpImageDrefGather || opcode == SpvOpImageSparseDrefGather || 1200 _.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { 1201 const uint32_t result_component_type = 1202 _.GetComponentType(actual_result_type); 1203 if (result_component_type != info.sampled_type) { 1204 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1205 << "Expected Image 'Sampled Type' to be the same as " 1206 << GetActualResultTypeStr(opcode) << " components"; 1207 } 1208 } 1209 1210 if (info.dim != SpvDim2D && info.dim != SpvDimCube && 1211 info.dim != SpvDimRect) { 1212 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1213 << "Expected Image 'Dim' cannot be Cube"; 1214 } 1215 1216 const uint32_t coord_type = _.GetOperandTypeId(inst, 3); 1217 if (!_.IsFloatScalarOrVectorType(coord_type)) { 1218 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1219 << "Expected Coordinate to be float scalar or vector"; 1220 } 1221 1222 const uint32_t min_coord_size = GetMinCoordSize(opcode, info); 1223 const uint32_t actual_coord_size = _.GetDimension(coord_type); 1224 if (min_coord_size > actual_coord_size) { 1225 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1226 << "Expected Coordinate to have at least " << min_coord_size 1227 << " components, but given only " << actual_coord_size; 1228 } 1229 1230 if (opcode == SpvOpImageGather || opcode == SpvOpImageSparseGather) { 1231 const uint32_t component_index_type = _.GetOperandTypeId(inst, 4); 1232 if (!_.IsIntScalarType(component_index_type) || 1233 _.GetBitWidth(component_index_type) != 32) { 1234 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1235 << "Expected Component to be 32-bit int scalar"; 1236 } 1237 } else { 1238 assert(opcode == SpvOpImageDrefGather || 1239 opcode == SpvOpImageSparseDrefGather); 1240 const uint32_t dref_type = _.GetOperandTypeId(inst, 4); 1241 if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) { 1242 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1243 << "Expected Dref to be of 32-bit float type"; 1244 } 1245 } 1246 1247 if (inst->words().size() <= 6) return SPV_SUCCESS; 1248 1249 const uint32_t mask = inst->word(6); 1250 if (spv_result_t result = 1251 ValidateImageOperands(_, inst, info, mask, /* word_index = */ 7)) 1252 return result; 1253 1254 return SPV_SUCCESS; 1255 } 1256 1257 spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) { 1258 const SpvOp opcode = inst->opcode(); 1259 uint32_t actual_result_type = 0; 1260 if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) { 1261 return error; 1262 } 1263 1264 if (!_.IsIntScalarOrVectorType(actual_result_type) && 1265 !_.IsFloatScalarOrVectorType(actual_result_type)) { 1266 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1267 << "Expected " << GetActualResultTypeStr(opcode) 1268 << " to be int or float scalar or vector type"; 1269 } 1270 1271 #if 0 1272 // TODO(atgoo (at) github.com) Disabled until the spec is clarified. 1273 if (_.GetDimension(actual_result_type) != 4) { 1274 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1275 << "Expected " << GetActualResultTypeStr(opcode) 1276 << " to have 4 components"; 1277 } 1278 #endif 1279 1280 const uint32_t image_type = _.GetOperandTypeId(inst, 2); 1281 if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { 1282 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1283 << "Expected Image to be of type OpTypeImage"; 1284 } 1285 1286 ImageTypeInfo info; 1287 if (!GetImageTypeInfo(_, image_type, &info)) { 1288 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1289 << "Corrupt image type definition"; 1290 } 1291 1292 if (info.dim == SpvDimSubpassData) { 1293 if (opcode == SpvOpImageSparseRead) { 1294 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1295 << "Image Dim SubpassData cannot be used with ImageSparseRead"; 1296 } 1297 1298 _.function(inst->function()->id()) 1299 ->RegisterExecutionModelLimitation( 1300 SpvExecutionModelFragment, 1301 std::string("Dim SubpassData requires Fragment execution model: ") + 1302 spvOpcodeString(opcode)); 1303 } 1304 1305 if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { 1306 const uint32_t result_component_type = 1307 _.GetComponentType(actual_result_type); 1308 if (result_component_type != info.sampled_type) { 1309 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1310 << "Expected Image 'Sampled Type' to be the same as " 1311 << GetActualResultTypeStr(opcode) << " components"; 1312 } 1313 } 1314 1315 if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result; 1316 1317 const uint32_t coord_type = _.GetOperandTypeId(inst, 3); 1318 if (!_.IsIntScalarOrVectorType(coord_type)) { 1319 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1320 << "Expected Coordinate to be int scalar or vector"; 1321 } 1322 1323 const uint32_t min_coord_size = GetMinCoordSize(opcode, info); 1324 const uint32_t actual_coord_size = _.GetDimension(coord_type); 1325 if (min_coord_size > actual_coord_size) { 1326 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1327 << "Expected Coordinate to have at least " << min_coord_size 1328 << " components, but given only " << actual_coord_size; 1329 } 1330 1331 if (info.format == SpvImageFormatUnknown && info.dim != SpvDimSubpassData && 1332 !_.HasCapability(SpvCapabilityStorageImageReadWithoutFormat)) { 1333 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1334 << "Capability StorageImageReadWithoutFormat is required to " 1335 << "read storage image"; 1336 } 1337 1338 if (inst->words().size() <= 5) return SPV_SUCCESS; 1339 1340 const uint32_t mask = inst->word(5); 1341 if (spv_result_t result = 1342 ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) 1343 return result; 1344 1345 return SPV_SUCCESS; 1346 } 1347 1348 spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) { 1349 const uint32_t image_type = _.GetOperandTypeId(inst, 0); 1350 if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { 1351 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1352 << "Expected Image to be of type OpTypeImage"; 1353 } 1354 1355 ImageTypeInfo info; 1356 if (!GetImageTypeInfo(_, image_type, &info)) { 1357 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1358 << "Corrupt image type definition"; 1359 } 1360 1361 if (info.dim == SpvDimSubpassData) { 1362 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1363 << "Image 'Dim' cannot be SubpassData"; 1364 } 1365 1366 if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result; 1367 1368 const uint32_t coord_type = _.GetOperandTypeId(inst, 1); 1369 if (!_.IsIntScalarOrVectorType(coord_type)) { 1370 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1371 << "Expected Coordinate to be int scalar or vector"; 1372 } 1373 1374 const uint32_t min_coord_size = GetMinCoordSize(inst->opcode(), info); 1375 const uint32_t actual_coord_size = _.GetDimension(coord_type); 1376 if (min_coord_size > actual_coord_size) { 1377 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1378 << "Expected Coordinate to have at least " << min_coord_size 1379 << " components, but given only " << actual_coord_size; 1380 } 1381 1382 // TODO(atgoo (at) github.com) The spec doesn't explicitely say what the type 1383 // of texel should be. 1384 const uint32_t texel_type = _.GetOperandTypeId(inst, 2); 1385 if (!_.IsIntScalarOrVectorType(texel_type) && 1386 !_.IsFloatScalarOrVectorType(texel_type)) { 1387 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1388 << "Expected Texel to be int or float vector or scalar"; 1389 } 1390 1391 #if 0 1392 // TODO: See above. 1393 if (_.GetDimension(texel_type) != 4) { 1394 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1395 << "Expected Texel to have 4 components"; 1396 } 1397 #endif 1398 1399 if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { 1400 const uint32_t texel_component_type = _.GetComponentType(texel_type); 1401 if (texel_component_type != info.sampled_type) { 1402 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1403 << "Expected Image 'Sampled Type' to be the same as Texel " 1404 << "components"; 1405 } 1406 } 1407 1408 if (info.format == SpvImageFormatUnknown && info.dim != SpvDimSubpassData && 1409 !_.HasCapability(SpvCapabilityStorageImageWriteWithoutFormat)) { 1410 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1411 << "Capability StorageImageWriteWithoutFormat is required to " 1412 "write " 1413 << "to storage image"; 1414 } 1415 1416 if (inst->words().size() <= 4) return SPV_SUCCESS; 1417 1418 const uint32_t mask = inst->word(4); 1419 if (spv_result_t result = 1420 ValidateImageOperands(_, inst, info, mask, /* word_index = */ 5)) 1421 return result; 1422 1423 return SPV_SUCCESS; 1424 } 1425 1426 spv_result_t ValidateImage(ValidationState_t& _, const Instruction* inst) { 1427 const uint32_t result_type = inst->type_id(); 1428 if (_.GetIdOpcode(result_type) != SpvOpTypeImage) { 1429 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1430 << "Expected Result Type to be OpTypeImage"; 1431 } 1432 1433 const uint32_t sampled_image_type = _.GetOperandTypeId(inst, 2); 1434 const Instruction* sampled_image_type_inst = _.FindDef(sampled_image_type); 1435 assert(sampled_image_type_inst); 1436 1437 if (sampled_image_type_inst->opcode() != SpvOpTypeSampledImage) { 1438 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1439 << "Expected Sample Image to be of type OpTypeSampleImage"; 1440 } 1441 1442 if (sampled_image_type_inst->word(2) != result_type) { 1443 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1444 << "Expected Sample Image image type to be equal to Result Type"; 1445 } 1446 1447 return SPV_SUCCESS; 1448 } 1449 1450 spv_result_t ValidateImageQuerySizeLod(ValidationState_t& _, 1451 const Instruction* inst) { 1452 const uint32_t result_type = inst->type_id(); 1453 if (!_.IsIntScalarOrVectorType(result_type)) { 1454 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1455 << "Expected Result Type to be int scalar or vector type"; 1456 } 1457 1458 const uint32_t image_type = _.GetOperandTypeId(inst, 2); 1459 if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { 1460 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1461 << "Expected Image to be of type OpTypeImage"; 1462 } 1463 1464 ImageTypeInfo info; 1465 if (!GetImageTypeInfo(_, image_type, &info)) { 1466 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1467 << "Corrupt image type definition"; 1468 } 1469 1470 uint32_t expected_num_components = info.arrayed; 1471 switch (info.dim) { 1472 case SpvDim1D: 1473 expected_num_components += 1; 1474 break; 1475 case SpvDim2D: 1476 case SpvDimCube: 1477 expected_num_components += 2; 1478 break; 1479 case SpvDim3D: 1480 expected_num_components += 3; 1481 break; 1482 default: 1483 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1484 << "Image 'Dim' must be 1D, 2D, 3D or Cube"; 1485 } 1486 1487 if (info.multisampled != 0) { 1488 return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Image 'MS' must be 0"; 1489 } 1490 1491 uint32_t result_num_components = _.GetDimension(result_type); 1492 if (result_num_components != expected_num_components) { 1493 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1494 << "Result Type has " << result_num_components << " components, " 1495 << "but " << expected_num_components << " expected"; 1496 } 1497 1498 const uint32_t lod_type = _.GetOperandTypeId(inst, 3); 1499 if (!_.IsIntScalarType(lod_type)) { 1500 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1501 << "Expected Level of Detail to be int scalar"; 1502 } 1503 return SPV_SUCCESS; 1504 } 1505 1506 spv_result_t ValidateImageQuerySize(ValidationState_t& _, 1507 const Instruction* inst) { 1508 const uint32_t result_type = inst->type_id(); 1509 if (!_.IsIntScalarOrVectorType(result_type)) { 1510 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1511 << "Expected Result Type to be int scalar or vector type"; 1512 } 1513 1514 const uint32_t image_type = _.GetOperandTypeId(inst, 2); 1515 if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { 1516 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1517 << "Expected Image to be of type OpTypeImage"; 1518 } 1519 1520 ImageTypeInfo info; 1521 if (!GetImageTypeInfo(_, image_type, &info)) { 1522 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1523 << "Corrupt image type definition"; 1524 } 1525 1526 uint32_t expected_num_components = info.arrayed; 1527 switch (info.dim) { 1528 case SpvDim1D: 1529 case SpvDimBuffer: 1530 expected_num_components += 1; 1531 break; 1532 case SpvDim2D: 1533 case SpvDimCube: 1534 case SpvDimRect: 1535 expected_num_components += 2; 1536 break; 1537 case SpvDim3D: 1538 expected_num_components += 3; 1539 break; 1540 default: 1541 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1542 << "Image 'Dim' must be 1D, Buffer, 2D, Cube, 3D or Rect"; 1543 } 1544 1545 if (info.dim == SpvDim1D || info.dim == SpvDim2D || info.dim == SpvDim3D || 1546 info.dim == SpvDimCube) { 1547 if (info.multisampled != 1 && info.sampled != 0 && info.sampled != 2) { 1548 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1549 << "Image must have either 'MS'=1 or 'Sampled'=0 or 'Sampled'=2"; 1550 } 1551 } 1552 1553 uint32_t result_num_components = _.GetDimension(result_type); 1554 if (result_num_components != expected_num_components) { 1555 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1556 << "Result Type has " << result_num_components << " components, " 1557 << "but " << expected_num_components << " expected"; 1558 } 1559 1560 return SPV_SUCCESS; 1561 } 1562 1563 spv_result_t ValidateImageQueryFormatOrOrder(ValidationState_t& _, 1564 const Instruction* inst) { 1565 if (!_.IsIntScalarType(inst->type_id())) { 1566 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1567 << "Expected Result Type to be int scalar type"; 1568 } 1569 1570 if (_.GetIdOpcode(_.GetOperandTypeId(inst, 2)) != SpvOpTypeImage) { 1571 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1572 << "Expected operand to be of type OpTypeImage"; 1573 } 1574 return SPV_SUCCESS; 1575 } 1576 1577 spv_result_t ValidateImageQueryLod(ValidationState_t& _, 1578 const Instruction* inst) { 1579 _.function(inst->function()->id()) 1580 ->RegisterExecutionModelLimitation( 1581 SpvExecutionModelFragment, 1582 "OpImageQueryLod requires Fragment execution model"); 1583 1584 const uint32_t result_type = inst->type_id(); 1585 if (!_.IsFloatVectorType(result_type)) { 1586 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1587 << "Expected Result Type to be float vector type"; 1588 } 1589 1590 if (_.GetDimension(result_type) != 2) { 1591 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1592 << "Expected Result Type to have 2 components"; 1593 } 1594 1595 const uint32_t image_type = _.GetOperandTypeId(inst, 2); 1596 if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) { 1597 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1598 << "Expected Image operand to be of type OpTypeSampledImage"; 1599 } 1600 1601 ImageTypeInfo info; 1602 if (!GetImageTypeInfo(_, image_type, &info)) { 1603 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1604 << "Corrupt image type definition"; 1605 } 1606 1607 if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D && 1608 info.dim != SpvDimCube) { 1609 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1610 << "Image 'Dim' must be 1D, 2D, 3D or Cube"; 1611 } 1612 1613 const uint32_t coord_type = _.GetOperandTypeId(inst, 3); 1614 if (_.HasCapability(SpvCapabilityKernel)) { 1615 if (!_.IsFloatScalarOrVectorType(coord_type) && 1616 !_.IsIntScalarOrVectorType(coord_type)) { 1617 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1618 << "Expected Coordinate to be int or float scalar or vector"; 1619 } 1620 } else { 1621 if (!_.IsFloatScalarOrVectorType(coord_type)) { 1622 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1623 << "Expected Coordinate to be float scalar or vector"; 1624 } 1625 } 1626 1627 const uint32_t min_coord_size = GetPlaneCoordSize(info); 1628 const uint32_t actual_coord_size = _.GetDimension(coord_type); 1629 if (min_coord_size > actual_coord_size) { 1630 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1631 << "Expected Coordinate to have at least " << min_coord_size 1632 << " components, but given only " << actual_coord_size; 1633 } 1634 return SPV_SUCCESS; 1635 } 1636 1637 spv_result_t ValidateImageSparseLod(ValidationState_t& _, 1638 const Instruction* inst) { 1639 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1640 << "Instruction reserved for future use, use of this instruction " 1641 << "is invalid"; 1642 } 1643 1644 spv_result_t ValidateImageQueryLevelsOrSamples(ValidationState_t& _, 1645 const Instruction* inst) { 1646 if (!_.IsIntScalarType(inst->type_id())) { 1647 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1648 << "Expected Result Type to be int scalar type"; 1649 } 1650 1651 const uint32_t image_type = _.GetOperandTypeId(inst, 2); 1652 if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { 1653 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1654 << "Expected Image to be of type OpTypeImage"; 1655 } 1656 1657 ImageTypeInfo info; 1658 if (!GetImageTypeInfo(_, image_type, &info)) { 1659 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1660 << "Corrupt image type definition"; 1661 } 1662 1663 const SpvOp opcode = inst->opcode(); 1664 if (opcode == SpvOpImageQueryLevels) { 1665 if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D && 1666 info.dim != SpvDimCube) { 1667 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1668 << "Image 'Dim' must be 1D, 2D, 3D or Cube"; 1669 } 1670 } else { 1671 assert(opcode == SpvOpImageQuerySamples); 1672 if (info.dim != SpvDim2D) { 1673 return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Image 'Dim' must be 2D"; 1674 } 1675 1676 if (info.multisampled != 1) { 1677 return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Image 'MS' must be 1"; 1678 } 1679 } 1680 return SPV_SUCCESS; 1681 } 1682 1683 spv_result_t ValidateImageSparseTexelsResident(ValidationState_t& _, 1684 const Instruction* inst) { 1685 if (!_.IsBoolScalarType(inst->type_id())) { 1686 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1687 << "Expected Result Type to be bool scalar type"; 1688 } 1689 1690 const uint32_t resident_code_type = _.GetOperandTypeId(inst, 2); 1691 if (!_.IsIntScalarType(resident_code_type)) { 1692 return _.diag(SPV_ERROR_INVALID_DATA, inst) 1693 << "Expected Resident Code to be int scalar"; 1694 } 1695 1696 return SPV_SUCCESS; 1697 } 1698 1699 } // namespace 1700 1701 // Validates correctness of image instructions. 1702 spv_result_t ImagePass(ValidationState_t& _, const Instruction* inst) { 1703 const SpvOp opcode = inst->opcode(); 1704 if (IsImplicitLod(opcode)) { 1705 _.function(inst->function()->id()) 1706 ->RegisterExecutionModelLimitation( 1707 SpvExecutionModelFragment, 1708 "ImplicitLod instructions require Fragment execution model"); 1709 } 1710 1711 switch (opcode) { 1712 case SpvOpTypeImage: 1713 return ValidateTypeImage(_, inst); 1714 case SpvOpTypeSampledImage: 1715 return ValidateTypeSampledImage(_, inst); 1716 case SpvOpSampledImage: 1717 return ValidateSampledImage(_, inst); 1718 case SpvOpImageTexelPointer: 1719 return ValidateImageTexelPointer(_, inst); 1720 1721 case SpvOpImageSampleImplicitLod: 1722 case SpvOpImageSampleExplicitLod: 1723 case SpvOpImageSampleProjImplicitLod: 1724 case SpvOpImageSampleProjExplicitLod: 1725 case SpvOpImageSparseSampleImplicitLod: 1726 case SpvOpImageSparseSampleExplicitLod: 1727 return ValidateImageLod(_, inst); 1728 1729 case SpvOpImageSampleDrefImplicitLod: 1730 case SpvOpImageSampleDrefExplicitLod: 1731 case SpvOpImageSampleProjDrefImplicitLod: 1732 case SpvOpImageSampleProjDrefExplicitLod: 1733 case SpvOpImageSparseSampleDrefImplicitLod: 1734 case SpvOpImageSparseSampleDrefExplicitLod: 1735 return ValidateImageDrefLod(_, inst); 1736 1737 case SpvOpImageFetch: 1738 case SpvOpImageSparseFetch: 1739 return ValidateImageFetch(_, inst); 1740 1741 case SpvOpImageGather: 1742 case SpvOpImageDrefGather: 1743 case SpvOpImageSparseGather: 1744 case SpvOpImageSparseDrefGather: 1745 return ValidateImageGather(_, inst); 1746 1747 case SpvOpImageRead: 1748 case SpvOpImageSparseRead: 1749 return ValidateImageRead(_, inst); 1750 1751 case SpvOpImageWrite: 1752 return ValidateImageWrite(_, inst); 1753 1754 case SpvOpImage: 1755 return ValidateImage(_, inst); 1756 1757 case SpvOpImageQueryFormat: 1758 case SpvOpImageQueryOrder: 1759 return ValidateImageQueryFormatOrOrder(_, inst); 1760 1761 case SpvOpImageQuerySizeLod: 1762 return ValidateImageQuerySizeLod(_, inst); 1763 case SpvOpImageQuerySize: 1764 return ValidateImageQuerySize(_, inst); 1765 case SpvOpImageQueryLod: 1766 return ValidateImageQueryLod(_, inst); 1767 1768 case SpvOpImageQueryLevels: 1769 case SpvOpImageQuerySamples: 1770 return ValidateImageQueryLevelsOrSamples(_, inst); 1771 1772 case SpvOpImageSparseSampleProjImplicitLod: 1773 case SpvOpImageSparseSampleProjExplicitLod: 1774 case SpvOpImageSparseSampleProjDrefImplicitLod: 1775 case SpvOpImageSparseSampleProjDrefExplicitLod: 1776 return ValidateImageSparseLod(_, inst); 1777 1778 case SpvOpImageSparseTexelsResident: 1779 return ValidateImageSparseTexelsResident(_, inst); 1780 1781 default: 1782 break; 1783 } 1784 1785 return SPV_SUCCESS; 1786 } 1787 1788 } // namespace val 1789 } // namespace spvtools 1790