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