1fd4e5da5Sopenharmony_ci// Copyright (c) 2017 Google Inc. 2fd4e5da5Sopenharmony_ci// 3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License. 5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at 6fd4e5da5Sopenharmony_ci// 7fd4e5da5Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8fd4e5da5Sopenharmony_ci// 9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and 13fd4e5da5Sopenharmony_ci// limitations under the License. 14fd4e5da5Sopenharmony_ci 15fd4e5da5Sopenharmony_ci#include <sstream> 16fd4e5da5Sopenharmony_ci#include <string> 17fd4e5da5Sopenharmony_ci 18fd4e5da5Sopenharmony_ci#include "gmock/gmock.h" 19fd4e5da5Sopenharmony_ci#include "test/unit_spirv.h" 20fd4e5da5Sopenharmony_ci#include "test/val/val_fixtures.h" 21fd4e5da5Sopenharmony_ci 22fd4e5da5Sopenharmony_cinamespace spvtools { 23fd4e5da5Sopenharmony_cinamespace val { 24fd4e5da5Sopenharmony_cinamespace { 25fd4e5da5Sopenharmony_ci 26fd4e5da5Sopenharmony_ciusing ::testing::HasSubstr; 27fd4e5da5Sopenharmony_ciusing ::testing::Not; 28fd4e5da5Sopenharmony_ci 29fd4e5da5Sopenharmony_ciusing ValidateDerivatives = spvtest::ValidateBase<bool>; 30fd4e5da5Sopenharmony_ci 31fd4e5da5Sopenharmony_cistd::string GenerateShaderCode( 32fd4e5da5Sopenharmony_ci const std::string& body, 33fd4e5da5Sopenharmony_ci const std::string& capabilities_and_extensions = "", 34fd4e5da5Sopenharmony_ci const std::string& execution_model = "Fragment") { 35fd4e5da5Sopenharmony_ci std::stringstream ss; 36fd4e5da5Sopenharmony_ci ss << R"( 37fd4e5da5Sopenharmony_ciOpCapability Shader 38fd4e5da5Sopenharmony_ciOpCapability DerivativeControl 39fd4e5da5Sopenharmony_ci)"; 40fd4e5da5Sopenharmony_ci 41fd4e5da5Sopenharmony_ci ss << capabilities_and_extensions; 42fd4e5da5Sopenharmony_ci ss << "OpMemoryModel Logical GLSL450\n"; 43fd4e5da5Sopenharmony_ci ss << "OpEntryPoint " << execution_model << " %main \"main\"" 44fd4e5da5Sopenharmony_ci << " %f32_var_input" 45fd4e5da5Sopenharmony_ci << " %f32vec4_var_input" 46fd4e5da5Sopenharmony_ci << "\n"; 47fd4e5da5Sopenharmony_ci if (execution_model == "Fragment") { 48fd4e5da5Sopenharmony_ci ss << "OpExecutionMode %main OriginUpperLeft\n"; 49fd4e5da5Sopenharmony_ci } 50fd4e5da5Sopenharmony_ci 51fd4e5da5Sopenharmony_ci ss << R"( 52fd4e5da5Sopenharmony_ci%void = OpTypeVoid 53fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void 54fd4e5da5Sopenharmony_ci%bool = OpTypeBool 55fd4e5da5Sopenharmony_ci%f32 = OpTypeFloat 32 56fd4e5da5Sopenharmony_ci%u32 = OpTypeInt 32 0 57fd4e5da5Sopenharmony_ci%s32 = OpTypeInt 32 1 58fd4e5da5Sopenharmony_ci%f32vec4 = OpTypeVector %f32 4 59fd4e5da5Sopenharmony_ci 60fd4e5da5Sopenharmony_ci%f32_ptr_input = OpTypePointer Input %f32 61fd4e5da5Sopenharmony_ci%f32_var_input = OpVariable %f32_ptr_input Input 62fd4e5da5Sopenharmony_ci 63fd4e5da5Sopenharmony_ci%f32vec4_ptr_input = OpTypePointer Input %f32vec4 64fd4e5da5Sopenharmony_ci%f32vec4_var_input = OpVariable %f32vec4_ptr_input Input 65fd4e5da5Sopenharmony_ci)"; 66fd4e5da5Sopenharmony_ci 67fd4e5da5Sopenharmony_ci if (capabilities_and_extensions.find("OpCapability Float16") != 68fd4e5da5Sopenharmony_ci std::string::npos) { 69fd4e5da5Sopenharmony_ci ss << "%f16 = OpTypeFloat 16\n" 70fd4e5da5Sopenharmony_ci << "%f16vec4 = OpTypeVector %f16 4\n" 71fd4e5da5Sopenharmony_ci << "%f16_0 = OpConstantNull %f16\n" 72fd4e5da5Sopenharmony_ci << "%f16vec4_0 = OpConstantNull %f16vec4\n"; 73fd4e5da5Sopenharmony_ci } 74fd4e5da5Sopenharmony_ci 75fd4e5da5Sopenharmony_ci ss << R"( 76fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func 77fd4e5da5Sopenharmony_ci%main_entry = OpLabel 78fd4e5da5Sopenharmony_ci)"; 79fd4e5da5Sopenharmony_ci 80fd4e5da5Sopenharmony_ci ss << body; 81fd4e5da5Sopenharmony_ci 82fd4e5da5Sopenharmony_ci ss << R"( 83fd4e5da5Sopenharmony_ciOpReturn 84fd4e5da5Sopenharmony_ciOpFunctionEnd)"; 85fd4e5da5Sopenharmony_ci 86fd4e5da5Sopenharmony_ci return ss.str(); 87fd4e5da5Sopenharmony_ci} 88fd4e5da5Sopenharmony_ci 89fd4e5da5Sopenharmony_ciTEST_F(ValidateDerivatives, ScalarSuccess) { 90fd4e5da5Sopenharmony_ci const std::string body = R"( 91fd4e5da5Sopenharmony_ci%f32_var = OpLoad %f32 %f32_var_input 92fd4e5da5Sopenharmony_ci%val1 = OpDPdx %f32 %f32_var 93fd4e5da5Sopenharmony_ci%val2 = OpDPdy %f32 %f32_var 94fd4e5da5Sopenharmony_ci%val3 = OpFwidth %f32 %f32_var 95fd4e5da5Sopenharmony_ci%val4 = OpDPdxFine %f32 %f32_var 96fd4e5da5Sopenharmony_ci%val5 = OpDPdyFine %f32 %f32_var 97fd4e5da5Sopenharmony_ci%val6 = OpFwidthFine %f32 %f32_var 98fd4e5da5Sopenharmony_ci%val7 = OpDPdxCoarse %f32 %f32_var 99fd4e5da5Sopenharmony_ci%val8 = OpDPdyCoarse %f32 %f32_var 100fd4e5da5Sopenharmony_ci%val9 = OpFwidthCoarse %f32 %f32_var 101fd4e5da5Sopenharmony_ci)"; 102fd4e5da5Sopenharmony_ci 103fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body).c_str()); 104fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 105fd4e5da5Sopenharmony_ci} 106fd4e5da5Sopenharmony_ci 107fd4e5da5Sopenharmony_ciTEST_F(ValidateDerivatives, VectorSuccess) { 108fd4e5da5Sopenharmony_ci const std::string body = R"( 109fd4e5da5Sopenharmony_ci%f32vec4_var = OpLoad %f32vec4 %f32vec4_var_input 110fd4e5da5Sopenharmony_ci%val1 = OpDPdx %f32vec4 %f32vec4_var 111fd4e5da5Sopenharmony_ci%val2 = OpDPdy %f32vec4 %f32vec4_var 112fd4e5da5Sopenharmony_ci%val3 = OpFwidth %f32vec4 %f32vec4_var 113fd4e5da5Sopenharmony_ci%val4 = OpDPdxFine %f32vec4 %f32vec4_var 114fd4e5da5Sopenharmony_ci%val5 = OpDPdyFine %f32vec4 %f32vec4_var 115fd4e5da5Sopenharmony_ci%val6 = OpFwidthFine %f32vec4 %f32vec4_var 116fd4e5da5Sopenharmony_ci%val7 = OpDPdxCoarse %f32vec4 %f32vec4_var 117fd4e5da5Sopenharmony_ci%val8 = OpDPdyCoarse %f32vec4 %f32vec4_var 118fd4e5da5Sopenharmony_ci%val9 = OpFwidthCoarse %f32vec4 %f32vec4_var 119fd4e5da5Sopenharmony_ci)"; 120fd4e5da5Sopenharmony_ci 121fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body).c_str()); 122fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 123fd4e5da5Sopenharmony_ci} 124fd4e5da5Sopenharmony_ci 125fd4e5da5Sopenharmony_ciTEST_F(ValidateDerivatives, OpDPdxWrongResultType) { 126fd4e5da5Sopenharmony_ci const std::string body = R"( 127fd4e5da5Sopenharmony_ci%f32_var = OpLoad %f32 %f32_var_input 128fd4e5da5Sopenharmony_ci%val1 = OpDPdx %u32 %f32vec4 129fd4e5da5Sopenharmony_ci)"; 130fd4e5da5Sopenharmony_ci 131fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body).c_str()); 132fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 133fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand '10[%v4float]' cannot " 134fd4e5da5Sopenharmony_ci "be a type")); 135fd4e5da5Sopenharmony_ci} 136fd4e5da5Sopenharmony_ci 137fd4e5da5Sopenharmony_ciTEST_F(ValidateDerivatives, OpDPdxWrongPType) { 138fd4e5da5Sopenharmony_ci const std::string body = R"( 139fd4e5da5Sopenharmony_ci%f32vec4_var = OpLoad %f32vec4 %f32vec4_var_input 140fd4e5da5Sopenharmony_ci%val1 = OpDPdx %f32 %f32vec4_var 141fd4e5da5Sopenharmony_ci)"; 142fd4e5da5Sopenharmony_ci 143fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body).c_str()); 144fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 145fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 146fd4e5da5Sopenharmony_ci HasSubstr("Expected P type and Result Type to be the same: " 147fd4e5da5Sopenharmony_ci "DPdx")); 148fd4e5da5Sopenharmony_ci} 149fd4e5da5Sopenharmony_ci 150fd4e5da5Sopenharmony_ciTEST_F(ValidateDerivatives, OpDPdxWrongExecutionModel) { 151fd4e5da5Sopenharmony_ci const std::string body = R"( 152fd4e5da5Sopenharmony_ci%f32vec4_var = OpLoad %f32vec4 %f32vec4_var_input 153fd4e5da5Sopenharmony_ci%val1 = OpDPdx %f32vec4 %f32vec4_var 154fd4e5da5Sopenharmony_ci)"; 155fd4e5da5Sopenharmony_ci 156fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body, "", "Vertex").c_str()); 157fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 158fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 159fd4e5da5Sopenharmony_ci HasSubstr("Derivative instructions require Fragment or GLCompute " 160fd4e5da5Sopenharmony_ci "execution model: DPdx")); 161fd4e5da5Sopenharmony_ci} 162fd4e5da5Sopenharmony_ci 163fd4e5da5Sopenharmony_ciTEST_F(ValidateDerivatives, NoExecutionModeGLCompute) { 164fd4e5da5Sopenharmony_ci const std::string spirv = R"( 165fd4e5da5Sopenharmony_ciOpCapability Shader 166fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 167fd4e5da5Sopenharmony_ciOpEntryPoint GLCompute %main "main" 168fd4e5da5Sopenharmony_ci%void = OpTypeVoid 169fd4e5da5Sopenharmony_ci%float = OpTypeFloat 32 170fd4e5da5Sopenharmony_ci%float4 = OpTypeVector %float 4 171fd4e5da5Sopenharmony_ci%undef = OpUndef %float4 172fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 173fd4e5da5Sopenharmony_ci%main = OpFunction %void None %void_fn 174fd4e5da5Sopenharmony_ci%entry = OpLabel 175fd4e5da5Sopenharmony_ci%derivative = OpDPdy %float4 %undef 176fd4e5da5Sopenharmony_ciOpReturn 177fd4e5da5Sopenharmony_ciOpFunctionEnd 178fd4e5da5Sopenharmony_ci)"; 179fd4e5da5Sopenharmony_ci 180fd4e5da5Sopenharmony_ci CompileSuccessfully(spirv); 181fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 182fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 183fd4e5da5Sopenharmony_ci HasSubstr("Derivative instructions require " 184fd4e5da5Sopenharmony_ci "DerivativeGroupQuadsNV or DerivativeGroupLinearNV " 185fd4e5da5Sopenharmony_ci "execution mode for GLCompute execution model")); 186fd4e5da5Sopenharmony_ci} 187fd4e5da5Sopenharmony_ci 188fd4e5da5Sopenharmony_ciusing ValidateHalfDerivatives = spvtest::ValidateBase<std::string>; 189fd4e5da5Sopenharmony_ci 190fd4e5da5Sopenharmony_ciTEST_P(ValidateHalfDerivatives, ScalarFailure) { 191fd4e5da5Sopenharmony_ci const std::string op = GetParam(); 192fd4e5da5Sopenharmony_ci const std::string body = "%val = " + op + " %f16 %f16_0\n"; 193fd4e5da5Sopenharmony_ci 194fd4e5da5Sopenharmony_ci CompileSuccessfully( 195fd4e5da5Sopenharmony_ci GenerateShaderCode(body, "OpCapability Float16\n").c_str()); 196fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 197fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 198fd4e5da5Sopenharmony_ci HasSubstr("Result type component width must be 32 bits")); 199fd4e5da5Sopenharmony_ci} 200fd4e5da5Sopenharmony_ci 201fd4e5da5Sopenharmony_ciTEST_P(ValidateHalfDerivatives, VectorFailure) { 202fd4e5da5Sopenharmony_ci const std::string op = GetParam(); 203fd4e5da5Sopenharmony_ci const std::string body = "%val = " + op + " %f16vec4 %f16vec4_0\n"; 204fd4e5da5Sopenharmony_ci 205fd4e5da5Sopenharmony_ci CompileSuccessfully( 206fd4e5da5Sopenharmony_ci GenerateShaderCode(body, "OpCapability Float16\n").c_str()); 207fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 208fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 209fd4e5da5Sopenharmony_ci HasSubstr("Result type component width must be 32 bits")); 210fd4e5da5Sopenharmony_ci} 211fd4e5da5Sopenharmony_ci 212fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(HalfDerivatives, ValidateHalfDerivatives, 213fd4e5da5Sopenharmony_ci ::testing::Values("OpDPdx", "OpDPdy", "OpFwidth", 214fd4e5da5Sopenharmony_ci "OpDPdxFine", "OpDPdyFine", 215fd4e5da5Sopenharmony_ci "OpFwidthFine", "OpDPdxCoarse", 216fd4e5da5Sopenharmony_ci "OpDPdyCoarse", "OpFwidthCoarse")); 217fd4e5da5Sopenharmony_ci 218fd4e5da5Sopenharmony_ci} // namespace 219fd4e5da5Sopenharmony_ci} // namespace val 220fd4e5da5Sopenharmony_ci} // namespace spvtools 221