• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Amber Authors.
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 
15 #include "src/shader_compiler.h"
16 
17 #include <algorithm>
18 #include <string>
19 #include <vector>
20 
21 #include "gtest/gtest.h"
22 #include "src/sampler.h"
23 #include "src/shader_data.h"
24 #if AMBER_ENABLE_SHADERC
25 #include "shaderc/shaderc.hpp"
26 #endif
27 
28 namespace amber {
29 namespace {
30 
31 const char kHexShader[] =
32     R"(0x03 0x02 0x23 0x07 0x00 0x00 0x01 0x00 0x07 0x00 0x08 0x00
33    0x15 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x11 0x00 0x02 0x00
34    0x01 0x00 0x00 0x00 0x0b 0x00 0x06 0x00 0x01 0x00 0x00 0x00
35    0x47 0x4c 0x53 0x4c 0x2e 0x73 0x74 0x64 0x2e 0x34 0x35 0x30
36    0x00 0x00 0x00 0x00 0x0e 0x00 0x03 0x00 0x00 0x00 0x00 0x00
37    0x01 0x00 0x00 0x00 0x0f 0x00 0x07 0x00 0x00 0x00 0x00 0x00
38    0x04 0x00 0x00 0x00 0x6d 0x61 0x69 0x6e 0x00 0x00 0x00 0x00
39    0x0d 0x00 0x00 0x00 0x11 0x00 0x00 0x00 0x03 0x00 0x03 0x00
40    0x02 0x00 0x00 0x00 0xae 0x01 0x00 0x00 0x05 0x00 0x04 0x00
41    0x04 0x00 0x00 0x00 0x6d 0x61 0x69 0x6e 0x00 0x00 0x00 0x00
42    0x05 0x00 0x06 0x00 0x0b 0x00 0x00 0x00 0x67 0x6c 0x5f 0x50
43    0x65 0x72 0x56 0x65 0x72 0x74 0x65 0x78 0x00 0x00 0x00 0x00
44    0x06 0x00 0x06 0x00 0x0b 0x00 0x00 0x00 0x00 0x00 0x00 0x00
45    0x67 0x6c 0x5f 0x50 0x6f 0x73 0x69 0x74 0x69 0x6f 0x6e 0x00
46    0x06 0x00 0x07 0x00 0x0b 0x00 0x00 0x00 0x01 0x00 0x00 0x00
47    0x67 0x6c 0x5f 0x50 0x6f 0x69 0x6e 0x74 0x53 0x69 0x7a 0x65
48    0x00 0x00 0x00 0x00 0x06 0x00 0x07 0x00 0x0b 0x00 0x00 0x00
49    0x02 0x00 0x00 0x00 0x67 0x6c 0x5f 0x43 0x6c 0x69 0x70 0x44
50    0x69 0x73 0x74 0x61 0x6e 0x63 0x65 0x00 0x05 0x00 0x03 0x00
51    0x0d 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x05 0x00 0x05 0x00
52    0x11 0x00 0x00 0x00 0x70 0x6f 0x73 0x69 0x74 0x69 0x6f 0x6e
53    0x00 0x00 0x00 0x00 0x48 0x00 0x05 0x00 0x0b 0x00 0x00 0x00
54    0x00 0x00 0x00 0x00 0x0b 0x00 0x00 0x00 0x00 0x00 0x00 0x00
55    0x48 0x00 0x05 0x00 0x0b 0x00 0x00 0x00 0x01 0x00 0x00 0x00
56    0x0b 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x48 0x00 0x05 0x00
57    0x0b 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x0b 0x00 0x00 0x00
58    0x03 0x00 0x00 0x00 0x47 0x00 0x03 0x00 0x0b 0x00 0x00 0x00
59    0x02 0x00 0x00 0x00 0x47 0x00 0x04 0x00 0x11 0x00 0x00 0x00
60    0x1e 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x13 0x00 0x02 0x00
61    0x02 0x00 0x00 0x00 0x21 0x00 0x03 0x00 0x03 0x00 0x00 0x00
62    0x02 0x00 0x00 0x00 0x16 0x00 0x03 0x00 0x06 0x00 0x00 0x00
63    0x20 0x00 0x00 0x00 0x17 0x00 0x04 0x00 0x07 0x00 0x00 0x00
64    0x06 0x00 0x00 0x00 0x04 0x00 0x00 0x00 0x15 0x00 0x04 0x00
65    0x08 0x00 0x00 0x00 0x20 0x00 0x00 0x00 0x00 0x00 0x00 0x00
66    0x2b 0x00 0x04 0x00 0x08 0x00 0x00 0x00 0x09 0x00 0x00 0x00
67    0x01 0x00 0x00 0x00 0x1c 0x00 0x04 0x00 0x0a 0x00 0x00 0x00
68    0x06 0x00 0x00 0x00 0x09 0x00 0x00 0x00 0x1e 0x00 0x05 0x00
69    0x0b 0x00 0x00 0x00 0x07 0x00 0x00 0x00 0x06 0x00 0x00 0x00
70    0x0a 0x00 0x00 0x00 0x20 0x00 0x04 0x00 0x0c 0x00 0x00 0x00
71    0x03 0x00 0x00 0x00 0x0b 0x00 0x00 0x00 0x3b 0x00 0x04 0x00
72    0x0c 0x00 0x00 0x00 0x0d 0x00 0x00 0x00 0x03 0x00 0x00 0x00
73    0x15 0x00 0x04 0x00 0x0e 0x00 0x00 0x00 0x20 0x00 0x00 0x00
74    0x01 0x00 0x00 0x00 0x2b 0x00 0x04 0x00 0x0e 0x00 0x00 0x00
75    0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x20 0x00 0x04 0x00
76    0x10 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x07 0x00 0x00 0x00
77    0x3b 0x00 0x04 0x00 0x10 0x00 0x00 0x00 0x11 0x00 0x00 0x00
78    0x01 0x00 0x00 0x00 0x20 0x00 0x04 0x00 0x13 0x00 0x00 0x00
79    0x03 0x00 0x00 0x00 0x07 0x00 0x00 0x00 0x36 0x00 0x05 0x00
80    0x02 0x00 0x00 0x00 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
81    0x03 0x00 0x00 0x00 0xf8 0x00 0x02 0x00 0x05 0x00 0x00 0x00
82    0x3d 0x00 0x04 0x00 0x07 0x00 0x00 0x00 0x12 0x00 0x00 0x00
83    0x11 0x00 0x00 0x00 0x41 0x00 0x05 0x00 0x13 0x00 0x00 0x00
84    0x14 0x00 0x00 0x00 0x0d 0x00 0x00 0x00 0x0f 0x00 0x00 0x00
85    0x3e 0x00 0x03 0x00 0x14 0x00 0x00 0x00 0x12 0x00 0x00 0x00
86    0xfd 0x00 0x01 0x00 0x38 0x00 0x01 0x00)";
87 
88 }  // namespace
89 
90 using ShaderCompilerTest = testing::Test;
91 
92 #if AMBER_ENABLE_SHADERC
TEST_F(ShaderCompilerTest,CompilesGlsl)93 TEST_F(ShaderCompilerTest, CompilesGlsl) {
94   std::string contents = R"(
95 #version 420
96 layout(location = 0) in vec4 position;
97 
98 void main() {
99   gl_Position = position;
100 })";
101 
102   Shader shader(kShaderTypeVertex);
103   shader.SetName("TestShader");
104   shader.SetFormat(kShaderFormatGlsl);
105   shader.SetData(contents);
106 
107   ShaderCompiler sc;
108   Result r;
109   std::vector<uint32_t> binary;
110   Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
111   Pipeline pipeline(PipelineType::kCompute);
112   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
113   ASSERT_TRUE(r.IsSuccess()) << r.Error();
114   EXPECT_FALSE(binary.empty());
115   EXPECT_EQ(0x07230203u, binary[0]);  // Verify SPIR-V header present.
116 }
117 #endif  // AMBER_ENABLE_SHADERC
118 
119 #if AMBER_ENABLE_SPIRV_TOOLS
TEST_F(ShaderCompilerTest,CompilesSpirvAsm)120 TEST_F(ShaderCompilerTest, CompilesSpirvAsm) {
121   Shader shader(kShaderTypeVertex);
122   shader.SetName("TestShader");
123   shader.SetFormat(kShaderFormatSpirvAsm);
124   shader.SetData(kPassThroughShader);
125 
126   ShaderCompiler sc;
127   Result r;
128   std::vector<uint32_t> binary;
129   Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
130   Pipeline pipeline(PipelineType::kCompute);
131   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
132   ASSERT_TRUE(r.IsSuccess());
133   EXPECT_FALSE(binary.empty());
134   EXPECT_EQ(0x07230203u, binary[0]);  // Verify SPIR-V header present.
135 }
136 
TEST_F(ShaderCompilerTest,InvalidSpirvHex)137 TEST_F(ShaderCompilerTest, InvalidSpirvHex) {
138   std::string contents = kHexShader;
139   contents[3] = '0';
140 
141   Shader shader(kShaderTypeVertex);
142   shader.SetName("BadTestShader");
143   shader.SetFormat(kShaderFormatSpirvHex);
144   shader.SetData(contents);
145 
146   ShaderCompiler sc;
147   Result r;
148   std::vector<uint32_t> binary;
149   Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
150   Pipeline pipeline(PipelineType::kCompute);
151   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
152   ASSERT_FALSE(r.IsSuccess());
153   EXPECT_EQ("Invalid shader: error: line 0: Invalid SPIR-V magic number.\n",
154             r.Error());
155 }
156 
TEST_F(ShaderCompilerTest,InvalidHex)157 TEST_F(ShaderCompilerTest, InvalidHex) {
158   Shader shader(kShaderTypeVertex);
159   shader.SetName("BadTestShader");
160   shader.SetFormat(kShaderFormatSpirvHex);
161   shader.SetData("aaaaaaaaaa");
162 
163   ShaderCompiler sc;
164   Result r;
165   std::vector<uint32_t> binary;
166   Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
167   Pipeline pipeline(PipelineType::kCompute);
168   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
169   ASSERT_FALSE(r.IsSuccess());
170   EXPECT_EQ("Invalid shader: error: line 0: Invalid SPIR-V magic number.\n",
171             r.Error());
172 }
173 
TEST_F(ShaderCompilerTest,OptimizeShader)174 TEST_F(ShaderCompilerTest, OptimizeShader) {
175   const std::string spirv = R"(
176 OpCapability Shader
177 OpExtension "SPV_KHR_storage_buffer_storage_class"
178 OpMemoryModel Logical GLSL450
179 OpEntryPoint GLCompute %main "main"
180 OpExecutionMode %main LocalSize 1 1 1
181 OpDecorate %block Block
182 OpMemberDecorate %block 0 Offset 0
183 OpDecorate %in DescriptorSet 0
184 OpDecorate %in Binding 0
185 OpDecorate %out DescriptorSet 0
186 OpDecorate %out Binding 1
187 %void = OpTypeVoid
188 %int = OpTypeInt 32 0
189 %int_0 = OpConstant %int 0
190 %block = OpTypeStruct %int
191 %ptr_ssbo_block = OpTypePointer StorageBuffer %block
192 %ptr_ssbo_int = OpTypePointer StorageBuffer %int
193 %in = OpVariable %ptr_ssbo_block StorageBuffer
194 %out = OpVariable %ptr_ssbo_block StorageBuffer
195 %void_fn = OpTypeFunction %void
196 %main = OpFunction %void None %void_fn
197 %entry = OpLabel
198 %in_gep = OpAccessChain %ptr_ssbo_int %in %int_0
199 %ld = OpLoad %int %in_gep
200 %dead = OpIAdd %int %ld %int_0
201 %out_gep = OpAccessChain %ptr_ssbo_int %out %int_0
202 OpStore %out_gep %ld
203 OpReturn
204 OpFunctionEnd
205 )";
206 
207   Shader shader(kShaderTypeCompute);
208   shader.SetName("TestShader");
209   shader.SetFormat(kShaderFormatSpirvAsm);
210   shader.SetData(spirv);
211 
212   Pipeline::ShaderInfo unoptimized(&shader, kShaderTypeCompute);
213   Pipeline::ShaderInfo optimized(&shader, kShaderTypeCompute);
214   optimized.SetShaderOptimizations({"--eliminate-dead-code-aggressive"});
215 
216   ShaderCompiler sc;
217   Result r;
218   std::vector<uint32_t> unopt_binary;
219   Pipeline pipeline(PipelineType::kCompute);
220   std::tie(r, unopt_binary) = sc.Compile(&pipeline, &unoptimized, ShaderMap());
221   ASSERT_TRUE(r.IsSuccess());
222 
223   std::vector<uint32_t> opt_binary;
224   std::tie(r, opt_binary) = sc.Compile(&pipeline, &optimized, ShaderMap());
225   ASSERT_TRUE(r.IsSuccess());
226   EXPECT_NE(opt_binary.size(), unopt_binary.size());
227 }
228 #endif  // AMBER_ENABLE_SPIRV_TOOLS
229 
TEST_F(ShaderCompilerTest,CompilesSpirvHex)230 TEST_F(ShaderCompilerTest, CompilesSpirvHex) {
231   Shader shader(kShaderTypeVertex);
232   shader.SetName("TestShader");
233   shader.SetFormat(kShaderFormatSpirvHex);
234   shader.SetData(kHexShader);
235 
236   ShaderCompiler sc;
237   Result r;
238   std::vector<uint32_t> binary;
239   Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
240   Pipeline pipeline(PipelineType::kCompute);
241   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
242   ASSERT_TRUE(r.IsSuccess());
243   EXPECT_FALSE(binary.empty());
244   EXPECT_EQ(0x07230203u, binary[0]);  // Verify SPIR-V header present.
245 }
246 
TEST_F(ShaderCompilerTest,FailsOnInvalidShader)247 TEST_F(ShaderCompilerTest, FailsOnInvalidShader) {
248   std::string contents = "Just Random\nText()\nThat doesn't work.";
249 
250   Shader shader(kShaderTypeVertex);
251   shader.SetName("BadTestShader");
252   shader.SetFormat(kShaderFormatGlsl);
253   shader.SetData(contents);
254 
255   ShaderCompiler sc;
256   Result r;
257   std::vector<uint32_t> binary;
258   Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
259   Pipeline pipeline(PipelineType::kCompute);
260   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
261   ASSERT_FALSE(r.IsSuccess());
262 }
263 
TEST_F(ShaderCompilerTest,ReturnsCachedShader)264 TEST_F(ShaderCompilerTest, ReturnsCachedShader) {
265   // This shader would normally fail, but because we pull it from the cache,
266   // we don't compile this so the test will pass.
267   std::string contents = "Just Random\nText()\nThat doesn't work.";
268 
269   static const char kShaderName[] = "CachedShader";
270   static const char kShaderNameWithPipeline[] = "pipeline-CachedShader";
271   Shader shader(kShaderTypeVertex);
272   shader.SetName(kShaderName);
273   shader.SetFormat(kShaderFormatGlsl);
274   shader.SetData(contents);
275 
276   std::vector<uint32_t> src_bytes = {1, 2, 3, 4, 5};
277 
278   ShaderMap map;
279   map[kShaderNameWithPipeline] = src_bytes;
280 
281   ShaderCompiler sc;
282   Result r;
283   std::vector<uint32_t> binary;
284   Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
285   Pipeline pipeline(PipelineType::kCompute);
286   pipeline.SetName("pipeline");
287   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, map);
288   ASSERT_TRUE(r.IsSuccess()) << r.Error();
289 
290   ASSERT_EQ(binary.size(), src_bytes.size());
291   for (size_t i = 0; i < src_bytes.size(); ++i) {
292     EXPECT_EQ(src_bytes[i], binary[i]);
293   }
294 }
295 
296 #if AMBER_ENABLE_CLSPV
TEST_F(ShaderCompilerTest,ClspvCompile)297 TEST_F(ShaderCompilerTest, ClspvCompile) {
298   Shader shader(kShaderTypeCompute);
299   shader.SetName("TestShader");
300   shader.SetFormat(kShaderFormatOpenCLC);
301   shader.SetData(R"(
302 kernel void TestShader(global int* in, global int* out) {
303   *out = *in;
304 }
305   )");
306 
307   ShaderCompiler sc;
308   Result r;
309   std::vector<uint32_t> binary;
310   Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
311   Pipeline pipeline(PipelineType::kCompute);
312   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
313   ASSERT_TRUE(r.IsSuccess());
314   EXPECT_FALSE(binary.empty());
315   EXPECT_EQ(0x07230203u, binary[0]);  // Verify SPIR-V header present.
316 }
317 
TEST_F(ShaderCompilerTest,ClspvDisallowCaching)318 TEST_F(ShaderCompilerTest, ClspvDisallowCaching) {
319   Shader shader(kShaderTypeCompute);
320   std::string name = "TestShader";
321   shader.SetName(name);
322   shader.SetFormat(kShaderFormatOpenCLC);
323   shader.SetData(R"(
324 kernel void TestShader(global int* in, global int* out) {
325   *out = *in;
326 }
327   )");
328 
329   std::vector<uint32_t> src_bytes = {1, 2, 3, 4, 5};
330 
331   ShaderMap map;
332   map[name] = src_bytes;
333 
334   ShaderCompiler sc;
335   Result r;
336   std::vector<uint32_t> binary;
337   Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
338   Pipeline pipeline(PipelineType::kCompute);
339   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, map);
340   ASSERT_FALSE(r.IsSuccess());
341   EXPECT_TRUE(binary.empty());
342 }
343 
TEST_F(ShaderCompilerTest,ClspvCompileOptions)344 TEST_F(ShaderCompilerTest, ClspvCompileOptions) {
345   std::string data = R"(
346 kernel void TestShader(global int* in, global int* out, int m, int b) {
347   *out = *in * m + b;
348 }
349 )";
350   Shader shader(kShaderTypeCompute);
351   shader.SetName("TestShader");
352   shader.SetFormat(kShaderFormatOpenCLC);
353   shader.SetData(data);
354 
355   ShaderCompiler sc;
356   Result r;
357   std::vector<uint32_t> binary;
358   Pipeline::ShaderInfo shader_info1(&shader, kShaderTypeCompute);
359   shader_info1.SetCompileOptions({"-cluster-pod-kernel-args=0"});
360   Pipeline pipeline(PipelineType::kCompute);
361   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info1, ShaderMap());
362   ASSERT_TRUE(r.IsSuccess());
363   EXPECT_FALSE(binary.empty());
364   EXPECT_EQ(0x07230203u, binary[0]);  // Verify SPIR-V header present.
365   auto iter = shader_info1.GetDescriptorMap().find("TestShader");
366   ASSERT_NE(iter, shader_info1.GetDescriptorMap().end());
367   uint32_t max_binding = 0;
368   bool has_pod_ubo = 0;
369   for (const auto& entry : iter->second) {
370     max_binding = std::max(max_binding, entry.binding);
371     has_pod_ubo =
372         entry.kind == Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD_UBO;
373   }
374   EXPECT_EQ(3U, max_binding);
375   EXPECT_TRUE(has_pod_ubo);
376 
377   binary.clear();
378   Pipeline::ShaderInfo shader_info2(&shader, kShaderTypeCompute);
379   shader_info2.SetCompileOptions({"-cluster-pod-kernel-args", "-pod-ubo"});
380   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info2, ShaderMap());
381   ASSERT_TRUE(r.IsSuccess());
382   EXPECT_FALSE(binary.empty());
383   EXPECT_EQ(0x07230203u, binary[0]);  // Verify SPIR-V header present.
384   iter = shader_info2.GetDescriptorMap().find("TestShader");
385   ASSERT_NE(iter, shader_info2.GetDescriptorMap().end());
386   max_binding = 0;
387   has_pod_ubo = 0;
388   for (const auto& entry : iter->second) {
389     max_binding = std::max(max_binding, entry.binding);
390     has_pod_ubo =
391         entry.kind == Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD_UBO;
392   }
393   EXPECT_EQ(2U, max_binding);
394   EXPECT_TRUE(has_pod_ubo);
395 }
396 
TEST_F(ShaderCompilerTest,ClspvImagesAndSamplers)397 TEST_F(ShaderCompilerTest, ClspvImagesAndSamplers) {
398   std::string data = R"(
399 kernel void TestShader(read_only image2d_t ro_image, write_only image2d_t wo_image, sampler_t sampler) {
400   int2 coord = (int2)(0, 0);
401   float4 texel = read_imagef(ro_image, sampler, coord);
402   write_imagef(wo_image, coord, texel);
403 }
404 )";
405 
406   Shader shader(kShaderTypeCompute);
407   shader.SetName("TestShader");
408   shader.SetFormat(kShaderFormatOpenCLC);
409   shader.SetData(data);
410 
411   ShaderCompiler sc;
412   Result r;
413   std::vector<uint32_t> binary;
414   Pipeline::ShaderInfo shader_info1(&shader, kShaderTypeCompute);
415   Pipeline pipeline(PipelineType::kCompute);
416   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info1, ShaderMap());
417   ASSERT_TRUE(r.IsSuccess());
418   EXPECT_FALSE(binary.empty());
419   EXPECT_EQ(0x07230203u, binary[0]);  // Verify SPIR-V header present.
420   auto iter = shader_info1.GetDescriptorMap().find("TestShader");
421   for (const auto& entry : iter->second) {
422     if (entry.binding == 0) {
423       EXPECT_EQ(entry.kind,
424                 Pipeline::ShaderInfo::DescriptorMapEntry::Kind::RO_IMAGE);
425     } else if (entry.binding == 1) {
426       EXPECT_EQ(entry.kind,
427                 Pipeline::ShaderInfo::DescriptorMapEntry::Kind::WO_IMAGE);
428     } else if (entry.binding == 2) {
429       EXPECT_EQ(entry.kind,
430                 Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SAMPLER);
431     } else {
432       ASSERT_TRUE(false);
433     }
434   }
435 }
436 
TEST_F(ShaderCompilerTest,ClspvLiteralSamplers)437 TEST_F(ShaderCompilerTest, ClspvLiteralSamplers) {
438   std::string data = R"(
439 const sampler_t s1 = CLK_ADDRESS_NONE | CLK_FILTER_NEAREST | CLK_NORMALIZED_COORDS_FALSE;
440 const sampler_t s2 = CLK_ADDRESS_MIRRORED_REPEAT | CLK_FILTER_LINEAR | CLK_NORMALIZED_COORDS_TRUE;
441 
442 kernel void foo(read_only image2d_t im, global float4* out) {
443   out[0] = read_imagef(im, s1, (int2)(0));
444   out[1] = read_imagef(im, s2, (int2)(0));
445 }
446 )";
447 
448   Pipeline pipeline(PipelineType::kCompute);
449   pipeline.SetName("pipe");
450   Shader shader(kShaderTypeCompute);
451   shader.SetName("foo");
452   shader.SetFormat(kShaderFormatOpenCLC);
453   shader.SetData(data);
454 
455   ShaderCompiler sc;
456   Result r;
457   std::vector<uint32_t> binary;
458   Pipeline::ShaderInfo shader_info1(&shader, kShaderTypeCompute);
459   std::tie(r, binary) = sc.Compile(&pipeline, &shader_info1, ShaderMap());
460   ASSERT_TRUE(r.IsSuccess());
461   EXPECT_FALSE(binary.empty());
462   EXPECT_EQ(0x07230203u, binary[0]);  // Verify SPIR-V header present.
463   bool found_s1 = false;
464   bool found_s2 = false;
465   EXPECT_EQ(0, pipeline.GetSamplers()[0].descriptor_set);
466   EXPECT_EQ(0, pipeline.GetSamplers()[1].descriptor_set);
467   EXPECT_NE(pipeline.GetSamplers()[0].binding,
468             pipeline.GetSamplers()[1].binding);
469   if (pipeline.GetSamplers()[0].mask == 0x10 ||
470       pipeline.GetSamplers()[1].mask == 0x10) {
471     found_s1 = true;
472   }
473   if (pipeline.GetSamplers()[0].mask == (0x1 | 0x8 | 0x20) ||
474       pipeline.GetSamplers()[1].mask == (0x1 | 0x8 | 0x20)) {
475     found_s2 = true;
476   }
477   EXPECT_EQ(true, found_s1);
478   EXPECT_EQ(true, found_s2);
479 }
480 #endif  // AMBER_ENABLE_CLSPV
481 
482 struct ParseSpvEnvCase {
483   std::string env_str;
484   bool ok;
485   uint32_t target_env;
486   uint32_t env_version;
487   uint32_t spirv_version;
488 };
489 
490 using ParseSpvEnvTest = ::testing::TestWithParam<ParseSpvEnvCase>;
491 
TEST_P(ParseSpvEnvTest,Samples)492 TEST_P(ParseSpvEnvTest, Samples) {
493   uint32_t target_env = 42u;
494   uint32_t env_version = 43u;
495   uint32_t spirv_version = 44u;
496   auto r = amber::ParseSpvEnv(GetParam().env_str, &target_env, &env_version,
497                               &spirv_version);
498   if (GetParam().ok) {
499     EXPECT_TRUE(r.IsSuccess());
500     EXPECT_EQ(GetParam().target_env, target_env) << GetParam().env_str;
501     EXPECT_EQ(GetParam().env_version, env_version) << GetParam().env_str;
502     EXPECT_EQ(GetParam().spirv_version, spirv_version) << GetParam().env_str;
503   } else {
504     EXPECT_FALSE(r.IsSuccess());
505   }
506 }
507 
508 // See also shaderc/env.h
509 const uint32_t vulkan = 0;
510 const uint32_t vulkan_1_0 = ((uint32_t(1) << 22));
511 const uint32_t vulkan_1_1 = ((uint32_t(1) << 22) | (1 << 12));
512 const uint32_t vulkan_1_2 = ((uint32_t(1) << 22) | (2 << 12));
513 const uint32_t spv_1_0 = uint32_t(0x10000);
514 const uint32_t spv_1_1 = uint32_t(0x10100);
515 const uint32_t spv_1_2 = uint32_t(0x10200);
516 const uint32_t spv_1_3 = uint32_t(0x10300);
517 const uint32_t spv_1_4 = uint32_t(0x10400);
518 const uint32_t spv_1_5 = uint32_t(0x10500);
519 
520 INSTANTIATE_TEST_SUITE_P(ParseSpvEnvFailures,
521                          ParseSpvEnvTest,
522                          ::testing::ValuesIn(std::vector<ParseSpvEnvCase>{
523                              {"foobar", false, 0u, 0u, 0u},
524                              {"spv99", false, 0u, 0u, 0u},
525                              {"spv99.9", false, 0u, 0u, 0u},
526                              {"spv1.0.1", false, 0u, 0u, 0u},
527                              {"spv1.0.1", false, 0u, 0u, 0u},
528                              {"spv1.9", false, 0u, 0u, 0u},
529                              {"vulkan99", false, 0u, 0u, 0u},
530                              {"vulkan99.9", false, 0u, 0u, 0u},
531                          }));
532 
533 INSTANTIATE_TEST_SUITE_P(ParseSpvEnvSuccesses,
534                          ParseSpvEnvTest,
535                          ::testing::ValuesIn(std::vector<ParseSpvEnvCase>{
536                              {"", true, vulkan, vulkan_1_0, spv_1_0},
537                              {"spv1.0", true, vulkan, vulkan_1_0, spv_1_0},
538                              {"spv1.1", true, vulkan, vulkan_1_1, spv_1_1},
539                              {"spv1.2", true, vulkan, vulkan_1_1, spv_1_2},
540                              {"spv1.3", true, vulkan, vulkan_1_1, spv_1_3},
541                              {"spv1.4", true, vulkan, vulkan_1_2, spv_1_4},
542                              {"spv1.5", true, vulkan, vulkan_1_2, spv_1_5},
543                              {"vulkan1.0", true, vulkan, vulkan_1_0, spv_1_0},
544                              {"vulkan1.1", true, vulkan, vulkan_1_1, spv_1_3},
545                              {"vulkan1.1spv1.4", true, vulkan, vulkan_1_1,
546                               spv_1_4},
547                              {"vulkan1.2", true, vulkan, vulkan_1_2, spv_1_5},
548                          }));
549 
550 }  // namespace amber
551