val_derivatives_test.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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. #include <sstream>
  15. #include <string>
  16. #include "gmock/gmock.h"
  17. #include "test/unit_spirv.h"
  18. #include "test/val/val_fixtures.h"
  19. namespace spvtools {
  20. namespace val {
  21. namespace {
  22. using ::testing::HasSubstr;
  23. using ::testing::Not;
  24. using ValidateDerivatives = spvtest::ValidateBase<bool>;
  25. std::string GenerateShaderCode(
  26. const std::string& body,
  27. const std::string& capabilities_and_extensions = "",
  28. const std::string& execution_model = "Fragment") {
  29. std::stringstream ss;
  30. ss << R"(
  31. OpCapability Shader
  32. OpCapability DerivativeControl
  33. )";
  34. ss << capabilities_and_extensions;
  35. ss << "OpMemoryModel Logical GLSL450\n";
  36. ss << "OpEntryPoint " << execution_model << " %main \"main\""
  37. << " %f32_var_input"
  38. << " %f32vec4_var_input"
  39. << "\n";
  40. if (execution_model == "Fragment") {
  41. ss << "OpExecutionMode %main OriginUpperLeft\n";
  42. }
  43. ss << R"(
  44. %void = OpTypeVoid
  45. %func = OpTypeFunction %void
  46. %bool = OpTypeBool
  47. %f32 = OpTypeFloat 32
  48. %u32 = OpTypeInt 32 0
  49. %s32 = OpTypeInt 32 1
  50. %f32vec4 = OpTypeVector %f32 4
  51. %f32_ptr_input = OpTypePointer Input %f32
  52. %f32_var_input = OpVariable %f32_ptr_input Input
  53. %f32vec4_ptr_input = OpTypePointer Input %f32vec4
  54. %f32vec4_var_input = OpVariable %f32vec4_ptr_input Input
  55. )";
  56. if (capabilities_and_extensions.find("OpCapability Float16") !=
  57. std::string::npos) {
  58. ss << "%f16 = OpTypeFloat 16\n"
  59. << "%f16vec4 = OpTypeVector %f16 4\n"
  60. << "%f16_0 = OpConstantNull %f16\n"
  61. << "%f16vec4_0 = OpConstantNull %f16vec4\n";
  62. }
  63. ss << R"(
  64. %main = OpFunction %void None %func
  65. %main_entry = OpLabel
  66. )";
  67. ss << body;
  68. ss << R"(
  69. OpReturn
  70. OpFunctionEnd)";
  71. return ss.str();
  72. }
  73. TEST_F(ValidateDerivatives, ScalarSuccess) {
  74. const std::string body = R"(
  75. %f32_var = OpLoad %f32 %f32_var_input
  76. %val1 = OpDPdx %f32 %f32_var
  77. %val2 = OpDPdy %f32 %f32_var
  78. %val3 = OpFwidth %f32 %f32_var
  79. %val4 = OpDPdxFine %f32 %f32_var
  80. %val5 = OpDPdyFine %f32 %f32_var
  81. %val6 = OpFwidthFine %f32 %f32_var
  82. %val7 = OpDPdxCoarse %f32 %f32_var
  83. %val8 = OpDPdyCoarse %f32 %f32_var
  84. %val9 = OpFwidthCoarse %f32 %f32_var
  85. )";
  86. CompileSuccessfully(GenerateShaderCode(body).c_str());
  87. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  88. }
  89. TEST_F(ValidateDerivatives, VectorSuccess) {
  90. const std::string body = R"(
  91. %f32vec4_var = OpLoad %f32vec4 %f32vec4_var_input
  92. %val1 = OpDPdx %f32vec4 %f32vec4_var
  93. %val2 = OpDPdy %f32vec4 %f32vec4_var
  94. %val3 = OpFwidth %f32vec4 %f32vec4_var
  95. %val4 = OpDPdxFine %f32vec4 %f32vec4_var
  96. %val5 = OpDPdyFine %f32vec4 %f32vec4_var
  97. %val6 = OpFwidthFine %f32vec4 %f32vec4_var
  98. %val7 = OpDPdxCoarse %f32vec4 %f32vec4_var
  99. %val8 = OpDPdyCoarse %f32vec4 %f32vec4_var
  100. %val9 = OpFwidthCoarse %f32vec4 %f32vec4_var
  101. )";
  102. CompileSuccessfully(GenerateShaderCode(body).c_str());
  103. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  104. }
  105. TEST_F(ValidateDerivatives, OpDPdxWrongResultType) {
  106. const std::string body = R"(
  107. %f32_var = OpLoad %f32 %f32_var_input
  108. %val1 = OpDPdx %u32 %f32vec4
  109. )";
  110. CompileSuccessfully(GenerateShaderCode(body).c_str());
  111. ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  112. EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand '10[%v4float]' cannot "
  113. "be a type"));
  114. }
  115. TEST_F(ValidateDerivatives, OpDPdxWrongPType) {
  116. const std::string body = R"(
  117. %f32vec4_var = OpLoad %f32vec4 %f32vec4_var_input
  118. %val1 = OpDPdx %f32 %f32vec4_var
  119. )";
  120. CompileSuccessfully(GenerateShaderCode(body).c_str());
  121. ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  122. EXPECT_THAT(getDiagnosticString(),
  123. HasSubstr("Expected P type and Result Type to be the same: "
  124. "DPdx"));
  125. }
  126. TEST_F(ValidateDerivatives, OpDPdxWrongExecutionModel) {
  127. const std::string body = R"(
  128. %f32vec4_var = OpLoad %f32vec4 %f32vec4_var_input
  129. %val1 = OpDPdx %f32vec4 %f32vec4_var
  130. )";
  131. CompileSuccessfully(GenerateShaderCode(body, "", "Vertex").c_str());
  132. ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  133. EXPECT_THAT(getDiagnosticString(),
  134. HasSubstr("Derivative instructions require Fragment, GLCompute, "
  135. "MeshEXT or TaskEXT execution model: DPdx"));
  136. }
  137. TEST_F(ValidateDerivatives, NoExecutionModeGLCompute) {
  138. const std::string spirv = R"(
  139. OpCapability Shader
  140. OpMemoryModel Logical GLSL450
  141. OpEntryPoint GLCompute %main "main"
  142. %void = OpTypeVoid
  143. %float = OpTypeFloat 32
  144. %float4 = OpTypeVector %float 4
  145. %undef = OpUndef %float4
  146. %void_fn = OpTypeFunction %void
  147. %main = OpFunction %void None %void_fn
  148. %entry = OpLabel
  149. %derivative = OpDPdy %float4 %undef
  150. OpReturn
  151. OpFunctionEnd
  152. )";
  153. CompileSuccessfully(spirv);
  154. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  155. EXPECT_THAT(getDiagnosticString(),
  156. HasSubstr("Derivative instructions require "
  157. "DerivativeGroupQuadsKHR or DerivativeGroupLinearKHR "
  158. "execution mode for GLCompute, MeshEXT or TaskEXT "
  159. "execution model"));
  160. }
  161. using ValidateHalfDerivatives = spvtest::ValidateBase<std::string>;
  162. TEST_P(ValidateHalfDerivatives, ScalarFailure) {
  163. const std::string op = GetParam();
  164. const std::string body = "%val = " + op + " %f16 %f16_0\n";
  165. CompileSuccessfully(
  166. GenerateShaderCode(body, "OpCapability Float16\n").c_str());
  167. ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  168. EXPECT_THAT(getDiagnosticString(),
  169. HasSubstr("Result type component width must be 32 bits"));
  170. }
  171. TEST_P(ValidateHalfDerivatives, VectorFailure) {
  172. const std::string op = GetParam();
  173. const std::string body = "%val = " + op + " %f16vec4 %f16vec4_0\n";
  174. CompileSuccessfully(
  175. GenerateShaderCode(body, "OpCapability Float16\n").c_str());
  176. ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  177. EXPECT_THAT(getDiagnosticString(),
  178. HasSubstr("Result type component width must be 32 bits"));
  179. }
  180. INSTANTIATE_TEST_SUITE_P(HalfDerivatives, ValidateHalfDerivatives,
  181. ::testing::Values("OpDPdx", "OpDPdy", "OpFwidth",
  182. "OpDPdxFine", "OpDPdyFine",
  183. "OpFwidthFine", "OpDPdxCoarse",
  184. "OpDPdyCoarse", "OpFwidthCoarse"));
  185. } // namespace
  186. } // namespace val
  187. } // namespace spvtools