val_primitives_test.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // Copyright (c) 2017 LunarG 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 ValidatePrimitives = spvtest::ValidateBase<bool>;
  25. std::string GenerateShaderCode(
  26. const std::string& body,
  27. const std::string& capabilities_and_extensions =
  28. "OpCapability GeometryStreams",
  29. const std::string& execution_model = "Geometry") {
  30. std::ostringstream ss;
  31. ss << capabilities_and_extensions << "\n";
  32. ss << "OpMemoryModel Logical GLSL450\n";
  33. ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
  34. if (execution_model == "Geometry") {
  35. ss << "OpExecutionMode %main InputPoints\n";
  36. ss << "OpExecutionMode %main OutputPoints\n";
  37. }
  38. ss << R"(
  39. %void = OpTypeVoid
  40. %func = OpTypeFunction %void
  41. %f32 = OpTypeFloat 32
  42. %u32 = OpTypeInt 32 0
  43. %u32vec4 = OpTypeVector %u32 4
  44. %f32_0 = OpConstant %f32 0
  45. %u32_0 = OpConstant %u32 0
  46. %u32_1 = OpConstant %u32 1
  47. %u32_2 = OpConstant %u32 2
  48. %u32_3 = OpConstant %u32 3
  49. %u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3
  50. %main = OpFunction %void None %func
  51. %main_entry = OpLabel
  52. )";
  53. ss << body;
  54. ss << R"(
  55. OpReturn
  56. OpFunctionEnd)";
  57. return ss.str();
  58. }
  59. // Returns SPIR-V assembly fragment representing a function call,
  60. // the end of the callee body, and the preamble and body of the called
  61. // function with the given body, but missing the final return and
  62. // function-end. The result is of the form where it can be used in the
  63. // |body| argument to GenerateShaderCode.
  64. std::string CallAndCallee(const std::string& body) {
  65. std::ostringstream ss;
  66. ss << R"(
  67. %placeholder = OpFunctionCall %void %foo
  68. OpReturn
  69. OpFunctionEnd
  70. %foo = OpFunction %void None %func
  71. %foo_entry = OpLabel
  72. )";
  73. ss << body;
  74. return ss.str();
  75. }
  76. // OpEmitVertex doesn't have any parameters, so other validation
  77. // is handled by the binary parser, and generic dominance checks.
  78. TEST_F(ValidatePrimitives, EmitVertexSuccess) {
  79. CompileSuccessfully(
  80. GenerateShaderCode("OpEmitVertex", "OpCapability Geometry"));
  81. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  82. }
  83. TEST_F(ValidatePrimitives, EmitVertexFailMissingCapability) {
  84. CompileSuccessfully(
  85. GenerateShaderCode("OpEmitVertex", "OpCapability Shader", "Vertex"));
  86. EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
  87. EXPECT_THAT(
  88. getDiagnosticString(),
  89. HasSubstr(
  90. "Opcode EmitVertex requires one of these capabilities: Geometry"));
  91. }
  92. TEST_F(ValidatePrimitives, EmitVertexFailWrongExecutionMode) {
  93. CompileSuccessfully(
  94. GenerateShaderCode("OpEmitVertex", "OpCapability Geometry", "Vertex"));
  95. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  96. EXPECT_THAT(
  97. getDiagnosticString(),
  98. HasSubstr("EmitVertex instructions require Geometry execution model"));
  99. }
  100. TEST_F(ValidatePrimitives, EmitVertexFailWrongExecutionModeNestedFunction) {
  101. CompileSuccessfully(GenerateShaderCode(CallAndCallee("OpEmitVertex"),
  102. "OpCapability Geometry", "Vertex"));
  103. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  104. EXPECT_THAT(
  105. getDiagnosticString(),
  106. HasSubstr("EmitVertex instructions require Geometry execution model"));
  107. }
  108. // OpEndPrimitive doesn't have any parameters, so other validation
  109. // is handled by the binary parser, and generic dominance checks.
  110. TEST_F(ValidatePrimitives, EndPrimitiveSuccess) {
  111. CompileSuccessfully(
  112. GenerateShaderCode("OpEndPrimitive", "OpCapability Geometry"));
  113. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  114. }
  115. TEST_F(ValidatePrimitives, EndPrimitiveFailMissingCapability) {
  116. CompileSuccessfully(
  117. GenerateShaderCode("OpEndPrimitive", "OpCapability Shader", "Vertex"));
  118. EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
  119. EXPECT_THAT(
  120. getDiagnosticString(),
  121. HasSubstr(
  122. "Opcode EndPrimitive requires one of these capabilities: Geometry"));
  123. }
  124. TEST_F(ValidatePrimitives, EndPrimitiveFailWrongExecutionMode) {
  125. CompileSuccessfully(
  126. GenerateShaderCode("OpEndPrimitive", "OpCapability Geometry", "Vertex"));
  127. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  128. EXPECT_THAT(
  129. getDiagnosticString(),
  130. HasSubstr("EndPrimitive instructions require Geometry execution model"));
  131. }
  132. TEST_F(ValidatePrimitives, EndPrimitiveFailWrongExecutionModeNestedFunction) {
  133. CompileSuccessfully(GenerateShaderCode(CallAndCallee("OpEndPrimitive"),
  134. "OpCapability Geometry", "Vertex"));
  135. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  136. EXPECT_THAT(
  137. getDiagnosticString(),
  138. HasSubstr("EndPrimitive instructions require Geometry execution model"));
  139. }
  140. TEST_F(ValidatePrimitives, EmitStreamVertexSuccess) {
  141. const std::string body = R"(
  142. OpEmitStreamVertex %u32_0
  143. )";
  144. CompileSuccessfully(GenerateShaderCode(body));
  145. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  146. }
  147. TEST_F(ValidatePrimitives, EmitStreamVertexFailMissingCapability) {
  148. CompileSuccessfully(GenerateShaderCode("OpEmitStreamVertex %u32_0",
  149. "OpCapability Shader", "Vertex"));
  150. EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
  151. EXPECT_THAT(getDiagnosticString(),
  152. HasSubstr("Opcode EmitStreamVertex requires one of these "
  153. "capabilities: GeometryStreams"));
  154. }
  155. TEST_F(ValidatePrimitives, EmitStreamVertexFailWrongExecutionMode) {
  156. CompileSuccessfully(GenerateShaderCode(
  157. "OpEmitStreamVertex %u32_0", "OpCapability GeometryStreams", "Vertex"));
  158. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  159. EXPECT_THAT(
  160. getDiagnosticString(),
  161. HasSubstr(
  162. "EmitStreamVertex instructions require Geometry execution model"));
  163. }
  164. TEST_F(ValidatePrimitives,
  165. EmitStreamVertexFailWrongExecutionModeNestedFunction) {
  166. CompileSuccessfully(
  167. GenerateShaderCode(CallAndCallee("OpEmitStreamVertex %u32_0"),
  168. "OpCapability GeometryStreams", "Vertex"));
  169. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  170. EXPECT_THAT(
  171. getDiagnosticString(),
  172. HasSubstr(
  173. "EmitStreamVertex instructions require Geometry execution model"));
  174. }
  175. TEST_F(ValidatePrimitives, EmitStreamVertexNonInt) {
  176. const std::string body = R"(
  177. OpEmitStreamVertex %f32_0
  178. )";
  179. CompileSuccessfully(GenerateShaderCode(body));
  180. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  181. EXPECT_THAT(getDiagnosticString(),
  182. HasSubstr("EmitStreamVertex: "
  183. "expected Stream to be int scalar"));
  184. }
  185. TEST_F(ValidatePrimitives, EmitStreamVertexNonScalar) {
  186. const std::string body = R"(
  187. OpEmitStreamVertex %u32vec4_0123
  188. )";
  189. CompileSuccessfully(GenerateShaderCode(body));
  190. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  191. EXPECT_THAT(getDiagnosticString(),
  192. HasSubstr("EmitStreamVertex: "
  193. "expected Stream to be int scalar"));
  194. }
  195. TEST_F(ValidatePrimitives, EmitStreamVertexNonConstant) {
  196. const std::string body = R"(
  197. %val1 = OpIAdd %u32 %u32_0 %u32_1
  198. OpEmitStreamVertex %val1
  199. )";
  200. CompileSuccessfully(GenerateShaderCode(body));
  201. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  202. EXPECT_THAT(getDiagnosticString(),
  203. HasSubstr("EmitStreamVertex: "
  204. "expected Stream to be constant instruction"));
  205. }
  206. TEST_F(ValidatePrimitives, EndStreamPrimitiveSuccess) {
  207. const std::string body = R"(
  208. OpEndStreamPrimitive %u32_0
  209. )";
  210. CompileSuccessfully(GenerateShaderCode(body));
  211. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  212. }
  213. TEST_F(ValidatePrimitives, EndStreamPrimitiveFailMissingCapability) {
  214. CompileSuccessfully(GenerateShaderCode("OpEndStreamPrimitive %u32_0",
  215. "OpCapability Shader", "Vertex"));
  216. EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
  217. EXPECT_THAT(getDiagnosticString(),
  218. HasSubstr("Opcode EndStreamPrimitive requires one of these "
  219. "capabilities: GeometryStreams"));
  220. }
  221. TEST_F(ValidatePrimitives, EndStreamPrimitiveFailWrongExecutionMode) {
  222. CompileSuccessfully(GenerateShaderCode(
  223. "OpEndStreamPrimitive %u32_0", "OpCapability GeometryStreams", "Vertex"));
  224. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  225. EXPECT_THAT(
  226. getDiagnosticString(),
  227. HasSubstr(
  228. "EndStreamPrimitive instructions require Geometry execution model"));
  229. }
  230. TEST_F(ValidatePrimitives,
  231. EndStreamPrimitiveFailWrongExecutionModeNestedFunction) {
  232. CompileSuccessfully(
  233. GenerateShaderCode(CallAndCallee("OpEndStreamPrimitive %u32_0"),
  234. "OpCapability GeometryStreams", "Vertex"));
  235. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  236. EXPECT_THAT(
  237. getDiagnosticString(),
  238. HasSubstr(
  239. "EndStreamPrimitive instructions require Geometry execution model"));
  240. }
  241. TEST_F(ValidatePrimitives, EndStreamPrimitiveNonInt) {
  242. const std::string body = R"(
  243. OpEndStreamPrimitive %f32_0
  244. )";
  245. CompileSuccessfully(GenerateShaderCode(body));
  246. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  247. EXPECT_THAT(getDiagnosticString(),
  248. HasSubstr("EndStreamPrimitive: "
  249. "expected Stream to be int scalar"));
  250. }
  251. TEST_F(ValidatePrimitives, EndStreamPrimitiveNonScalar) {
  252. const std::string body = R"(
  253. OpEndStreamPrimitive %u32vec4_0123
  254. )";
  255. CompileSuccessfully(GenerateShaderCode(body));
  256. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  257. EXPECT_THAT(getDiagnosticString(),
  258. HasSubstr("EndStreamPrimitive: "
  259. "expected Stream to be int scalar"));
  260. }
  261. TEST_F(ValidatePrimitives, EndStreamPrimitiveNonConstant) {
  262. const std::string body = R"(
  263. %val1 = OpIAdd %u32 %u32_0 %u32_1
  264. OpEndStreamPrimitive %val1
  265. )";
  266. CompileSuccessfully(GenerateShaderCode(body));
  267. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  268. EXPECT_THAT(getDiagnosticString(),
  269. HasSubstr("EndStreamPrimitive: "
  270. "expected Stream to be constant instruction"));
  271. }
  272. } // namespace
  273. } // namespace val
  274. } // namespace spvtools