convert_to_sampled_image_test.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. // Copyright (c) 2021 Google LLC
  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 <vector>
  15. #include "gmock/gmock.h"
  16. #include "source/opt/convert_to_sampled_image_pass.h"
  17. #include "test/opt/pass_fixture.h"
  18. #include "test/opt/pass_utils.h"
  19. namespace spvtools {
  20. namespace opt {
  21. namespace {
  22. using testing::Eq;
  23. using VectorOfDescriptorSetAndBindingPairs =
  24. std::vector<DescriptorSetAndBinding>;
  25. struct DescriptorSetAndBindingStringParsingTestCase {
  26. const char* descriptor_set_binding_str;
  27. bool expect_success;
  28. VectorOfDescriptorSetAndBindingPairs expected_descriptor_set_binding_pairs;
  29. };
  30. using DescriptorSetAndBindingStringParsingTest =
  31. ::testing::TestWithParam<DescriptorSetAndBindingStringParsingTestCase>;
  32. TEST_P(DescriptorSetAndBindingStringParsingTest, TestCase) {
  33. const auto& tc = GetParam();
  34. auto actual_descriptor_set_binding_pairs =
  35. ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
  36. tc.descriptor_set_binding_str);
  37. if (tc.expect_success) {
  38. EXPECT_NE(nullptr, actual_descriptor_set_binding_pairs);
  39. if (actual_descriptor_set_binding_pairs) {
  40. EXPECT_THAT(*actual_descriptor_set_binding_pairs,
  41. Eq(tc.expected_descriptor_set_binding_pairs));
  42. }
  43. } else {
  44. EXPECT_EQ(nullptr, actual_descriptor_set_binding_pairs);
  45. }
  46. }
  47. INSTANTIATE_TEST_SUITE_P(
  48. ValidString, DescriptorSetAndBindingStringParsingTest,
  49. ::testing::ValuesIn(std::vector<
  50. DescriptorSetAndBindingStringParsingTestCase>{
  51. // 0. empty vector
  52. {"", true, VectorOfDescriptorSetAndBindingPairs({})},
  53. // 1. one pair
  54. {"100:1024", true,
  55. VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{100,
  56. 1024}})},
  57. // 2. two pairs
  58. {"100:1024 200:2048", true,
  59. VectorOfDescriptorSetAndBindingPairs(
  60. {DescriptorSetAndBinding{100, 1024},
  61. DescriptorSetAndBinding{200, 2048}})},
  62. // 3. spaces between entries
  63. {"100:1024 \n \r \t \v \f 200:2048", true,
  64. VectorOfDescriptorSetAndBindingPairs(
  65. {DescriptorSetAndBinding{100, 1024},
  66. DescriptorSetAndBinding{200, 2048}})},
  67. // 4. \t, \n, \r and spaces before spec id
  68. {" \n \r\t \t \v \f 100:1024", true,
  69. VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{100,
  70. 1024}})},
  71. // 5. \t, \n, \r and spaces after value string
  72. {"100:1024 \n \r\t \t \v \f ", true,
  73. VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{100,
  74. 1024}})},
  75. // 6. maximum spec id
  76. {"4294967295:0", true,
  77. VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{
  78. 4294967295, 0}})},
  79. // 7. minimum spec id
  80. {"0:100", true,
  81. VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{0,
  82. 100}})},
  83. // 8. multiple entries
  84. {"101:1 102:2 103:3 104:4 200:201 9999:1000", true,
  85. VectorOfDescriptorSetAndBindingPairs(
  86. {DescriptorSetAndBinding{101, 1}, DescriptorSetAndBinding{102, 2},
  87. DescriptorSetAndBinding{103, 3}, DescriptorSetAndBinding{104, 4},
  88. DescriptorSetAndBinding{200, 201},
  89. DescriptorSetAndBinding{9999, 1000}})},
  90. }));
  91. INSTANTIATE_TEST_SUITE_P(
  92. InvalidString, DescriptorSetAndBindingStringParsingTest,
  93. ::testing::ValuesIn(
  94. std::vector<DescriptorSetAndBindingStringParsingTestCase>{
  95. // 0. missing default value
  96. {"100:", false, VectorOfDescriptorSetAndBindingPairs{}},
  97. // 1. descriptor set is not an integer
  98. {"100.0:200", false, VectorOfDescriptorSetAndBindingPairs{}},
  99. // 2. descriptor set is not a number
  100. {"something_not_a_number:1", false,
  101. VectorOfDescriptorSetAndBindingPairs{}},
  102. // 3. only descriptor set number
  103. {"100", false, VectorOfDescriptorSetAndBindingPairs{}},
  104. // 4. empty descriptor set
  105. {":3", false, VectorOfDescriptorSetAndBindingPairs{}},
  106. // 5. only colon
  107. {":", false, VectorOfDescriptorSetAndBindingPairs{}},
  108. // 6. descriptor set overflow
  109. {"4294967296:200", false, VectorOfDescriptorSetAndBindingPairs{}},
  110. // 7. descriptor set less than 0
  111. {"-1:200", false, VectorOfDescriptorSetAndBindingPairs{}},
  112. // 8. nullptr
  113. {nullptr, false, VectorOfDescriptorSetAndBindingPairs{}},
  114. // 9. only a number is invalid
  115. {"1234", false, VectorOfDescriptorSetAndBindingPairs{}},
  116. // 10. invalid entry separator
  117. {"12:34;23:14", false, VectorOfDescriptorSetAndBindingPairs{}},
  118. // 11. invalid descriptor set and default value separator
  119. {"12@34", false, VectorOfDescriptorSetAndBindingPairs{}},
  120. // 12. spaces before colon
  121. {"100 :1024", false, VectorOfDescriptorSetAndBindingPairs{}},
  122. // 13. spaces after colon
  123. {"100: 1024", false, VectorOfDescriptorSetAndBindingPairs{}},
  124. // 14. descriptor set represented in hex float format is invalid
  125. {"0x3p10:200", false, VectorOfDescriptorSetAndBindingPairs{}},
  126. }));
  127. std::string BuildShader(const char* shader_decorate_instructions,
  128. const char* shader_image_and_sampler_variables,
  129. const char* shader_body) {
  130. // Base HLSL code:
  131. //
  132. // SamplerState sam : register(s2);
  133. // Texture2D <float4> texture : register(t5);
  134. //
  135. // float4 main() : SV_TARGET {
  136. // return texture.SampleLevel(sam, float2(1, 2), 10, 2);
  137. // }
  138. std::stringstream ss;
  139. ss << R"(
  140. OpCapability Shader
  141. OpMemoryModel Logical GLSL450
  142. OpEntryPoint Fragment %main "main" %out_var_SV_TARGET
  143. OpExecutionMode %main OriginUpperLeft
  144. OpSource HLSL 600
  145. OpName %type_sampler "type.sampler"
  146. OpName %type_2d_image "type.2d.image"
  147. OpName %out_var_SV_TARGET "out.var.SV_TARGET"
  148. OpName %main "main"
  149. OpName %type_sampled_image "type.sampled.image"
  150. OpDecorate %out_var_SV_TARGET Location 0
  151. )";
  152. ss << shader_decorate_instructions;
  153. ss << R"(
  154. %float = OpTypeFloat 32
  155. %float_1 = OpConstant %float 1
  156. %float_2 = OpConstant %float 2
  157. %v2float = OpTypeVector %float 2
  158. %12 = OpConstantComposite %v2float %float_1 %float_2
  159. %float_10 = OpConstant %float 10
  160. %int = OpTypeInt 32 1
  161. %int_2 = OpConstant %int 2
  162. %v2int = OpTypeVector %int 2
  163. %17 = OpConstantComposite %v2int %int_2 %int_2
  164. %type_sampler = OpTypeSampler
  165. %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
  166. %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
  167. %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
  168. %v4float = OpTypeVector %float 4
  169. %_ptr_Output_v4float = OpTypePointer Output %v4float
  170. %void = OpTypeVoid
  171. %23 = OpTypeFunction %void
  172. %type_sampled_image = OpTypeSampledImage %type_2d_image
  173. )";
  174. ss << shader_image_and_sampler_variables;
  175. ss << R"(
  176. %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
  177. %main = OpFunction %void None %23
  178. %24 = OpLabel
  179. )";
  180. ss << shader_body;
  181. ss << R"(
  182. OpReturn
  183. OpFunctionEnd
  184. )";
  185. return ss.str();
  186. }
  187. using ConvertToSampledImageTest = PassTest<::testing::Test>;
  188. TEST_F(ConvertToSampledImageTest, Texture2DAndSamplerToSampledImage) {
  189. const std::string shader = BuildShader(
  190. R"(
  191. OpDecorate %sam DescriptorSet 0
  192. OpDecorate %sam Binding 5
  193. OpDecorate %texture DescriptorSet 0
  194. OpDecorate %texture Binding 5
  195. )",
  196. R"(
  197. ; CHECK-NOT: OpVariable %_ptr_UniformConstant_type_2d_image
  198. ; CHECK: [[tex:%\w+]] = OpVariable %_ptr_UniformConstant_type_sampled_image UniformConstant
  199. %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
  200. %texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
  201. )",
  202. R"(
  203. ; CHECK: [[load:%\w+]] = OpLoad %type_sampled_image [[tex]]
  204. ; CHECK: OpImageSampleExplicitLod %v4float [[load]]
  205. %25 = OpLoad %type_2d_image %texture
  206. %26 = OpLoad %type_sampler %sam
  207. %27 = OpSampledImage %type_sampled_image %25 %26
  208. %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17
  209. OpStore %out_var_SV_TARGET %28
  210. )");
  211. auto result = SinglePassRunAndMatch<ConvertToSampledImagePass>(
  212. shader, /* do_validate = */ true,
  213. VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 5}});
  214. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  215. }
  216. TEST_F(ConvertToSampledImageTest, Texture2DToSampledImage) {
  217. const std::string shader = BuildShader(
  218. R"(
  219. OpDecorate %sam DescriptorSet 0
  220. OpDecorate %sam Binding 2
  221. OpDecorate %texture DescriptorSet 0
  222. OpDecorate %texture Binding 5
  223. )",
  224. R"(
  225. ; CHECK: [[tex:%\w+]] = OpVariable %_ptr_UniformConstant_type_sampled_image UniformConstant
  226. %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
  227. %texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
  228. )",
  229. R"(
  230. ; CHECK: [[load:%\w+]] = OpLoad %type_sampled_image [[tex]]
  231. ; CHECK: [[image_extraction:%\w+]] = OpImage %type_2d_image [[load]]
  232. ; CHECK: OpSampledImage %type_sampled_image [[image_extraction]]
  233. %25 = OpLoad %type_2d_image %texture
  234. %26 = OpLoad %type_sampler %sam
  235. %27 = OpSampledImage %type_sampled_image %25 %26
  236. %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17
  237. OpStore %out_var_SV_TARGET %28
  238. )");
  239. auto result = SinglePassRunAndMatch<ConvertToSampledImagePass>(
  240. shader, /* do_validate = */ true,
  241. VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 5}});
  242. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  243. }
  244. TEST_F(ConvertToSampledImageTest, SamplerToSampledImage) {
  245. const std::string shader = BuildShader(
  246. R"(
  247. OpDecorate %sam DescriptorSet 0
  248. OpDecorate %sam Binding 2
  249. OpDecorate %texture DescriptorSet 0
  250. OpDecorate %texture Binding 5
  251. )",
  252. R"(
  253. %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
  254. %texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
  255. )",
  256. R"(
  257. %25 = OpLoad %type_2d_image %texture
  258. %26 = OpLoad %type_sampler %sam
  259. %27 = OpSampledImage %type_sampled_image %25 %26
  260. %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17
  261. OpStore %out_var_SV_TARGET %28
  262. )");
  263. auto result = SinglePassRunToBinary<ConvertToSampledImagePass>(
  264. shader, /* skip_nop = */ false,
  265. VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 2}});
  266. EXPECT_EQ(std::get<1>(result), Pass::Status::Failure);
  267. }
  268. TEST_F(ConvertToSampledImageTest, TwoImagesWithDuplicatedDescriptorSetBinding) {
  269. const std::string shader = BuildShader(
  270. R"(
  271. OpDecorate %sam DescriptorSet 0
  272. OpDecorate %sam Binding 2
  273. OpDecorate %texture0 DescriptorSet 0
  274. OpDecorate %texture0 Binding 5
  275. OpDecorate %texture1 DescriptorSet 0
  276. OpDecorate %texture1 Binding 5
  277. )",
  278. R"(
  279. %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
  280. %texture0 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
  281. %texture1 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
  282. )",
  283. R"(
  284. %25 = OpLoad %type_2d_image %texture0
  285. %26 = OpLoad %type_sampler %sam
  286. %27 = OpSampledImage %type_sampled_image %25 %26
  287. %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17
  288. OpStore %out_var_SV_TARGET %28
  289. )");
  290. auto result = SinglePassRunToBinary<ConvertToSampledImagePass>(
  291. shader, /* skip_nop = */ false,
  292. VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 5}});
  293. EXPECT_EQ(std::get<1>(result), Pass::Status::Failure);
  294. }
  295. TEST_F(ConvertToSampledImageTest,
  296. TwoSamplersWithDuplicatedDescriptorSetBinding) {
  297. const std::string shader = BuildShader(
  298. R"(
  299. OpDecorate %sam0 DescriptorSet 0
  300. OpDecorate %sam0 Binding 2
  301. OpDecorate %sam1 DescriptorSet 0
  302. OpDecorate %sam1 Binding 2
  303. OpDecorate %texture DescriptorSet 0
  304. OpDecorate %texture Binding 5
  305. )",
  306. R"(
  307. %sam0 = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
  308. %sam1 = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
  309. %texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
  310. )",
  311. R"(
  312. %25 = OpLoad %type_2d_image %texture
  313. %26 = OpLoad %type_sampler %sam0
  314. %27 = OpSampledImage %type_sampled_image %25 %26
  315. %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17
  316. OpStore %out_var_SV_TARGET %28
  317. )");
  318. auto result = SinglePassRunToBinary<ConvertToSampledImagePass>(
  319. shader, /* skip_nop = */ false,
  320. VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 2}});
  321. EXPECT_EQ(std::get<1>(result), Pass::Status::Failure);
  322. }
  323. } // namespace
  324. } // namespace opt
  325. } // namespace spvtools