diff options
author | dan sinclair <dj2@everburning.com> | 2018-07-30 16:59:29 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-30 16:59:29 -0400 |
commit | dcb0dc21de290cd6beaf21d6d5d2c63ed20f759e (patch) | |
tree | 38c14a0accfd55c9cc41d84f59813e231ce3e4d7 /source/val | |
parent | 673483d6a7a66b20395febf554e1ca172a6e5284 (diff) |
Split ImagePass into individual methods. (#1742)
This CL splits the switch in ImagePass into individual validate
functions. The error messages have been updated to drop the
suffix/prefix of the opcode name since it will be displayed in the
disassembly.
Diffstat (limited to 'source/val')
-rw-r--r-- | source/val/validate_image.cpp | 1798 |
1 files changed, 856 insertions, 942 deletions
diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 4816b337..1b2dfe6b 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -216,8 +216,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (expected_num_image_operand_words != num_words - word_index) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Number of image operand ids doesn't correspond to the bit mask: " - << spvOpcodeString(opcode); + << "Number of image operand ids doesn't correspond to the bit mask"; } if (spvtools::utils::CountSetBits( @@ -225,7 +224,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, SpvImageOperandsConstOffsetsMask)) > 1) { return _.diag(SPV_ERROR_INVALID_DATA) << "Image Operands Offset, ConstOffset, ConstOffsets cannot be used " - << "together: " << spvOpcodeString(opcode); + << "together"; }; const bool is_implicit_lod = IsImplicitLod(opcode); @@ -236,29 +235,25 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (mask & SpvImageOperandsBiasMask) { if (!is_implicit_lod) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Image Operand Bias can only be used with ImplicitLod opcodes: " - << spvOpcodeString(opcode); + << "Image Operand Bias can only be used with ImplicitLod opcodes"; }; const uint32_t type_id = _.GetTypeId(inst->word(word_index++)); if (!_.IsFloatScalarType(type_id)) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image Operand Bias to be float scalar: " - << spvOpcodeString(opcode); + << "Expected Image Operand Bias to be float scalar"; } if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D && info.dim != SpvDimCube) { return _.diag(SPV_ERROR_INVALID_DATA) << "Image Operand Bias requires 'Dim' parameter to be 1D, 2D, 3D " - "or " - << "Cube: " << spvOpcodeString(opcode); + "or Cube"; } if (info.multisampled != 0) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Image Operand Bias requires 'MS' parameter to be 0: " - << spvOpcodeString(opcode); + << "Image Operand Bias requires 'MS' parameter to be 0"; } } @@ -267,14 +262,13 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, opcode != SpvOpImageSparseFetch) { return _.diag(SPV_ERROR_INVALID_DATA) << "Image Operand Lod can only be used with ExplicitLod opcodes " - << "and OpImageFetch: " << spvOpcodeString(opcode); + << "and OpImageFetch"; }; if (mask & SpvImageOperandsGradMask) { return _.diag(SPV_ERROR_INVALID_DATA) << "Image Operand bits Lod and Grad cannot be set at the same " - "time: " - << spvOpcodeString(opcode); + "time"; } const uint32_t type_id = _.GetTypeId(inst->word(word_index++)); @@ -282,7 +276,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (!_.IsFloatScalarType(type_id)) { return _.diag(SPV_ERROR_INVALID_DATA) << "Expected Image Operand Lod to be float scalar when used " - << "with ExplicitLod: " << spvOpcodeString(opcode); + << "with ExplicitLod"; } } else { if (!_.IsIntScalarType(type_id)) { @@ -296,22 +290,19 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, info.dim != SpvDimCube) { return _.diag(SPV_ERROR_INVALID_DATA) << "Image Operand Lod requires 'Dim' parameter to be 1D, 2D, 3D " - "or " - << "Cube: " << spvOpcodeString(opcode); + "or Cube"; } if (info.multisampled != 0) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Image Operand Lod requires 'MS' parameter to be 0: " - << spvOpcodeString(opcode); + << "Image Operand Lod requires 'MS' parameter to be 0"; } } if (mask & SpvImageOperandsGradMask) { if (!is_explicit_lod) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Image Operand Grad can only be used with ExplicitLod opcodes: " - << spvOpcodeString(opcode); + << "Image Operand Grad can only be used with ExplicitLod opcodes"; }; const uint32_t dx_type_id = _.GetTypeId(inst->word(word_index++)); @@ -320,7 +311,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, !_.IsFloatScalarOrVectorType(dy_type_id)) { return _.diag(SPV_ERROR_INVALID_DATA) << "Expected both Image Operand Grad ids to be float scalars or " - << "vectors: " << spvOpcodeString(opcode); + << "vectors"; } const uint32_t plane_size = GetPlaneCoordSize(info); @@ -329,21 +320,18 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (plane_size != dx_size) { return _.diag(SPV_ERROR_INVALID_DATA) << "Expected Image Operand Grad dx to have " << plane_size - << " components, but given " << dx_size << ": " - << spvOpcodeString(opcode); + << " components, but given " << dx_size; } if (plane_size != dy_size) { return _.diag(SPV_ERROR_INVALID_DATA) << "Expected Image Operand Grad dy to have " << plane_size - << " components, but given " << dy_size << ": " - << spvOpcodeString(opcode); + << " components, but given " << dy_size; } if (info.multisampled != 0) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Image Operand Grad requires 'MS' parameter to be 0: " - << spvOpcodeString(opcode); + << "Image Operand Grad requires 'MS' parameter to be 0"; } } @@ -351,8 +339,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (info.dim == SpvDimCube) { return _.diag(SPV_ERROR_INVALID_DATA) << "Image Operand ConstOffset cannot be used with Cube Image " - "'Dim': " - << spvOpcodeString(opcode); + "'Dim'"; } const uint32_t id = inst->word(word_index++); @@ -360,13 +347,12 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (!_.IsIntScalarOrVectorType(type_id)) { return _.diag(SPV_ERROR_INVALID_DATA) << "Expected Image Operand ConstOffset to be int scalar or " - << "vector: " << spvOpcodeString(opcode); + << "vector"; } if (!spvOpcodeIsConstant(_.GetIdOpcode(id))) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image Operand ConstOffset to be a const object: " - << spvOpcodeString(opcode); + << "Expected Image Operand ConstOffset to be a const object"; } const uint32_t plane_size = GetPlaneCoordSize(info); @@ -374,16 +360,14 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (plane_size != offset_size) { return _.diag(SPV_ERROR_INVALID_DATA) << "Expected Image Operand ConstOffset to have " << plane_size - << " components, but given " << offset_size << ": " - << spvOpcodeString(opcode); + << " components, but given " << offset_size; } } if (mask & SpvImageOperandsOffsetMask) { if (info.dim == SpvDimCube) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Image Operand Offset cannot be used with Cube Image 'Dim': " - << spvOpcodeString(opcode); + << "Image Operand Offset cannot be used with Cube Image 'Dim'"; } const uint32_t id = inst->word(word_index++); @@ -391,7 +375,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (!_.IsIntScalarOrVectorType(type_id)) { return _.diag(SPV_ERROR_INVALID_DATA) << "Expected Image Operand Offset to be int scalar or " - << "vector: " << spvOpcodeString(opcode); + << "vector"; } const uint32_t plane_size = GetPlaneCoordSize(info); @@ -399,8 +383,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (plane_size != offset_size) { return _.diag(SPV_ERROR_INVALID_DATA) << "Expected Image Operand Offset to have " << plane_size - << " components, but given " << offset_size << ": " - << spvOpcodeString(opcode); + << " components, but given " << offset_size; } } @@ -410,15 +393,13 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, opcode != SpvOpImageSparseDrefGather) { return _.diag(SPV_ERROR_INVALID_DATA) << "Image Operand ConstOffsets can only be used with " - "OpImageGather " - << "and OpImageDrefGather: " << spvOpcodeString(opcode); + "OpImageGather and OpImageDrefGather"; } if (info.dim == SpvDimCube) { return _.diag(SPV_ERROR_INVALID_DATA) << "Image Operand ConstOffsets cannot be used with Cube Image " - "'Dim': " - << spvOpcodeString(opcode); + "'Dim'"; } const uint32_t id = inst->word(word_index++); @@ -428,8 +409,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (type_inst->opcode() != SpvOpTypeArray) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image Operand ConstOffsets to be an array of size 4: " - << spvOpcodeString(opcode); + << "Expected Image Operand ConstOffsets to be an array of size 4"; } uint64_t array_size = 0; @@ -439,8 +419,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (array_size != 4) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image Operand ConstOffsets to be an array of size 4: " - << spvOpcodeString(opcode); + << "Expected Image Operand ConstOffsets to be an array of size 4"; } const uint32_t component_type = type_inst->word(2); @@ -448,14 +427,12 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, _.GetDimension(component_type) != 2) { return _.diag(SPV_ERROR_INVALID_DATA) << "Expected Image Operand ConstOffsets array componenets to be " - "int " - << "vectors of size 2: " << spvOpcodeString(opcode); + "int vectors of size 2"; } if (!spvOpcodeIsConstant(_.GetIdOpcode(id))) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image Operand ConstOffsets to be a const object: " - << spvOpcodeString(opcode); + << "Expected Image Operand ConstOffsets to be a const object"; } } @@ -466,20 +443,18 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, return _.diag(SPV_ERROR_INVALID_DATA) << "Image Operand Sample can only be used with OpImageFetch, " << "OpImageRead, OpImageWrite, OpImageSparseFetch and " - << "OpImageSparseRead: " << spvOpcodeString(opcode); + << "OpImageSparseRead"; } if (info.multisampled == 0) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Image Operand Sample requires non-zero 'MS' parameter: " - << spvOpcodeString(opcode); + << "Image Operand Sample requires non-zero 'MS' parameter"; } const uint32_t type_id = _.GetTypeId(inst->word(word_index++)); if (!_.IsIntScalarType(type_id)) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image Operand Sample to be int scalar: " - << spvOpcodeString(opcode); + << "Expected Image Operand Sample to be int scalar"; } } @@ -487,29 +462,25 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (!is_implicit_lod && !(mask & SpvImageOperandsGradMask)) { return _.diag(SPV_ERROR_INVALID_DATA) << "Image Operand MinLod can only be used with ImplicitLod " - << "opcodes or together with Image Operand Grad: " - << spvOpcodeString(opcode); + << "opcodes or together with Image Operand Grad"; }; const uint32_t type_id = _.GetTypeId(inst->word(word_index++)); if (!_.IsFloatScalarType(type_id)) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image Operand MinLod to be float scalar: " - << spvOpcodeString(opcode); + << "Expected Image Operand MinLod to be float scalar"; } if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D && info.dim != SpvDimCube) { return _.diag(SPV_ERROR_INVALID_DATA) << "Image Operand MinLod requires 'Dim' parameter to be 1D, 2D, " - "3D " - << "or Cube: " << spvOpcodeString(opcode); + "3D or Cube"; } if (info.multisampled != 0) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Image Operand MinLod requires 'MS' parameter to be 0: " - << spvOpcodeString(opcode); + << "Image Operand MinLod requires 'MS' parameter to be 0"; } } @@ -524,20 +495,17 @@ spv_result_t ValidateImageCommon(ValidationState_t& _, const Instruction* inst, if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D && info.dim != SpvDimRect) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Dim' parameter to be 1D, 2D, 3D or Rect: " - << spvOpcodeString(opcode); + << "Expected Image 'Dim' parameter to be 1D, 2D, 3D or Rect"; } if (info.multisampled != 0) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Image Image 'MS' parameter to be 0: " - << spvOpcodeString(opcode); + << "Image Image 'MS' parameter to be 0"; } if (info.arrayed != 0) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Image Image 'arrayed' parameter to be 0: " - << spvOpcodeString(opcode); + << "Image Image 'arrayed' parameter to be 0"; } } @@ -547,23 +515,20 @@ spv_result_t ValidateImageCommon(ValidationState_t& _, const Instruction* inst, } else if (info.sampled == 2) { if (info.dim == SpvDim1D && !_.HasCapability(SpvCapabilityImage1D)) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Capability Image1D is required to access storage image: " - << spvOpcodeString(opcode); + << "Capability Image1D is required to access storage image"; } else if (info.dim == SpvDimRect && !_.HasCapability(SpvCapabilityImageRect)) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Capability ImageRect is required to access storage image: " - << spvOpcodeString(opcode); + << "Capability ImageRect is required to access storage image"; } else if (info.dim == SpvDimBuffer && !_.HasCapability(SpvCapabilityImageBuffer)) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Capability ImageBuffer is required to access storage image: " - << spvOpcodeString(opcode); + << "Capability ImageBuffer is required to access storage image"; } else if (info.dim == SpvDimCube && info.arrayed == 1 && !_.HasCapability(SpvCapabilityImageCubeArray)) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Capability ImageCubeArray is required to access storage " - << "image: " << spvOpcodeString(opcode); + << "Capability ImageCubeArray is required to access " + << "storage image"; } if (info.multisampled == 1 && @@ -574,13 +539,12 @@ spv_result_t ValidateImageCommon(ValidationState_t& _, const Instruction* inst, // and reenable. return _.diag(SPV_ERROR_INVALID_DATA) << "Capability ImageMSArray is required to access storage " - << "image: " << spvOpcodeString(opcode); + << "image"; #endif } } else { return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Sampled' parameter to be 0 or 2: " - << spvOpcodeString(opcode); + << "Expected Image 'Sampled' parameter to be 0 or 2"; } } @@ -625,17 +589,14 @@ spv_result_t GetActualResultType(ValidationState_t& _, const Instruction* inst, if (!type_inst || type_inst->opcode() != SpvOpTypeStruct) { return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) - << ": expected Result Type to be OpTypeStruct"; + << "Expected Result Type to be OpTypeStruct"; } if (type_inst->words().size() != 4 || !_.IsIntScalarType(type_inst->word(2))) { return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) - << ": expected Result Type to be a struct containing an int " - "scalar " - << "and a texel"; + << "Expected Result Type to be a struct containing an int " + "scalar and a texel"; } *actual_result_type = type_inst->word(3); @@ -653,1009 +614,962 @@ const char* GetActualResultTypeStr(SpvOp opcode) { return "Result Type"; } -} // namespace +spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { + assert(inst->type_id() == 0); -// Validates correctness of image instructions. -spv_result_t ImagePass(ValidationState_t& _, const Instruction* inst) { - const SpvOp opcode = inst->opcode(); - const uint32_t result_type = inst->type_id(); + ImageTypeInfo info; + if (!GetImageTypeInfo(_, inst->word(1), &info)) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Corrupt image type definition"; + } - if (IsImplicitLod(opcode)) { - _.current_function().RegisterExecutionModelLimitation( - SpvExecutionModelFragment, - "ImplicitLod instructions require Fragment execution model"); + if (spvIsVulkanEnv(_.context()->target_env)) { + if ((!_.IsFloatScalarType(info.sampled_type) && + !_.IsIntScalarType(info.sampled_type)) || + 32 != _.GetBitWidth(info.sampled_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Sampled Type to be a 32-bit int or float " + "scalar type for Vulkan environment"; + } + } else { + const SpvOp sampled_type_opcode = _.GetIdOpcode(info.sampled_type); + if (sampled_type_opcode != SpvOpTypeVoid && + sampled_type_opcode != SpvOpTypeInt && + sampled_type_opcode != SpvOpTypeFloat) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Sampled Type to be either void or" + << " numerical scalar type"; + } } - switch (opcode) { - case SpvOpTypeImage: { - assert(result_type == 0); + // Dim is checked elsewhere. - ImageTypeInfo info; - if (!GetImageTypeInfo(_, inst->word(1), &info)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "OpTypeImage: corrupt definition"; - } + if (info.depth > 2) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Invalid Depth " << info.depth << " (must be 0, 1 or 2)"; + } - if (spvIsVulkanEnv(_.context()->target_env)) { - if ((!_.IsFloatScalarType(info.sampled_type) && - !_.IsIntScalarType(info.sampled_type)) || - 32 != _.GetBitWidth(info.sampled_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) - << ": expected Sampled Type to be a 32-bit int or float " - "scalar type for Vulkan environment"; - } - } else { - const SpvOp sampled_type_opcode = _.GetIdOpcode(info.sampled_type); - if (sampled_type_opcode != SpvOpTypeVoid && - sampled_type_opcode != SpvOpTypeInt && - sampled_type_opcode != SpvOpTypeFloat) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) - << ": expected Sampled Type to be either void or numerical " - << "scalar type"; - } - } + if (info.arrayed > 1) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Invalid Arrayed " << info.arrayed << " (must be 0 or 1)"; + } - // Dim is checked elsewhere. + if (info.multisampled > 1) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Invalid MS " << info.multisampled << " (must be 0 or 1)"; + } - if (info.depth > 2) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) << ": invalid Depth " << info.depth - << " (must be 0, 1 or 2)"; - } + if (info.sampled > 2) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Invalid Sampled " << info.sampled << " (must be 0, 1 or 2)"; + } - if (info.arrayed > 1) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) << ": invalid Arrayed " - << info.arrayed << " (must be 0 or 1)"; - } + if (info.dim == SpvDimSubpassData) { + if (info.sampled != 2) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Dim SubpassData requires Sampled to be 2"; + } - if (info.multisampled > 1) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) << ": invalid MS " - << info.multisampled << " (must be 0 or 1)"; - } + if (info.format != SpvImageFormatUnknown) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Dim SubpassData requires format Unknown"; + } + } - if (info.sampled > 2) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) << ": invalid Sampled " - << info.sampled << " (must be 0, 1 or 2)"; - } + // Format and Access Qualifier are checked elsewhere. - if (info.dim == SpvDimSubpassData) { - if (info.sampled != 2) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) - << ": Dim SubpassData requires Sampled to be 2"; - } - - if (info.format != SpvImageFormatUnknown) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) - << ": Dim SubpassData requires format Unknown"; - } - } + return SPV_SUCCESS; +} - // Format and Access Qualifier are checked elsewhere. +spv_result_t ValidateTypeSampledImage(ValidationState_t& _, + const Instruction* inst) { + const uint32_t image_type = inst->word(2); + if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image to be of type OpTypeImage"; + } + return SPV_SUCCESS; +} - break; - } +spv_result_t ValidateSampledImage(ValidationState_t& _, + const Instruction* inst) { + if (_.GetIdOpcode(inst->type_id()) != SpvOpTypeSampledImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Result Type to be OpTypeSampledImage."; + } - case SpvOpTypeSampledImage: { - const uint32_t image_type = inst->word(2); - if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) - << ": expected Image to be of type OpTypeImage"; - } + const uint32_t image_type = _.GetOperandTypeId(inst, 2); + if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image to be of type OpTypeImage."; + } - break; + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Corrupt image type definition"; + } + + // TODO(atgoo@github.com) Check compatibility of result type and received + // image. + + if (spvIsVulkanEnv(_.context()->target_env)) { + if (info.sampled != 1) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image 'Sampled' parameter to be 1 " + << "for Vulkan environment."; + } + } else { + if (info.sampled != 0 && info.sampled != 1) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image 'Sampled' parameter to be 0 or 1"; } + } - case SpvOpSampledImage: { - if (_.GetIdOpcode(result_type) != SpvOpTypeSampledImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Result Type to be OpTypeSampledImage: " - << spvOpcodeString(opcode); - } + if (info.dim == SpvDimSubpassData) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image 'Dim' parameter to be not SubpassData."; + } - const uint32_t image_type = _.GetOperandTypeId(inst, 2); - if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image to be of type OpTypeImage: " - << spvOpcodeString(opcode); - } + if (_.GetIdOpcode(_.GetOperandTypeId(inst, 3)) != SpvOpTypeSampler) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Sampler to be of type OpTypeSampler"; + } + return SPV_SUCCESS; +} - ImageTypeInfo info; - if (!GetImageTypeInfo(_, image_type, &info)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Corrupt image type definition"; - } +spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) { + const SpvOp opcode = inst->opcode(); + uint32_t actual_result_type = 0; + if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) { + return error; + } - // TODO(atgoo@github.com) Check compatibility of result type and received - // image. - - if (spvIsVulkanEnv(_.context()->target_env)) { - if (info.sampled != 1) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Sampled' parameter to be 1 for Vulkan " - "environment: " - << spvOpcodeString(opcode); - } - } else { - if (info.sampled != 0 && info.sampled != 1) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Sampled' parameter to be 0 or 1: " - << spvOpcodeString(opcode); - } - } + if (!_.IsIntVectorType(actual_result_type) && + !_.IsFloatVectorType(actual_result_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected " << GetActualResultTypeStr(opcode) + << " to be int or float vector type"; + } - if (info.dim == SpvDimSubpassData) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Dim' parameter to be not SubpassData: " - << spvOpcodeString(opcode); - } + if (_.GetDimension(actual_result_type) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected " << GetActualResultTypeStr(opcode) + << " to have 4 components"; + } - if (_.GetIdOpcode(_.GetOperandTypeId(inst, 3)) != SpvOpTypeSampler) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Sampler to be of type OpTypeSampler: " - << spvOpcodeString(opcode); - } + const uint32_t image_type = _.GetOperandTypeId(inst, 2); + if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Sampled Image to be of type OpTypeSampledImage"; + } - break; + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Corrupt image type definition"; + } + + if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result; + + if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { + const uint32_t texel_component_type = + _.GetComponentType(actual_result_type); + if (texel_component_type != info.sampled_type) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image 'Sampled Type' to be the same as " + << GetActualResultTypeStr(opcode) << " components"; } + } - case SpvOpImageSampleImplicitLod: - case SpvOpImageSampleExplicitLod: - case SpvOpImageSampleProjImplicitLod: - case SpvOpImageSampleProjExplicitLod: - case SpvOpImageSparseSampleImplicitLod: - case SpvOpImageSparseSampleExplicitLod: { - uint32_t actual_result_type = 0; - if (spv_result_t error = - GetActualResultType(_, inst, &actual_result_type)) { - return error; - } + const uint32_t coord_type = _.GetOperandTypeId(inst, 3); + if ((opcode == SpvOpImageSampleExplicitLod || + opcode == SpvOpImageSparseSampleExplicitLod) && + _.HasCapability(SpvCapabilityKernel)) { + if (!_.IsFloatScalarOrVectorType(coord_type) && + !_.IsIntScalarOrVectorType(coord_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to be int or float scalar or vector"; + } + } else { + if (!_.IsFloatScalarOrVectorType(coord_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to be float scalar or vector"; + } + } - if (!_.IsIntVectorType(actual_result_type) && - !_.IsFloatVectorType(actual_result_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected " << GetActualResultTypeStr(opcode) - << " to be int or float vector type: " - << spvOpcodeString(opcode); - } + const uint32_t min_coord_size = GetMinCoordSize(opcode, info); + const uint32_t actual_coord_size = _.GetDimension(coord_type); + if (min_coord_size > actual_coord_size) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to have at least " << min_coord_size + << " components, but given only " << actual_coord_size; + } - if (_.GetDimension(actual_result_type) != 4) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected " << GetActualResultTypeStr(opcode) - << " to have 4 components: " << spvOpcodeString(opcode); - } + if (inst->words().size() <= 5) { + assert(IsImplicitLod(opcode)); + return SPV_SUCCESS; + } - const uint32_t image_type = _.GetOperandTypeId(inst, 2); - if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Sampled Image to be of type OpTypeSampledImage: " - << spvOpcodeString(opcode); - } + const uint32_t mask = inst->word(5); + if (spv_result_t result = + ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) + return result; - ImageTypeInfo info; - if (!GetImageTypeInfo(_, image_type, &info)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Corrupt image type definition"; - } + return SPV_SUCCESS; +} - if (spv_result_t result = ValidateImageCommon(_, inst, info)) - return result; - - if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { - const uint32_t texel_component_type = - _.GetComponentType(actual_result_type); - if (texel_component_type != info.sampled_type) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Sampled Type' to be the same as " - << GetActualResultTypeStr(opcode) - << " components: " << spvOpcodeString(opcode); - } - } +spv_result_t ValidateImageDrefLod(ValidationState_t& _, + const Instruction* inst) { + const SpvOp opcode = inst->opcode(); + uint32_t actual_result_type = 0; + if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) { + return error; + } - const uint32_t coord_type = _.GetOperandTypeId(inst, 3); - if ((opcode == SpvOpImageSampleExplicitLod || - opcode == SpvOpImageSparseSampleExplicitLod) && - _.HasCapability(SpvCapabilityKernel)) { - if (!_.IsFloatScalarOrVectorType(coord_type) && - !_.IsIntScalarOrVectorType(coord_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to be int or float scalar or vector: " - << spvOpcodeString(opcode); - } - } else { - if (!_.IsFloatScalarOrVectorType(coord_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to be float scalar or vector: " - << spvOpcodeString(opcode); - } - } + if (!_.IsIntScalarType(actual_result_type) && + !_.IsFloatScalarType(actual_result_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected " << GetActualResultTypeStr(opcode) + << " to be int or float scalar type"; + } - const uint32_t min_coord_size = GetMinCoordSize(opcode, info); - const uint32_t actual_coord_size = _.GetDimension(coord_type); - if (min_coord_size > actual_coord_size) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to have at least " << min_coord_size - << " components, but given only " << actual_coord_size << ": " - << spvOpcodeString(opcode); - } + const uint32_t image_type = _.GetOperandTypeId(inst, 2); + if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Sampled Image to be of type OpTypeSampledImage"; + } - if (inst->words().size() <= 5) { - assert(IsImplicitLod(opcode)); - break; - } + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Corrupt image type definition"; + } - const uint32_t mask = inst->word(5); - if (spv_result_t result = - ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) - return result; + if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result; - break; - } + if (actual_result_type != info.sampled_type) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image 'Sampled Type' to be the same as " + << GetActualResultTypeStr(opcode); + } - case SpvOpImageSampleDrefImplicitLod: - case SpvOpImageSampleDrefExplicitLod: - case SpvOpImageSampleProjDrefImplicitLod: - case SpvOpImageSampleProjDrefExplicitLod: - case SpvOpImageSparseSampleDrefImplicitLod: - case SpvOpImageSparseSampleDrefExplicitLod: { - uint32_t actual_result_type = 0; - if (spv_result_t error = - GetActualResultType(_, inst, &actual_result_type)) { - return error; - } + const uint32_t coord_type = _.GetOperandTypeId(inst, 3); + if (!_.IsFloatScalarOrVectorType(coord_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to be float scalar or vector"; + } - if (!_.IsIntScalarType(actual_result_type) && - !_.IsFloatScalarType(actual_result_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected " << GetActualResultTypeStr(opcode) - << " to be int or float scalar type: " - << spvOpcodeString(opcode); - } + const uint32_t min_coord_size = GetMinCoordSize(opcode, info); + const uint32_t actual_coord_size = _.GetDimension(coord_type); + if (min_coord_size > actual_coord_size) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to have at least " << min_coord_size + << " components, but given only " << actual_coord_size; + } - const uint32_t image_type = _.GetOperandTypeId(inst, 2); - if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Sampled Image to be of type OpTypeSampledImage: " - << spvOpcodeString(opcode); - } + const uint32_t dref_type = _.GetOperandTypeId(inst, 4); + if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Dref to be of 32-bit float type"; + } - ImageTypeInfo info; - if (!GetImageTypeInfo(_, image_type, &info)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Corrupt image type definition"; - } + if (inst->words().size() <= 6) { + assert(IsImplicitLod(opcode)); + return SPV_SUCCESS; + } - if (spv_result_t result = ValidateImageCommon(_, inst, info)) - return result; + const uint32_t mask = inst->word(6); + if (spv_result_t result = + ValidateImageOperands(_, inst, info, mask, /* word_index = */ 7)) + return result; - if (actual_result_type != info.sampled_type) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Sampled Type' to be the same as " - << GetActualResultTypeStr(opcode) << ": " - << spvOpcodeString(opcode); - } + return SPV_SUCCESS; +} - const uint32_t coord_type = _.GetOperandTypeId(inst, 3); - if (!_.IsFloatScalarOrVectorType(coord_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to be float scalar or vector: " - << spvOpcodeString(opcode); - } +spv_result_t ValidateImageFetch(ValidationState_t& _, const Instruction* inst) { + uint32_t actual_result_type = 0; + if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) { + return error; + } - const uint32_t min_coord_size = GetMinCoordSize(opcode, info); - const uint32_t actual_coord_size = _.GetDimension(coord_type); - if (min_coord_size > actual_coord_size) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to have at least " << min_coord_size - << " components, but given only " << actual_coord_size << ": " - << spvOpcodeString(opcode); - } + const SpvOp opcode = inst->opcode(); + if (!_.IsIntVectorType(actual_result_type) && + !_.IsFloatVectorType(actual_result_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected " << GetActualResultTypeStr(opcode) + << " to be int or float vector type"; + } - const uint32_t dref_type = _.GetOperandTypeId(inst, 4); - if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) - << ": Expected Dref to be of 32-bit float type"; - } + if (_.GetDimension(actual_result_type) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected " << GetActualResultTypeStr(opcode) + << " to have 4 components"; + } - if (inst->words().size() <= 6) { - assert(IsImplicitLod(opcode)); - break; - } + const uint32_t image_type = _.GetOperandTypeId(inst, 2); + if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image to be of type OpTypeImage"; + } - const uint32_t mask = inst->word(6); - if (spv_result_t result = - ValidateImageOperands(_, inst, info, mask, /* word_index = */ 7)) - return result; + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Corrupt image type definition"; + } - break; + if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { + const uint32_t result_component_type = + _.GetComponentType(actual_result_type); + if (result_component_type != info.sampled_type) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image 'Sampled Type' to be the same as " + << GetActualResultTypeStr(opcode) << " components"; } + } - case SpvOpImageFetch: - case SpvOpImageSparseFetch: { - uint32_t actual_result_type = 0; - if (spv_result_t error = - GetActualResultType(_, inst, &actual_result_type)) { - return error; - } + if (info.dim == SpvDimCube) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Image 'Dim' cannot be Cube"; + } - if (!_.IsIntVectorType(actual_result_type) && - !_.IsFloatVectorType(actual_result_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected " << GetActualResultTypeStr(opcode) - << " to be int or float vector type: " - << spvOpcodeString(opcode); - } + if (info.sampled != 1) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image 'Sampled' parameter to be 1"; + } - if (_.GetDimension(actual_result_type) != 4) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected " << GetActualResultTypeStr(opcode) - << " to have 4 components: " << spvOpcodeString(opcode); - } + const uint32_t coord_type = _.GetOperandTypeId(inst, 3); + if (!_.IsIntScalarOrVectorType(coord_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to be int scalar or vector"; + } - const uint32_t image_type = _.GetOperandTypeId(inst, 2); - if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image to be of type OpTypeImage: " - << spvOpcodeString(opcode); - } + const uint32_t min_coord_size = GetMinCoordSize(opcode, info); + const uint32_t actual_coord_size = _.GetDimension(coord_type); + if (min_coord_size > actual_coord_size) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to have at least " << min_coord_size + << " components, but given only " << actual_coord_size; + } - ImageTypeInfo info; - if (!GetImageTypeInfo(_, image_type, &info)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Corrupt image type definition"; - } + if (inst->words().size() <= 5) return SPV_SUCCESS; - if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { - const uint32_t result_component_type = - _.GetComponentType(actual_result_type); - if (result_component_type != info.sampled_type) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Sampled Type' to be the same as " - << GetActualResultTypeStr(opcode) - << " components: " << spvOpcodeString(opcode); - } - } + const uint32_t mask = inst->word(5); + if (spv_result_t result = + ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) + return result; - if (info.dim == SpvDimCube) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Image 'Dim' cannot be Cube: " << spvOpcodeString(opcode); - } + return SPV_SUCCESS; +} - if (info.sampled != 1) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Sampled' parameter to be 1: " - << spvOpcodeString(opcode); - } +spv_result_t ValidateImageGather(ValidationState_t& _, + const Instruction* inst) { + uint32_t actual_result_type = 0; + if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) + return error; - const uint32_t coord_type = _.GetOperandTypeId(inst, 3); - if (!_.IsIntScalarOrVectorType(coord_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to be int scalar or vector: " - << spvOpcodeString(opcode); - } + const SpvOp opcode = inst->opcode(); + if (!_.IsIntVectorType(actual_result_type) && + !_.IsFloatVectorType(actual_result_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected " << GetActualResultTypeStr(opcode) + << " to be int or float vector type"; + } - const uint32_t min_coord_size = GetMinCoordSize(opcode, info); - const uint32_t actual_coord_size = _.GetDimension(coord_type); - if (min_coord_size > actual_coord_size) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to have at least " << min_coord_size - << " components, but given only " << actual_coord_size << ": " - << spvOpcodeString(opcode); - } + if (_.GetDimension(actual_result_type) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected " << GetActualResultTypeStr(opcode) + << " to have 4 components"; + } - if (inst->words().size() <= 5) break; + const uint32_t image_type = _.GetOperandTypeId(inst, 2); + if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Sampled Image to be of type OpTypeSampledImage"; + } - const uint32_t mask = inst->word(5); - if (spv_result_t result = - ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) - return result; + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Corrupt image type definition"; + } - break; + if (opcode == SpvOpImageDrefGather || opcode == SpvOpImageSparseDrefGather || + _.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { + const uint32_t result_component_type = + _.GetComponentType(actual_result_type); + if (result_component_type != info.sampled_type) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image 'Sampled Type' to be the same as " + << GetActualResultTypeStr(opcode) << " components"; } + } - case SpvOpImageGather: - case SpvOpImageDrefGather: - case SpvOpImageSparseGather: - case SpvOpImageSparseDrefGather: { - uint32_t actual_result_type = 0; - if (spv_result_t error = - GetActualResultType(_, inst, &actual_result_type)) { - return error; - } + if (info.dim != SpvDim2D && info.dim != SpvDimCube && + info.dim != SpvDimRect) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image 'Dim' cannot be Cube"; + } - if (!_.IsIntVectorType(actual_result_type) && - !_.IsFloatVectorType(actual_result_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected " << GetActualResultTypeStr(opcode) - << " to be int or float vector type: " - << spvOpcodeString(opcode); - } + const uint32_t coord_type = _.GetOperandTypeId(inst, 3); + if (!_.IsFloatScalarOrVectorType(coord_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to be float scalar or vector"; + } - if (_.GetDimension(actual_result_type) != 4) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected " << GetActualResultTypeStr(opcode) - << " to have 4 components: " << spvOpcodeString(opcode); - } + const uint32_t min_coord_size = GetMinCoordSize(opcode, info); + const uint32_t actual_coord_size = _.GetDimension(coord_type); + if (min_coord_size > actual_coord_size) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to have at least " << min_coord_size + << " components, but given only " << actual_coord_size; + } - const uint32_t image_type = _.GetOperandTypeId(inst, 2); - if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Sampled Image to be of type OpTypeSampledImage: " - << spvOpcodeString(opcode); - } + if (opcode == SpvOpImageGather || opcode == SpvOpImageSparseGather) { + const uint32_t component_index_type = _.GetOperandTypeId(inst, 4); + if (!_.IsIntScalarType(component_index_type) || + _.GetBitWidth(component_index_type) != 32) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Component to be 32-bit int scalar"; + } + } else { + assert(opcode == SpvOpImageDrefGather || + opcode == SpvOpImageSparseDrefGather); + const uint32_t dref_type = _.GetOperandTypeId(inst, 4); + if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Dref to be of 32-bit float type"; + } + } - ImageTypeInfo info; - if (!GetImageTypeInfo(_, image_type, &info)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Corrupt image type definition"; - } + if (inst->words().size() <= 6) return SPV_SUCCESS; - if (opcode == SpvOpImageDrefGather || - opcode == SpvOpImageSparseDrefGather || - _.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { - const uint32_t result_component_type = - _.GetComponentType(actual_result_type); - if (result_component_type != info.sampled_type) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Sampled Type' to be the same as " - << GetActualResultTypeStr(opcode) - << " components: " << spvOpcodeString(opcode); - } - } + const uint32_t mask = inst->word(6); + if (spv_result_t result = + ValidateImageOperands(_, inst, info, mask, /* word_index = */ 7)) + return result; - if (info.dim != SpvDim2D && info.dim != SpvDimCube && - info.dim != SpvDimRect) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Dim' cannot be Cube: " - << spvOpcodeString(opcode); - } + return SPV_SUCCESS; +} - const uint32_t coord_type = _.GetOperandTypeId(inst, 3); - if (!_.IsFloatScalarOrVectorType(coord_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to be float scalar or vector: " - << spvOpcodeString(opcode); - } +spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) { + const SpvOp opcode = inst->opcode(); + uint32_t actual_result_type = 0; + if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) { + return error; + } - const uint32_t min_coord_size = GetMinCoordSize(opcode, info); - const uint32_t actual_coord_size = _.GetDimension(coord_type); - if (min_coord_size > actual_coord_size) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to have at least " << min_coord_size - << " components, but given only " << actual_coord_size << ": " - << spvOpcodeString(opcode); - } + if (!_.IsIntScalarOrVectorType(actual_result_type) && + !_.IsFloatScalarOrVectorType(actual_result_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected " << GetActualResultTypeStr(opcode) + << " to be int or float scalar or vector type"; + } - if (opcode == SpvOpImageGather || opcode == SpvOpImageSparseGather) { - const uint32_t component_index_type = _.GetOperandTypeId(inst, 4); - if (!_.IsIntScalarType(component_index_type) || - _.GetBitWidth(component_index_type) != 32) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Component to be 32-bit int scalar: " - << spvOpcodeString(opcode); - } - } else { - assert(opcode == SpvOpImageDrefGather || - opcode == SpvOpImageSparseDrefGather); - const uint32_t dref_type = _.GetOperandTypeId(inst, 4); - if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) - << ": Expected Dref to be of 32-bit float type"; - } - } +#if 0 + // TODO(atgoo@github.com) Disabled until the spec is clarified. + if (_.GetDimension(actual_result_type) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected " << GetActualResultTypeStr(opcode) + << " to have 4 components"; + } +#endif - if (inst->words().size() <= 6) break; + const uint32_t image_type = _.GetOperandTypeId(inst, 2); + if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image to be of type OpTypeImage"; + } - const uint32_t mask = inst->word(6); - if (spv_result_t result = - ValidateImageOperands(_, inst, info, mask, /* word_index = */ 7)) - return result; + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Corrupt image type definition"; + } - break; + if (info.dim == SpvDimSubpassData) { + if (opcode == SpvOpImageSparseRead) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Image Dim SubpassData cannot be used with ImageSparseRead"; } - case SpvOpImageRead: - case SpvOpImageSparseRead: { - uint32_t actual_result_type = 0; - if (spv_result_t error = - GetActualResultType(_, inst, &actual_result_type)) { - return error; - } + _.current_function().RegisterExecutionModelLimitation( + SpvExecutionModelFragment, + std::string("Dim SubpassData requires Fragment execution model: ") + + spvOpcodeString(opcode)); + } - if (!_.IsIntScalarOrVectorType(actual_result_type) && - !_.IsFloatScalarOrVectorType(actual_result_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected " << GetActualResultTypeStr(opcode) - << " to be int or float scalar or vector type: " - << spvOpcodeString(opcode); - } + if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { + const uint32_t result_component_type = + _.GetComponentType(actual_result_type); + if (result_component_type != info.sampled_type) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image 'Sampled Type' to be the same as " + << GetActualResultTypeStr(opcode) << " components"; + } + } -#if 0 - // TODO(atgoo@github.com) Disabled until the spec is clarified. - if (_.GetDimension(actual_result_type) != 4) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected " << GetActualResultTypeStr(opcode) - << " to have 4 components: " << spvOpcodeString(opcode); - } -#endif + if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result; - const uint32_t image_type = _.GetOperandTypeId(inst, 2); - if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image to be of type OpTypeImage: " - << spvOpcodeString(opcode); - } + const uint32_t coord_type = _.GetOperandTypeId(inst, 3); + if (!_.IsIntScalarOrVectorType(coord_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to be int scalar or vector"; + } - ImageTypeInfo info; - if (!GetImageTypeInfo(_, image_type, &info)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Corrupt image type definition"; - } + const uint32_t min_coord_size = GetMinCoordSize(opcode, info); + const uint32_t actual_coord_size = _.GetDimension(coord_type); + if (min_coord_size > actual_coord_size) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to have at least " << min_coord_size + << " components, but given only " << actual_coord_size; + } - if (info.dim == SpvDimSubpassData) { - if (opcode == SpvOpImageSparseRead) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Image Dim SubpassData cannot be used with " - << spvOpcodeString(opcode); - } - - _.current_function().RegisterExecutionModelLimitation( - SpvExecutionModelFragment, - std::string("Dim SubpassData requires Fragment execution model: ") + - spvOpcodeString(opcode)); - } + if (info.format == SpvImageFormatUnknown && info.dim != SpvDimSubpassData && + !_.HasCapability(SpvCapabilityStorageImageReadWithoutFormat)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Capability StorageImageReadWithoutFormat is required to " + << "read storage image"; + } - if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { - const uint32_t result_component_type = - _.GetComponentType(actual_result_type); - if (result_component_type != info.sampled_type) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Sampled Type' to be the same as " - << GetActualResultTypeStr(opcode) - << " components: " << spvOpcodeString(opcode); - } - } + if (inst->words().size() <= 5) return SPV_SUCCESS; - if (spv_result_t result = ValidateImageCommon(_, inst, info)) - return result; + const uint32_t mask = inst->word(5); + if (spv_result_t result = + ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) + return result; - const uint32_t coord_type = _.GetOperandTypeId(inst, 3); - if (!_.IsIntScalarOrVectorType(coord_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to be int scalar or vector: " - << spvOpcodeString(opcode); - } + return SPV_SUCCESS; +} - const uint32_t min_coord_size = GetMinCoordSize(opcode, info); - const uint32_t actual_coord_size = _.GetDimension(coord_type); - if (min_coord_size > actual_coord_size) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to have at least " << min_coord_size - << " components, but given only " << actual_coord_size << ": " - << spvOpcodeString(opcode); - } +spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) { + const uint32_t image_type = _.GetOperandTypeId(inst, 0); + if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image to be of type OpTypeImage"; + } - if (info.format == SpvImageFormatUnknown && - info.dim != SpvDimSubpassData && - !_.HasCapability(SpvCapabilityStorageImageReadWithoutFormat)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Capability StorageImageReadWithoutFormat is required to " - << "read storage image: " << spvOpcodeString(opcode); - } + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Corrupt image type definition"; + } - if (inst->words().size() <= 5) break; + if (info.dim == SpvDimSubpassData) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Image 'Dim' cannot be SubpassData"; + } - const uint32_t mask = inst->word(5); - if (spv_result_t result = - ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) - return result; + if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result; - break; + const uint32_t coord_type = _.GetOperandTypeId(inst, 1); + if (!_.IsIntScalarOrVectorType(coord_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to be int scalar or vector"; + } + + const uint32_t min_coord_size = GetMinCoordSize(inst->opcode(), info); + const uint32_t actual_coord_size = _.GetDimension(coord_type); + if (min_coord_size > actual_coord_size) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to have at least " << min_coord_size + << " components, but given only " << actual_coord_size; + } + + // TODO(atgoo@github.com) The spec doesn't explicitely say what the type + // of texel should be. + const uint32_t texel_type = _.GetOperandTypeId(inst, 2); + if (!_.IsIntScalarOrVectorType(texel_type) && + !_.IsFloatScalarOrVectorType(texel_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Texel to be int or float vector or scalar"; + } + +#if 0 + // TODO: See above. + if (_.GetDimension(texel_type) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Texel to have 4 components"; + } +#endif + + if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { + const uint32_t texel_component_type = _.GetComponentType(texel_type); + if (texel_component_type != info.sampled_type) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image 'Sampled Type' to be the same as Texel " + << "components"; } + } - case SpvOpImageWrite: { - const uint32_t image_type = _.GetOperandTypeId(inst, 0); - if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image to be of type OpTypeImage: " - << spvOpcodeString(opcode); - } + if (info.format == SpvImageFormatUnknown && info.dim != SpvDimSubpassData && + !_.HasCapability(SpvCapabilityStorageImageWriteWithoutFormat)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Capability StorageImageWriteWithoutFormat is required to " + "write " + << "to storage image"; + } - ImageTypeInfo info; - if (!GetImageTypeInfo(_, image_type, &info)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Corrupt image type definition"; - } + if (inst->words().size() <= 4) return SPV_SUCCESS; - if (info.dim == SpvDimSubpassData) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Image 'Dim' cannot be SubpassData: " - << spvOpcodeString(opcode); - } + const uint32_t mask = inst->word(4); + if (spv_result_t result = + ValidateImageOperands(_, inst, info, mask, /* word_index = */ 5)) + return result; - if (spv_result_t result = ValidateImageCommon(_, inst, info)) - return result; + return SPV_SUCCESS; +} - const uint32_t coord_type = _.GetOperandTypeId(inst, 1); - if (!_.IsIntScalarOrVectorType(coord_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to be int scalar or vector: " - << spvOpcodeString(opcode); - } +spv_result_t ValidateImage(ValidationState_t& _, const Instruction* inst) { + const uint32_t result_type = inst->type_id(); + if (_.GetIdOpcode(result_type) != SpvOpTypeImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Result Type to be OpTypeImage"; + } - const uint32_t min_coord_size = GetMinCoordSize(opcode, info); - const uint32_t actual_coord_size = _.GetDimension(coord_type); - if (min_coord_size > actual_coord_size) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to have at least " << min_coord_size - << " components, but given only " << actual_coord_size << ": " - << spvOpcodeString(opcode); - } + const uint32_t sampled_image_type = _.GetOperandTypeId(inst, 2); + const Instruction* sampled_image_type_inst = _.FindDef(sampled_image_type); + assert(sampled_image_type_inst); - // TODO(atgoo@github.com) The spec doesn't explicitely say what the type - // of texel should be. - const uint32_t texel_type = _.GetOperandTypeId(inst, 2); - if (!_.IsIntScalarOrVectorType(texel_type) && - !_.IsFloatScalarOrVectorType(texel_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Texel to be int or float vector or scalar: " - << spvOpcodeString(opcode); - } + if (sampled_image_type_inst->opcode() != SpvOpTypeSampledImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Sample Image to be of type OpTypeSampleImage"; + } -#if 0 - // TODO: See above. - if (_.GetDimension(texel_type) != 4) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Texel to have 4 components: " - << spvOpcodeString(opcode); - } -#endif + if (sampled_image_type_inst->word(2) != result_type) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Sample Image image type to be equal to Result Type"; + } - if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { - const uint32_t texel_component_type = _.GetComponentType(texel_type); - if (texel_component_type != info.sampled_type) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image 'Sampled Type' to be the same as Texel " - << "components: " << spvOpcodeString(opcode); - } - } + return SPV_SUCCESS; +} - if (info.format == SpvImageFormatUnknown && - info.dim != SpvDimSubpassData && - !_.HasCapability(SpvCapabilityStorageImageWriteWithoutFormat)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Capability StorageImageWriteWithoutFormat is required to " - "write " - << "to storage image: " << spvOpcodeString(opcode); - } +spv_result_t ValidateImageQuerySizeLod(ValidationState_t& _, + const Instruction* inst) { + const uint32_t result_type = inst->type_id(); + if (!_.IsIntScalarOrVectorType(result_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Result Type to be int scalar or vector type"; + } - if (inst->words().size() <= 4) break; + const uint32_t image_type = _.GetOperandTypeId(inst, 2); + if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image to be of type OpTypeImage"; + } - const uint32_t mask = inst->word(4); - if (spv_result_t result = - ValidateImageOperands(_, inst, info, mask, /* word_index = */ 5)) - return result; + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Corrupt image type definition"; + } + uint32_t expected_num_components = info.arrayed; + switch (info.dim) { + case SpvDim1D: + expected_num_components += 1; break; - } + case SpvDim2D: + case SpvDimCube: + expected_num_components += 2; + break; + case SpvDim3D: + expected_num_components += 3; + break; + default: + return _.diag(SPV_ERROR_INVALID_DATA) + << "Image 'Dim' must be 1D, 2D, 3D or Cube"; + }; - case SpvOpImage: { - if (_.GetIdOpcode(result_type) != SpvOpTypeImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Result Type to be OpTypeImage: " - << spvOpcodeString(opcode); - } + if (info.multisampled != 0) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Image 'MS' must be 0"; + } - const uint32_t sampled_image_type = _.GetOperandTypeId(inst, 2); - const Instruction* sampled_image_type_inst = - _.FindDef(sampled_image_type); - assert(sampled_image_type_inst); + uint32_t result_num_components = _.GetDimension(result_type); + if (result_num_components != expected_num_components) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Result Type has " << result_num_components << " components, " + << "but " << expected_num_components << " expected"; + } - if (sampled_image_type_inst->opcode() != SpvOpTypeSampledImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Sample Image to be of type OpTypeSampleImage: " - << spvOpcodeString(opcode); - } + const uint32_t lod_type = _.GetOperandTypeId(inst, 3); + if (!_.IsIntScalarType(lod_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Level of Detail to be int scalar"; + } + return SPV_SUCCESS; +} - if (sampled_image_type_inst->word(2) != result_type) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Sample Image image type to be equal to Result " - "Type: " - << spvOpcodeString(opcode); - } +spv_result_t ValidateImageQuerySize(ValidationState_t& _, + const Instruction* inst) { + const uint32_t result_type = inst->type_id(); + if (!_.IsIntScalarOrVectorType(result_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Result Type to be int scalar or vector type"; + } - break; - } + const uint32_t image_type = _.GetOperandTypeId(inst, 2); + if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image to be of type OpTypeImage"; + } - case SpvOpImageQueryFormat: - case SpvOpImageQueryOrder: { - if (!_.IsIntScalarType(result_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Result Type to be int scalar type: " - << spvOpcodeString(opcode); - } +#if 0 + // TODO(atgoo@github.com) The spec doesn't whitelist all Dims supported by + // GLSL. Need to verify if there is an error and reenable. + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Corrupt image type definition"; + } - if (_.GetIdOpcode(_.GetOperandTypeId(inst, 2)) != SpvOpTypeImage) { + uint32_t expected_num_components = info.arrayed; + switch (info.dim) { + case SpvDimBuffer: + expected_num_components += 1; + break; + case SpvDim2D: + if (info.multisampled != 1 && info.sampled != 0 && + info.sampled != 2) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected operand to be of type OpTypeImage: " - << spvOpcodeString(opcode); + << "Expected either 'MS'=1 or 'Sampled'=0 or 'Sampled'=2 " + << "for 2D dim"; } + case SpvDimRect: + expected_num_components += 2; break; - } - - case SpvOpImageQuerySizeLod: { - if (!_.IsIntScalarOrVectorType(result_type)) { + case SpvDim3D: + expected_num_components += 3; + if (info.sampled != 0 && + info.sampled != 2) { return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Result Type to be int scalar or vector type: " - << spvOpcodeString(opcode); + << "Expected either 'Sampled'=0 or 'Sampled'=2 " + << "for 3D dim"; } + break; + default: + return _.diag(SPV_ERROR_INVALID_DATA) + << "Image 'Dim' must be Buffer, 2D, 3D or Rect"; + }; - const uint32_t image_type = _.GetOperandTypeId(inst, 2); - if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image to be of type OpTypeImage: " - << spvOpcodeString(opcode); - } - ImageTypeInfo info; - if (!GetImageTypeInfo(_, image_type, &info)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Corrupt image type definition"; - } + if (info.multisampled != 0) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Image 'MS' must be 0"; + } - uint32_t expected_num_components = info.arrayed; - switch (info.dim) { - case SpvDim1D: - expected_num_components += 1; - break; - case SpvDim2D: - case SpvDimCube: - expected_num_components += 2; - break; - case SpvDim3D: - expected_num_components += 3; - break; - default: - return _.diag(SPV_ERROR_INVALID_DATA) - << "Image 'Dim' must be 1D, 2D, 3D or Cube: " - << spvOpcodeString(opcode); - }; - - if (info.multisampled != 0) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Image 'MS' must be 0: " << spvOpcodeString(opcode); - } + uint32_t result_num_components = _.GetDimension(result_type); + if (result_num_components != expected_num_components) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Result Type has " << result_num_components << " components, " + << "but " << expected_num_components << " expected"; + } +#endif - uint32_t result_num_components = _.GetDimension(result_type); - if (result_num_components != expected_num_components) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Result Type has " << result_num_components << " components, " - << "but " << expected_num_components - << " expected: " << spvOpcodeString(opcode); - } + return SPV_SUCCESS; +} - const uint32_t lod_type = _.GetOperandTypeId(inst, 3); - if (!_.IsIntScalarType(lod_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Level of Detail to be int scalar: " - << spvOpcodeString(opcode); - } +spv_result_t ValidateImageQueryFormatOrOrder(ValidationState_t& _, + const Instruction* inst) { + if (!_.IsIntScalarType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Result Type to be int scalar type"; + } - break; + if (_.GetIdOpcode(_.GetOperandTypeId(inst, 2)) != SpvOpTypeImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected operand to be of type OpTypeImage"; + } + return SPV_SUCCESS; +} + +spv_result_t ValidateImageQueryLod(ValidationState_t& _, + const Instruction* inst) { + _.current_function().RegisterExecutionModelLimitation( + SpvExecutionModelFragment, + "OpImageQueryLod requires Fragment execution model"); + + const uint32_t result_type = inst->type_id(); + if (!_.IsFloatVectorType(result_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Result Type to be float vector type"; + } + + if (_.GetDimension(result_type) != 2) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Result Type to have 2 components"; + } + + const uint32_t image_type = _.GetOperandTypeId(inst, 2); + if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image operand to be of type OpTypeSampledImage"; + } + + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Corrupt image type definition"; + } + + if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D && + info.dim != SpvDimCube) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Image 'Dim' must be 1D, 2D, 3D or Cube"; + } + + const uint32_t coord_type = _.GetOperandTypeId(inst, 3); + if (_.HasCapability(SpvCapabilityKernel)) { + if (!_.IsFloatScalarOrVectorType(coord_type) && + !_.IsIntScalarOrVectorType(coord_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to be int or float scalar or vector"; + } + } else { + if (!_.IsFloatScalarOrVectorType(coord_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to be float scalar or vector"; } + } - case SpvOpImageQuerySize: { - if (!_.IsIntScalarOrVectorType(result_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Result Type to be int scalar or vector type: " - << spvOpcodeString(opcode); - } + const uint32_t min_coord_size = GetPlaneCoordSize(info); + const uint32_t actual_coord_size = _.GetDimension(coord_type); + if (min_coord_size > actual_coord_size) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Coordinate to have at least " << min_coord_size + << " components, but given only " << actual_coord_size; + } + return SPV_SUCCESS; +} - const uint32_t image_type = _.GetOperandTypeId(inst, 2); - if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image to be of type OpTypeImage: " - << spvOpcodeString(opcode); - } +spv_result_t ValidateImageSparseLod(ValidationState_t& _, const Instruction*) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Instruction reserved for future use, use of this instruction " + << "is invalid"; +} -#if 0 - // TODO(atgoo@github.com) The spec doesn't whitelist all Dims supported by - // GLSL. Need to verify if there is an error and reenable. - ImageTypeInfo info; - if (!GetImageTypeInfo(_, image_type, &info)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Corrupt image type definition"; - } +spv_result_t ValidateImageQueryLevelsOrSamples(ValidationState_t& _, + const Instruction* inst) { + if (!_.IsIntScalarType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Result Type to be int scalar type"; + } - uint32_t expected_num_components = info.arrayed; - switch (info.dim) { - case SpvDimBuffer: - expected_num_components += 1; - break; - case SpvDim2D: - if (info.multisampled != 1 && info.sampled != 0 && - info.sampled != 2) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected either 'MS'=1 or 'Sampled'=0 or 'Sampled'=2 " - << "for 2D dim: " << spvOpcodeString(opcode); - } - case SpvDimRect: - expected_num_components += 2; - break; - case SpvDim3D: - expected_num_components += 3; - if (info.sampled != 0 && - info.sampled != 2) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected either 'Sampled'=0 or 'Sampled'=2 " - << "for 3D dim: " << spvOpcodeString(opcode); - } - break; - default: - return _.diag(SPV_ERROR_INVALID_DATA) - << "Image 'Dim' must be Buffer, 2D, 3D or Rect: " - << spvOpcodeString(opcode); - }; - - - if (info.multisampled != 0) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Image 'MS' must be 0: " << spvOpcodeString(opcode); - } + const uint32_t image_type = _.GetOperandTypeId(inst, 2); + if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Image to be of type OpTypeImage"; + } - uint32_t result_num_components = _.GetDimension(result_type); - if (result_num_components != expected_num_components) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Result Type has " << result_num_components << " components, " - << "but " << expected_num_components << " expected: " - << spvOpcodeString(opcode); - } -#endif - break; + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Corrupt image type definition"; + } + + const SpvOp opcode = inst->opcode(); + if (opcode == SpvOpImageQueryLevels) { + if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D && + info.dim != SpvDimCube) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Image 'Dim' must be 1D, 2D, 3D or Cube"; + } + } else { + assert(opcode == SpvOpImageQuerySamples); + if (info.dim != SpvDim2D) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Image 'Dim' must be 2D"; } - case SpvOpImageQueryLod: { - _.current_function().RegisterExecutionModelLimitation( - SpvExecutionModelFragment, - "OpImageQueryLod requires Fragment execution model"); + if (info.multisampled != 1) { + return _.diag(SPV_ERROR_INVALID_DATA) << "Image 'MS' must be 1"; + } + } + return SPV_SUCCESS; +} - if (!_.IsFloatVectorType(result_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Result Type to be float vector type: " - << spvOpcodeString(opcode); - } +spv_result_t ValidateImageSparseTexelsResident(ValidationState_t& _, + const Instruction* inst) { + if (!_.IsBoolScalarType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Result Type to be bool scalar type"; + } - if (_.GetDimension(result_type) != 2) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Result Type to have 2 components: " - << spvOpcodeString(opcode); - } + const uint32_t resident_code_type = _.GetOperandTypeId(inst, 2); + if (!_.IsIntScalarType(resident_code_type)) { + return _.diag(SPV_ERROR_INVALID_DATA) + << "Expected Resident Code to be int scalar"; + } - const uint32_t image_type = _.GetOperandTypeId(inst, 2); - if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image operand to be of type OpTypeSampledImage: " - << spvOpcodeString(opcode); - } + return SPV_SUCCESS; +} - ImageTypeInfo info; - if (!GetImageTypeInfo(_, image_type, &info)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Corrupt image type definition"; - } +} // namespace - if (info.dim != SpvDim1D && info.dim != SpvDim2D && - info.dim != SpvDim3D && info.dim != SpvDimCube) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Image 'Dim' must be 1D, 2D, 3D or Cube: " - << spvOpcodeString(opcode); - } +// Validates correctness of image instructions. +spv_result_t ImagePass(ValidationState_t& _, const Instruction* inst) { + const SpvOp opcode = inst->opcode(); + if (IsImplicitLod(opcode)) { + _.current_function().RegisterExecutionModelLimitation( + SpvExecutionModelFragment, + "ImplicitLod instructions require Fragment execution model"); + } - const uint32_t coord_type = _.GetOperandTypeId(inst, 3); - if (_.HasCapability(SpvCapabilityKernel)) { - if (!_.IsFloatScalarOrVectorType(coord_type) && - !_.IsIntScalarOrVectorType(coord_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to be int or float scalar or vector: " - << spvOpcodeString(opcode); - } - } else { - if (!_.IsFloatScalarOrVectorType(coord_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to be float scalar or vector: " - << spvOpcodeString(opcode); - } - } + switch (opcode) { + case SpvOpTypeImage: + return ValidateTypeImage(_, inst); + case SpvOpTypeSampledImage: + return ValidateTypeSampledImage(_, inst); + case SpvOpSampledImage: + return ValidateSampledImage(_, inst); - const uint32_t min_coord_size = GetPlaneCoordSize(info); - const uint32_t actual_coord_size = _.GetDimension(coord_type); - if (min_coord_size > actual_coord_size) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Coordinate to have at least " << min_coord_size - << " components, but given only " << actual_coord_size << ": " - << spvOpcodeString(opcode); - } - break; - } + case SpvOpImageSampleImplicitLod: + case SpvOpImageSampleExplicitLod: + case SpvOpImageSampleProjImplicitLod: + case SpvOpImageSampleProjExplicitLod: + case SpvOpImageSparseSampleImplicitLod: + case SpvOpImageSparseSampleExplicitLod: + return ValidateImageLod(_, inst); - case SpvOpImageQueryLevels: - case SpvOpImageQuerySamples: { - if (!_.IsIntScalarType(result_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Result Type to be int scalar type: " - << spvOpcodeString(opcode); - } + case SpvOpImageSampleDrefImplicitLod: + case SpvOpImageSampleDrefExplicitLod: + case SpvOpImageSampleProjDrefImplicitLod: + case SpvOpImageSampleProjDrefExplicitLod: + case SpvOpImageSparseSampleDrefImplicitLod: + case SpvOpImageSparseSampleDrefExplicitLod: + return ValidateImageDrefLod(_, inst); - const uint32_t image_type = _.GetOperandTypeId(inst, 2); - if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Expected Image to be of type OpTypeImage: " - << spvOpcodeString(opcode); - } + case SpvOpImageFetch: + case SpvOpImageSparseFetch: + return ValidateImageFetch(_, inst); - ImageTypeInfo info; - if (!GetImageTypeInfo(_, image_type, &info)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Corrupt image type definition"; - } + case SpvOpImageGather: + case SpvOpImageDrefGather: + case SpvOpImageSparseGather: + case SpvOpImageSparseDrefGather: + return ValidateImageGather(_, inst); - if (opcode == SpvOpImageQueryLevels) { - if (info.dim != SpvDim1D && info.dim != SpvDim2D && - info.dim != SpvDim3D && info.dim != SpvDimCube) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Image 'Dim' must be 1D, 2D, 3D or Cube: " - << spvOpcodeString(opcode); - } - } else { - assert(opcode == SpvOpImageQuerySamples); - if (info.dim != SpvDim2D) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Image 'Dim' must be 2D: " << spvOpcodeString(opcode); - } - - if (info.multisampled != 1) { - return _.diag(SPV_ERROR_INVALID_DATA) - << "Image 'MS' must be 1: " << spvOpcodeString(opcode); - } - } + case SpvOpImageRead: + case SpvOpImageSparseRead: + return ValidateImageRead(_, inst); - break; - } + case SpvOpImageWrite: + return ValidateImageWrite(_, inst); + + case SpvOpImage: + return ValidateImage(_, inst); + + case SpvOpImageQueryFormat: + case SpvOpImageQueryOrder: + return ValidateImageQueryFormatOrOrder(_, inst); + + case SpvOpImageQuerySizeLod: + return ValidateImageQuerySizeLod(_, inst); + case SpvOpImageQuerySize: + return ValidateImageQuerySize(_, inst); + case SpvOpImageQueryLod: + return ValidateImageQueryLod(_, inst); + + case SpvOpImageQueryLevels: + case SpvOpImageQuerySamples: + return ValidateImageQueryLevelsOrSamples(_, inst); case SpvOpImageSparseSampleProjImplicitLod: case SpvOpImageSparseSampleProjExplicitLod: case SpvOpImageSparseSampleProjDrefImplicitLod: - case SpvOpImageSparseSampleProjDrefExplicitLod: { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) - << ": instruction reserved for future use, " - << "use of this instruction is invalid"; - } - - case SpvOpImageSparseTexelsResident: { - if (!_.IsBoolScalarType(result_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) - << ": expected Result Type to be bool scalar type"; - } + case SpvOpImageSparseSampleProjDrefExplicitLod: + return ValidateImageSparseLod(_, inst); - const uint32_t resident_code_type = _.GetOperandTypeId(inst, 2); - if (!_.IsIntScalarType(resident_code_type)) { - return _.diag(SPV_ERROR_INVALID_DATA) - << spvOpcodeString(opcode) - << ": expected Resident Code to be int scalar"; - } - break; - } + case SpvOpImageSparseTexelsResident: + return ValidateImageSparseTexelsResident(_, inst); default: break; |