1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 Google LLC
6 * Copyright (c) 2019 The Khronos Group Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Test new features in SPIR-V 1.4.
23 *//*--------------------------------------------------------------------*/
24
25#include <string>
26#include <vector>
27#include <amber/amber.h>
28
29#include "tcuDefs.hpp"
30
31#include "vkDefs.hpp"
32#include "vktTestGroupUtil.hpp"
33#include "vktAmberTestCase.hpp"
34#include "vktSpvAsmSpirvVersion1p4Tests.hpp"
35#include "vktTestGroupUtil.hpp"
36
37namespace vkt
38{
39namespace SpirVAssembly
40{
41namespace
42{
43
44struct Case
45{
46	Case(const char* b) : basename(b), requirements() { }
47	Case(const char* b, const std::vector<std::string>& e) : basename(b), requirements(e) { }
48	const char *basename;
49	// Additional Vulkan requirements, if any.
50	std::vector<std::string> requirements;
51};
52struct CaseGroup
53{
54	CaseGroup(const char* the_data_dir, const char* the_subdir) : data_dir(the_data_dir), subdir(the_subdir) { }
55	void add(const char* basename)
56	{
57		cases.push_back(Case(basename));
58	}
59	void add(const char* basename, const std::vector<std::string>& requirements)
60	{
61		cases.push_back(Case(basename, requirements));
62	}
63
64	const char* data_dir;
65	const char* subdir;
66	std::vector<Case> cases;
67};
68
69
70void addTestsForAmberFiles (tcu::TestCaseGroup* tests, CaseGroup group)
71{
72#ifndef CTS_USES_VULKANSC
73	tcu::TestContext& testCtx = tests->getTestContext();
74	const std::string data_dir(group.data_dir);
75	const std::string subdir(group.subdir);
76	const std::string category = data_dir + "/" + subdir;
77	std::vector<Case> cases(group.cases);
78	vk::SpirVAsmBuildOptions asm_options(VK_MAKE_API_VERSION(0, 1, 1, 0), vk::SPIRV_VERSION_1_4);
79	asm_options.supports_VK_KHR_spirv_1_4 = true;
80
81	for (unsigned i = 0; i < cases.size() ; ++i)
82	{
83
84		const std::string file = std::string(cases[i].basename) + ".amber";
85		cts_amber::AmberTestCase *testCase = cts_amber::createAmberTestCase(testCtx,
86																			cases[i].basename,
87																			category.c_str(),
88																			file);
89		DE_ASSERT(testCase != DE_NULL);
90		// Add Vulkan extension requirements.
91		// VK_KHR_spirv_1_4 requires Vulkan 1.1, which includes many common extensions.
92		// So for, example, these tests never have to request VK_KHR_storage_buffer_storage_class,
93		// or VK_KHR_variable_pointers since those extensions were promoted to core features
94		// in Vulkan 1.1.  Note that feature bits may still be optional.
95		testCase->addRequirement("VK_KHR_spirv_1_4");
96		// The tests often use StorageBuffer storage class.
97		// We do not have to request VK_KHR_storage_buffer_storage_class because that extension
98		// is about enabling use of SPV_KHR_storage_buffer_storage_class.  But SPIR-V 1.4 allows
99		// use of StorageBuffer storage class without any further declarations of extensions
100		// or capabilities.  This will also hold for tests that use features introduced by
101		// extensions folded into SPIR-V 1.4 or earlier, and which don't require extra capabilities
102		// to be enabled by Vulkan.  Other examples are functionality in SPV_GOOGLE_decorate_string,
103		// SPV_GOOGLE_hlsl_functionality1, and SPV_KHR_no_integer_wrap_decoration.
104		const std::vector<std::string>& reqmts = cases[i].requirements;
105		for (size_t r = 0; r < reqmts.size() ; ++r)
106		{
107			testCase->addRequirement(reqmts[r]);
108		}
109
110		testCase->setSpirVAsmBuildOptions(asm_options);
111		tests->addChild(testCase);
112	}
113#else
114	DE_UNREF(tests);
115	DE_UNREF(group);
116#endif
117}
118
119} // anonymous
120
121tcu::TestCaseGroup* createSpirvVersion1p4Group (tcu::TestContext& testCtx)
122{
123	// SPIR-V 1.4 new features
124	de::MovePtr<tcu::TestCaseGroup> spirv1p4Tests(new tcu::TestCaseGroup(testCtx, "spirv1p4"));
125
126	// Location of the Amber script files under the data/vulkan/amber source tree.
127	const char* data_dir = "spirv_assembly/instruction/spirv1p4";
128
129	// Set up features used for various tests.
130	std::vector<std::string> Geom;
131	Geom.push_back("Features.geometryShader");
132
133	std::vector<std::string> Tess;
134	Tess.push_back("Features.tessellationShader");
135
136	std::vector<std::string> Varptr_ssbo;
137	Varptr_ssbo.push_back("VariablePointerFeatures.variablePointersStorageBuffer");
138
139	std::vector<std::string> Varptr_full = Varptr_ssbo;
140	Varptr_full.push_back("VariablePointerFeatures.variablePointers");
141
142	std::vector<std::string> Int16;
143	Int16.push_back("Features.shaderInt16");
144
145	std::vector<std::string> Int16_storage = Int16;
146	Int16_storage.push_back("VK_KHR_16bit_storage");
147	Int16_storage.push_back("Storage16BitFeatures.storageBuffer16BitAccess");
148
149	std::vector<std::string> Int64;
150	Int64.push_back("Features.shaderInt64");
151
152	// Define test groups
153
154	CaseGroup group(data_dir, "opcopylogical");
155	// different matrix layout
156	group.add("different_matrix_layout");
157	// different matrix strides
158	group.add("different_matrix_strides");
159	// nested_arrays_different_inner_stride
160	group.add("nested_arrays_different_inner_stride");
161	// nested_arrays_different_inner_stride
162	group.add("nested_arrays_different_outer_stride");
163	// nested_arrays_different_strides
164	group.add("nested_arrays_different_strides");
165	// same array two ids
166	group.add("same_array_two_ids");
167	// same struct two ids
168	group.add("same_struct_two_ids");
169	// ssbo_to_ubo
170	group.add("ssbo_to_ubo");
171	// two_arrays_different_stride_1
172	group.add("two_arrays_different_stride_1");
173	// two_arrays_different_stride_2
174	group.add("two_arrays_different_stride_2");
175	// ubo_to_ssbo
176	group.add("ubo_to_ssbo");
177	spirv1p4Tests->addChild(createTestGroup(testCtx, "opcopylogical", addTestsForAmberFiles, group));
178
179	group = CaseGroup(data_dir, "opptrdiff");
180	// pointer diff within an SSBO
181	group.add("ssbo_comparisons_diff", Varptr_ssbo);
182	// pointer diff in SSBO with full VariablePointers
183	group.add("variable_pointers_vars_ssbo_2_diff", Varptr_ssbo);
184	// pointer diff in SSBO, stored in private var
185	group.add("variable_pointers_vars_ssbo_diff", Varptr_ssbo);
186	// pointer diff in workgroup storage, stored in private var
187	group.add("variable_pointers_vars_wg_diff", Varptr_full);
188	// pointer diff in workgroup storage
189	group.add("wg_comparisons_diff", Varptr_full);
190	spirv1p4Tests->addChild(createTestGroup(testCtx, "opptrdiff", addTestsForAmberFiles, group));
191
192	group = CaseGroup(data_dir, "opptrequal");
193	// ptr equal against different SSBO variables
194	group.add("different_ssbos_equal", Varptr_full);
195	// ptr equal against different WG variables
196	group.add("different_wgs_equal", Varptr_full);
197	// ptr equal null in SSBO
198	group.add("null_comparisons_ssbo_equal", Varptr_ssbo);
199	// ptr equal null in Workgrop
200	group.add("null_comparisons_wg_equal", Varptr_full);
201	// ptr equal in SSBO
202	group.add("ssbo_comparisons_equal", Varptr_ssbo);
203	// ptr equal in SSBO, store pointers in Function var
204	group.add("variable_pointers_ssbo_2_equal", Varptr_full);
205	// ptr equal in SSBO
206	group.add("variable_pointers_ssbo_equal", Varptr_ssbo);
207	// ptr equal in SSBO, store pointers in Private var
208	group.add("variable_pointers_vars_ssbo_equal", Varptr_ssbo);
209	// ptr equal between simple data primitives in SSBOs
210	group.add("simple_variable_pointers_ptr_equal", Varptr_ssbo);
211	// ptr equal in Workgrop, store pointers in Private var
212	group.add("variable_pointers_vars_wg_equal", Varptr_full);
213	// ptr equal in Workgrop
214	group.add("variable_pointers_wg_equal", Varptr_full);
215	// ptr equal in Workgrop
216	group.add("wg_comparisons_equal", Varptr_full);
217	spirv1p4Tests->addChild(createTestGroup(testCtx, "opptrequal", addTestsForAmberFiles, group));
218
219	group = CaseGroup(data_dir, "opptrnotequal");
220	// ptr not equal against different SSBO variables
221	group.add("different_ssbos_not_equal", Varptr_full);
222	// ptr not equal against different WG variables
223	group.add("different_wgs_not_equal", Varptr_full);
224	// ptr not equal null SSBO
225	group.add("null_comparisons_ssbo_not_equal", Varptr_ssbo);
226	// ptr not equal null SSBO
227	group.add("null_comparisons_wg_not_equal", Varptr_full);
228	// ptr not equal SSBO
229	group.add("ssbo_comparisons_not_equal", Varptr_ssbo);
230	// ptr not equal SSBO, store pointer in Function var
231	group.add("variable_pointers_ssbo_2_not_equal", Varptr_full);
232	// ptr not equal SSBO, pointer from function return
233	group.add("variable_pointers_ssbo_not_equal", Varptr_ssbo);
234	// ptr not equal between simple data primitives in SSBOs
235	group.add("simple_variable_pointers_ptr_not_equal", Varptr_ssbo);
236	// ptr not equal SSBO, store pointer in Private var
237	group.add("variable_pointers_vars_ssbo_not_equal", Varptr_ssbo);
238	// ptr not equal Workgroup, store pointer in Private var
239	group.add("variable_pointers_vars_wg_not_equal", Varptr_full);
240	// ptr not equal Workgroup
241	group.add("variable_pointers_wg_not_equal", Varptr_full);
242	// ptr not equal Workgroup
243	group.add("wg_comparisons_not_equal", Varptr_full);
244	spirv1p4Tests->addChild(createTestGroup(testCtx, "opptrnotequal", addTestsForAmberFiles, group));
245
246	group = CaseGroup(data_dir, "opcopymemory");
247	// different alignments
248	group.add("different_alignments");
249	// no source access operands
250	group.add("no_source_access_operands");
251	// no target access operands
252	group.add("no_target_access_operands");
253	spirv1p4Tests->addChild(createTestGroup(testCtx, "opcopymemory", addTestsForAmberFiles, group));
254
255	group = CaseGroup(data_dir, "uniformid");
256	// workgroup uniform load result at consumption, in nonuniform control flow
257	group.add("partially_active_uniform_id");
258	// subgroup uniform compare result inside control flow
259	group.add("subgroup_cfg_uniform_id"); // Assumes subgroup size <= LocalSize of 8
260	// subgroup uniform load result
261	group.add("subgroup_uniform"); // Assumes subgroup size <= LocalSize 8
262	// workgroup uniform compare result
263	group.add("workgroup_cfg_uniform_id");
264	// workgroup uniform load result
265	group.add("workgroup_uniform");
266	spirv1p4Tests->addChild(createTestGroup(testCtx, "uniformid", addTestsForAmberFiles, group));
267
268	group = CaseGroup(data_dir, "nonwritable");
269	// NonWritable decorates Function variables
270	group.add("function_2_nonwritable");
271	// NonWritable decorates 2 Function variables
272	group.add("function_nonwritable");
273	// NonWritable decorates Function variable in non-entrypoint function
274	group.add("non_main_function_nonwritable");
275	// NonWritable decorates Private variables
276	group.add("private_2_nonwritable");
277	// NonWritable decorates 2 Private variables
278	group.add("private_nonwritable");
279	spirv1p4Tests->addChild(createTestGroup(testCtx, "nonwritable", addTestsForAmberFiles, group));
280
281	group = CaseGroup(data_dir, "entrypoint");
282	// push constant on compute shader entry point
283	group.add("comp_pc_entry_point");
284	// SSBO on compute shader entry point
285	group.add("comp_ssbo_entry_point");
286	// UBO on compute shader entry point
287	group.add("comp_ubo_entry_point");
288	// Workgroup var on compute shader entry point
289	group.add("comp_workgroup_entry_point");
290	// push constant on fragment shader entry point
291	group.add("frag_pc_entry_point");
292	// SSBO on fragment shader entry point
293	group.add("frag_ssbo_entry_point");
294	// UBO on fragment shader entry point
295	group.add("frag_ubo_entry_point");
296	// push constant on geometry shader entry point
297	group.add("geom_pc_entry_point", Geom);
298	// SSBO on geometry shader entry point
299	group.add("geom_ssbo_entry_point", Geom);
300	// UBO on geometry shader entry point
301	group.add("geom_ubo_entry_point", Geom);
302	// push constant on tess control shader entry point
303	group.add("tess_con_pc_entry_point", Tess);
304	// SSBO on tess control shader entry point
305	group.add("tess_con_ssbo_entry_point", Tess);
306	// UBO on tess control shader entry point
307	group.add("tess_con_ubo_entry_point", Tess);
308	// push constant on tess eval shader entry point
309	group.add("tess_eval_pc_entry_point", Tess);
310	// SSBO on tess eval shader entry point
311	group.add("tess_eval_ssbo_entry_point", Tess);
312	// UBO on tess eval shader entry point
313	group.add("tess_eval_ubo_entry_point", Tess);
314	// push constant on vertex shader entry point
315	group.add("vert_pc_entry_point");
316	// SSBO on vertex shader entry point
317	group.add("vert_ssbo_entry_point");
318	// UBO on vertex shader entry point
319	group.add("vert_ubo_entry_point");
320	// EntryPoint lists all module-scope variables
321	spirv1p4Tests->addChild(createTestGroup(testCtx, "entrypoint", addTestsForAmberFiles, group));
322
323	group = CaseGroup(data_dir, "hlsl_functionality1");
324	// CounterBuffer decoration
325	group.add("counter_buffer");
326	// OpDecorateString
327	group.add("decorate_string");
328	// OpMemberDecorateString
329	group.add("member_decorate_string");
330	// Features in SPV_GOOGLE_hlsl_functionality1 in SPIR-V 1.4
331	spirv1p4Tests->addChild(createTestGroup(testCtx, "hlsl_functionality1", addTestsForAmberFiles, group));
332
333	group = CaseGroup(data_dir, "loop_control");
334	// Loop control IterationMultiple
335	group.add("iteration_multiple");
336	// Loop control MaxIterations
337	group.add("max_iterations");
338	// Loop control MinIterations
339	group.add("min_iterations");
340	// Loop control PartialCount
341	group.add("partial_count");
342	// Loop control PeelCount
343	group.add("peel_count");
344	// SPIR-V 1.4 loop controls
345	spirv1p4Tests->addChild(createTestGroup(testCtx, "loop_control", addTestsForAmberFiles, group));
346
347	group = CaseGroup(data_dir, "opselect");
348	// OpSelect arrays, new in SPIR-V 1.4
349	group.add("array_select");
350	// OpSelect arrays with non-standard strides, new in SPIR-V 1.4
351	group.add("array_stride_select");
352	// OpSelect structs with nested arrays, new in SPIR-V 1.4
353	group.add("nested_array_select");
354	// OpSelect structs with nested structs, new in SPIR-V 1.4
355	group.add("nested_struct_select");
356	// OpSelect scalars, verify SPIR-V 1.0
357	group.add("scalar_select");
358	// OpSelect SSBO pointers to different buffers, verify SPIR-V 1.0
359	group.add("ssbo_pointers_2_select", Varptr_full);
360	// OpSelect SSBO pointers to same buffer, verify SPIR-V 1.0
361	group.add("ssbo_pointers_select", Varptr_ssbo);
362	// OpSelect structs, new in SPIR-V 1.4
363	group.add("struct_select");
364	// OpSelect vector with vector selector, verify SPIR-V 1.0
365	group.add("vector_element_select");
366	// OpSelect vector with scalar selector, new in SPIR-V 1.4
367	group.add("vector_select");
368	// OpSelect Workgroup pointers to different buffers, verify SPIR-V 1.0
369	group.add("wg_pointers_2_select", Varptr_full);
370	// OpSelect Workgroup pointers to same buffer, verify SPIR-V 1.0
371	group.add("wg_pointers_select", Varptr_full);
372	// SPIR-V 1.4 OpSelect more cases
373	spirv1p4Tests->addChild(createTestGroup(testCtx, "opselect", addTestsForAmberFiles, group));
374
375	group = CaseGroup(data_dir, "uconvert");
376	// uconvert small to int64
377	group.add("spec_const_opt_extend_16_64_bit", Int64);
378	// uconvert from int16
379	group.add("spec_const_opt_extend_16", Int16);
380	// uconvert large to int64
381	group.add("spec_const_opt_extend_251658240_64_bits", Int64);
382	// uconvert large from int16
383	group.add("spec_const_opt_extend_61440", Int16);
384	// uconvert from int64
385	group.add("spec_const_opt_truncate_16_64_bit", Int64);
386	// uconvert small to int16
387	group.add("spec_const_opt_truncate_16", Int16_storage);
388	// uconvert large to int16
389	group.add("spec_const_opt_truncate_983040", Int16_storage);
390	// uconvert negative from int16
391	group.add("spec_const_opt_zero_extend_n4096", Int16);
392	// SPIR-V 1.4 UConvert in OpSpecConstantOp
393	spirv1p4Tests->addChild(createTestGroup(testCtx, "uconvert", addTestsForAmberFiles, group));
394
395	group = CaseGroup(data_dir, "wrap");
396	// Accept NoSignedWrap decoration
397	group.add("no_signed_wrap");
398	// Accept NoUnsignedWrap decoration
399	group.add("no_unsigned_wrap");
400	// SPIR-V 1.4 integer wrap decorations
401	spirv1p4Tests->addChild(createTestGroup(testCtx, "wrap", addTestsForAmberFiles, group));
402
403	return spirv1p4Tests.release();
404}
405
406} // SpirVAssembly
407} // vkt
408