• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Test copying struct which contains an empty struct.
22 		  Test pointer comparisons of empty struct members.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktSpvAsmComputeShaderTestUtil.hpp"
26 #include "vktSpvAsmComputeShaderCase.hpp"
27 #include "vktSpvAsmEmptyStructTests.hpp"
28 #include "tcuStringTemplate.hpp"
29 #include "vktTestGroupUtil.hpp"
30 #include "vktSpvAsmUtils.hpp"
31 
32 namespace vkt
33 {
34 namespace SpirVAssembly
35 {
36 namespace
37 {
38 
verifyResult(const std::vector<Resource> &,const std::vector<AllocationSp> & outputAllocs,const std::vector<Resource> & expectedOutputs,tcu::TestLog &)39 bool verifyResult(const std::vector<Resource>&,
40 				  const std::vector<AllocationSp>&	outputAllocs,
41 				  const std::vector<Resource>&		expectedOutputs,
42 				  tcu::TestLog&)
43 {
44 	for (deUint32 outputNdx = 0; outputNdx < static_cast<deUint32>(outputAllocs.size()); ++outputNdx)
45 	{
46 		std::vector<deUint8> expectedBytes;
47 		expectedOutputs[outputNdx].getBytes(expectedBytes);
48 
49 		const deUint32  itemCount	= static_cast<deUint32>(expectedBytes.size()) / 4u;
50 		const deUint32* returned	= static_cast<const deUint32*>(outputAllocs[outputNdx]->getHostPtr());
51 		const deUint32* expected	= reinterpret_cast<const deUint32*>(&expectedBytes.front());
52 
53 		for (deUint32 i = 0; i < itemCount; ++i)
54 		{
55 			// skip items with 0 as this is used to mark empty structure
56 			if (expected[i] == 0)
57 				continue;
58 			if (expected[i] != returned[i])
59 				return false;
60 		}
61 	}
62 	return true;
63 }
64 
addCopyingComputeGroup(tcu::TestCaseGroup * group)65 void addCopyingComputeGroup(tcu::TestCaseGroup* group)
66 {
67 	const tcu::StringTemplate shaderTemplate(
68 		"OpCapability Shader\n"
69 
70 		"OpExtension \"SPV_KHR_storage_buffer_storage_class\"\n"
71 
72 		"OpMemoryModel Logical GLSL450\n"
73 		"OpEntryPoint GLCompute %main \"main\" %var_id\n"
74 		"OpExecutionMode %main LocalSize 1 1 1\n"
75 
76 		"OpDecorate %var_id BuiltIn GlobalInvocationId\n"
77 		"OpDecorate %var_input Binding 0\n"
78 		"OpDecorate %var_input DescriptorSet 0\n"
79 
80 		"OpDecorate %var_outdata Binding 1\n"
81 		"OpDecorate %var_outdata DescriptorSet 0\n"
82 
83 		"OpMemberDecorate %type_container_struct 0 Offset 0\n"
84 		"OpMemberDecorate %type_container_struct 1 Offset ${OFFSET_1}\n"
85 		"OpMemberDecorate %type_container_struct 2 Offset ${OFFSET_2}\n"
86 		"OpMemberDecorate %type_container_struct 3 Offset ${OFFSET_3}\n"
87 		"OpDecorate %type_container_struct Block\n"
88 
89 		+ std::string(getComputeAsmCommonTypes()) +
90 
91 		//struct EmptyStruct {};
92 		//struct ContainerStruct {
93 		//  int i;
94 		//  A a1;
95 		//  A a2;
96 		//  int j;
97 		//};
98 		//layout(set=, binding = ) buffer block B b;
99 
100 		// types
101 		"%type_empty_struct					= OpTypeStruct\n"
102 		"%type_container_struct				= OpTypeStruct %i32 %type_empty_struct %type_empty_struct %i32\n"
103 
104 		"%type_container_struct_ubo_ptr		= OpTypePointer Uniform %type_container_struct\n"
105 		"%type_container_struct_ssbo_ptr	= OpTypePointer StorageBuffer %type_container_struct\n"
106 
107 		// variables
108 		"%var_id							= OpVariable %uvec3ptr Input\n"
109 		"${VARIABLES}\n"
110 
111 		// void main function
112 		"%main								= OpFunction %void None %voidf\n"
113 		"%label								= OpLabel\n"
114 
115 		"${COPYING_METHOD}"
116 
117 		"OpReturn\n"
118 		"OpFunctionEnd\n");
119 
120 	struct BufferType
121 	{
122 		std::string				name;
123 		VkDescriptorType		descriptorType;
124 		std::vector<deUint32>	offsets;
125 		std::vector<int>		input;
126 		std::vector<int>		expectedOutput;
127 		std::string				spirvVariables;
128 		std::string				spirvCopyObject;
129 
130 		BufferType (const std::string&				name_,
131 					VkDescriptorType				descriptorType_,
132 					const std::vector<uint32_t>&	offsets_,
133 					const std::vector<int>&			input_,
134 					const std::vector<int>&			expectedOutput_,
135 					const std::string&				spirvVariables_,
136 					const std::string&				spirvCopyObject_)
137 			: name				(name_)
138 			, descriptorType	(descriptorType_)
139 			, offsets			(offsets_)
140 			, input				(input_)
141 			, expectedOutput	(expectedOutput_)
142 			, spirvVariables	(spirvVariables_)
143 			, spirvCopyObject	(spirvCopyObject_)
144 			{}
145 	};
146 	const std::vector<BufferType> bufferTypes
147 	{
148 		{
149 			"ubo",
150 			VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
151 
152 			// structure decorated as Block for variable in Uniform storage class
153 			// must follow relaxed uniform buffer layout rules and be aligned to 16
154 			{0, 16, 32, 48},
155 			{2, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 7, 0, 0, 0},
156 			{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0},
157 
158 			"%var_input						= OpVariable %type_container_struct_ubo_ptr Uniform\n"
159 			"%var_outdata					= OpVariable %type_container_struct_ssbo_ptr StorageBuffer\n",
160 
161 			"%input_copy					= OpCopyObject %type_container_struct_ubo_ptr %var_input\n"
162 		},
163 		{
164 			"ssbo",
165 			VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
166 
167 			{0, 4, 8, 12},
168 			{2, 3, 5, 7 },
169 			{2, 0, 0, 7 },
170 
171 			"%var_input						= OpVariable %type_container_struct_ssbo_ptr StorageBuffer\n"
172 			"%var_outdata					= OpVariable %type_container_struct_ssbo_ptr StorageBuffer\n",
173 
174 			"%input_copy					= OpCopyObject %type_container_struct_ssbo_ptr %var_input\n"
175 		}
176 	};
177 
178 	struct CopyingMethod
179 	{
180 		std::string name;
181 		std::string spirvCopyCode;
182 
183 		CopyingMethod (const std::string& name_, const std::string& spirvCopyCode_)
184 			: name			(name_)
185 			, spirvCopyCode	(spirvCopyCode_)
186 			{}
187 	};
188 	const std::vector<CopyingMethod> copyingMethods
189 	{
190 		{
191 			"copy_object",
192 
193 			"%result						= OpLoad %type_container_struct %input_copy\n"
194 			"OpStore %var_outdata %result\n"
195 		},
196 		{
197 			"copy_memory",
198 
199 			"OpCopyMemory %var_outdata %var_input\n"
200 		}
201 	};
202 
203 	for (const auto& bufferType : bufferTypes)
204 	{
205 		for (const auto& copyingMethod : copyingMethods)
206 		{
207 			std::string name = copyingMethod.name + "_" + bufferType.name;
208 
209 			std::map<std::string, std::string> specializationMap
210 			{
211 				{ "OFFSET_1",		de::toString(bufferType.offsets[1]) },
212 				{ "OFFSET_2",		de::toString(bufferType.offsets[2]) },
213 				{ "OFFSET_3",		de::toString(bufferType.offsets[3]) },
214 				{ "VARIABLES",		bufferType.spirvVariables },
215 
216 				// NOTE: to simlify code spirvCopyObject is added also when OpCopyMemory is used
217 				{ "COPYING_METHOD", bufferType.spirvCopyObject + copyingMethod.spirvCopyCode },
218 			};
219 
220 			ComputeShaderSpec spec;
221 			spec.assembly		= shaderTemplate.specialize(specializationMap);
222 			spec.numWorkGroups	= tcu::IVec3(1, 1, 1);
223 			spec.verifyIO		= verifyResult;
224 			spec.inputs.push_back (Resource(BufferSp(new Int32Buffer(bufferType.input)), bufferType.descriptorType));
225 			spec.outputs.push_back(Resource(BufferSp(new Int32Buffer(bufferType.expectedOutput))));
226 			group->addChild(new SpvAsmComputeShaderCase(group->getTestContext(), name.c_str(), "", spec));
227 		}
228 	}
229 }
230 
addPointerComparisionComputeGroup(tcu::TestCaseGroup * group)231 void addPointerComparisionComputeGroup(tcu::TestCaseGroup* group)
232 {
233   // NOTE: pointer comparison is possible only for StorageBuffer storage class
234 
235   std::string computeSource =
236       "OpCapability Shader\n"
237       "OpCapability VariablePointersStorageBuffer\n"
238 
239       "OpMemoryModel Logical GLSL450\n"
240       "OpEntryPoint GLCompute %main \"main\" %var_id %var_input %var_outdata\n"
241       "OpExecutionMode %main LocalSize 1 1 1\n"
242 
243       "OpDecorate %var_id BuiltIn GlobalInvocationId\n"
244       "OpDecorate %var_input Binding 0\n"
245       "OpDecorate %var_input DescriptorSet 0\n"
246 
247       "OpDecorate %var_outdata Binding 1\n"
248       "OpDecorate %var_outdata DescriptorSet 0\n"
249 
250       "OpMemberDecorate %type_container_struct 0 Offset 0\n"
251       "OpMemberDecorate %type_container_struct 1 Offset 4\n"
252       "OpMemberDecorate %type_container_struct 2 Offset 8\n"
253       "OpMemberDecorate %type_container_struct 3 Offset 12\n"
254       "OpDecorate %type_container_struct Block\n"
255 
256       "OpMemberDecorate %type_i32_struct 0 Offset 0\n"
257       "OpDecorate %type_i32_struct Block\n"
258 
259       + std::string(getComputeAsmCommonTypes("StorageBuffer")) +
260 
261       // struct EmptyStruct {};
262       // struct ContainerStruct {
263       //  int i;
264       //  A a1;
265       //  A a2;
266       //  int j;
267       //};
268       // layout(set=, binding = ) buffer block B b;
269 
270       // types
271       "%type_empty_struct					= "
272       "OpTypeStruct\n"
273       "%type_container_struct				= OpTypeStruct %i32 "
274       "%type_empty_struct %type_empty_struct %i32\n"
275       "%type_i32_struct					= OpTypeStruct %i32\n"
276 
277       // constants
278       "%c_i32_0							= OpConstant "
279       "%i32 0\n"
280       "%c_i32_1							= OpConstant "
281       "%i32 1\n"
282       "%c_i32_2							= OpConstant "
283       "%i32 2\n"
284 
285       "%type_container_struct_in_ptr		= OpTypePointer StorageBuffer "
286       "%type_container_struct\n"
287       "%type_i32_struct_out_ptr			= OpTypePointer StorageBuffer "
288       "%type_i32_struct\n"
289 
290       "%type_func_struct_ptr_ptr			= OpTypePointer "
291       "StorageBuffer %type_empty_struct\n"
292 
293       // variables
294       "%var_id							= OpVariable "
295       "%uvec3ptr Input\n"
296       "%var_input							= "
297       "OpVariable %type_container_struct_in_ptr StorageBuffer\n"
298       "%var_outdata						= OpVariable "
299       "%type_i32_struct_out_ptr StorageBuffer\n"
300 
301       // void main function
302       "%main								= "
303       "OpFunction %void None %voidf\n"
304       "%label								= "
305       "OpLabel\n"
306 
307       // compare pointers to empty structures
308       "%ptr_to_first						= "
309       "OpAccessChain %type_func_struct_ptr_ptr %var_input %c_i32_1\n"
310       "%ptr_to_second						= "
311       "OpAccessChain %type_func_struct_ptr_ptr %var_input %c_i32_2\n"
312       "%pointers_not_equal				= OpPtrNotEqual %bool "
313       "%ptr_to_first %ptr_to_second\n"
314       "%result							= OpSelect "
315       "%i32 %pointers_not_equal %c_i32_1 %c_i32_0\n"
316       "%outloc							= "
317       "OpAccessChain %i32ptr %var_outdata %c_i32_0\n"
318       "OpStore %outloc %result\n"
319 
320       "OpReturn\n"
321       "OpFunctionEnd\n";
322 
323   tcu::TestContext &testCtx = group->getTestContext();
324   std::vector<int> input = {2, 3, 5, 7};
325   std::vector<int> expectedOutput = {1};
326 
327   ComputeShaderSpec spec;
328   spec.assembly = computeSource;
329   spec.numWorkGroups = tcu::IVec3(1, 1, 1);
330   spec.spirvVersion = SPIRV_VERSION_1_4;
331   spec.requestedVulkanFeatures.extVariablePointers.variablePointersStorageBuffer = true;
332   spec.inputs.push_back(Resource(BufferSp(new Int32Buffer(input))));
333   spec.outputs.push_back(Resource(BufferSp(new Int32Buffer(expectedOutput))));
334   spec.extensions.push_back("VK_KHR_spirv_1_4");
335   group->addChild(new SpvAsmComputeShaderCase(testCtx, "ssbo", "", spec));
336 }
337 
addFunctionArgumentReturnValueGroup(tcu::TestCaseGroup * group)338 void addFunctionArgumentReturnValueGroup(tcu::TestCaseGroup* group)
339 {
340   const tcu::StringTemplate shaderTemplate(
341       "      OpCapability Shader\n"
342       " %1 = OpExtInstImport \"GLSL.std.450\"\n"
343       "      OpMemoryModel Logical GLSL450\n"
344       "      OpEntryPoint GLCompute %4 \"main\" %29 %42 %51 ${GLOBAL_VARIABLE} %79\n"
345       "      OpExecutionMode %4 LocalSize 2 1 1\n"
346       "      OpSource GLSL 460\n"
347       "      OpDecorate %29 BuiltIn LocalInvocationId\n"
348       "      OpMemberDecorate %40 0 Offset 0\n"
349       "      OpMemberDecorate %40 1 Offset 4\n"
350       "      OpMemberDecorate %40 2 Offset 8\n"
351       "      OpDecorate %40 Block\n"
352       "      OpDecorate %42 DescriptorSet 0\n"
353       "      OpDecorate %42 Binding 1\n"
354       "      OpMemberDecorate %49 0 Offset 0\n"
355       "      OpDecorate %49 Block\n"
356       "      OpDecorate %51 DescriptorSet 0\n"
357       "      OpDecorate %51 Binding 0\n"
358       "      OpMemberDecorate %77 0 Offset 0\n"
359       "      OpMemberDecorate %77 1 Offset 4\n"
360       "      OpMemberDecorate %77 2 Offset 8\n"
361       "      OpDecorate %77 Block\n"
362       "      OpDecorate %79 DescriptorSet 0\n"
363       "      OpDecorate %79 Binding 2\n"
364       "      OpDecorate %96 BuiltIn WorkgroupSize\n"
365       " %2 = OpTypeVoid\n"
366       " %3 = OpTypeFunction %2\n"
367       " %7 = OpTypeStruct\n"
368       " %8 = OpTypePointer Function %7\n"
369       " %9 = OpTypeBool\n"
370       "%10 = OpTypePointer Function %9\n"
371       "%11 = OpTypeFunction %7 %8 %8 %10\n"
372       "%26 = OpTypeInt 32 0\n"
373       "%27 = OpTypeVector %26 3\n"
374       "%28 = OpTypePointer Input %27\n"
375       "%29 = OpVariable %28 Input\n"
376       "%30 = OpConstant %26 0\n"
377       "%31 = OpTypePointer Input %26\n"
378       "%34 = OpConstant %26 2\n"
379       "%39 = OpTypeStruct\n"
380       "%40 = OpTypeStruct %26 %39 %26\n"
381       "%41 = OpTypePointer StorageBuffer %40\n"
382       "%42 = OpVariable %41 StorageBuffer\n"
383       "%43 = OpTypeInt 32 1\n"
384       "%44 = OpConstant %43 0\n"
385       "%45 = OpConstant %26 1\n"
386       "%46 = OpTypePointer StorageBuffer %26\n"
387       "%48 = OpConstant %43 1\n"
388       "%49 = OpTypeStruct %39\n"
389       "%50 = OpTypePointer StorageBuffer %49\n"
390       "%51 = OpVariable %50 StorageBuffer\n"
391 
392       "${VARIABLE_DEFINITION}\n"
393 
394       "%59 = OpTypePointer StorageBuffer %39\n"
395       "%69 = OpConstant %43 2\n"
396       "%77 = OpTypeStruct %26 %39 %26\n"
397       "%78 = OpTypePointer StorageBuffer %77\n"
398       "%79 = OpVariable %78 StorageBuffer\n"
399       "%96 = OpConstantComposite %27 %34 %45 %45\n"
400       " %4 = OpFunction %2 None %3\n"
401       " %5 = OpLabel\n"
402 
403       "${VARIABLE_FUNCTION_DEFINITION}\n"
404 
405       "%58 = OpVariable %8 Function\n"
406       "%63 = OpVariable %8 Function\n"
407       "%65 = OpVariable %10 Function\n"
408       "%85 = OpVariable %8 Function\n"
409       "%89 = OpVariable %8 Function\n"
410       "%91 = OpVariable %10 Function\n"
411       "%32 = OpAccessChain %31 %29 %30\n"
412       "%33 = OpLoad %26 %32\n"
413       "%35 = OpUMod %26 %33 %34\n"
414       "%36 = OpIEqual %9 %35 %30\n"
415       "      OpSelectionMerge %38 None\n"
416       "      OpBranchConditional %36 %37 %38\n"
417       "%37 = OpLabel\n"
418       "%47 = OpAccessChain %46 %42 %44\n"
419       "      OpStore %47 %45\n"
420       "%54 = OpAccessChain %31 %29 %30\n"
421       "%55 = OpLoad %26 %54\n"
422       "%56 = OpUMod %26 %55 %34\n"
423       "%57 = OpIEqual %9 %56 %30\n"
424       "%60 = OpAccessChain %59 %51 %44\n"
425       "%61 = OpLoad %39 %60\n"
426       "%62 = OpCopyLogical %7 %61\n"
427       "      OpStore %58 %62\n"
428       "%64 = OpLoad %7 %53\n"
429       "      OpStore %63 %64\n"
430       "      OpStore %65 %57\n"
431       "%66 = OpFunctionCall %7 %15 %58 %63 %65\n"
432       "%67 = OpAccessChain %59 %42 %48\n"
433       "%68 = OpCopyLogical %39 %66\n"
434       "      OpStore %67 %68\n"
435       "%70 = OpAccessChain %46 %42 %69\n"
436       "      OpStore %70 %45\n"
437       "      OpBranch %38\n"
438       "%38 = OpLabel\n"
439       "%71 = OpAccessChain %31 %29 %30\n"
440       "%72 = OpLoad %26 %71\n"
441       "%73 = OpUMod %26 %72 %34\n"
442       "%74 = OpIEqual %9 %73 %45\n"
443       "      OpSelectionMerge %76 None\n"
444       "      OpBranchConditional %74 %75 %76\n"
445       "%75 = OpLabel\n"
446       "%80 = OpAccessChain %46 %79 %44\n"
447       "      OpStore %80 %45\n"
448       "%81 = OpAccessChain %31 %29 %30\n"
449       "%82 = OpLoad %26 %81\n"
450       "%83 = OpUMod %26 %82 %34\n"
451       "%84 = OpIEqual %9 %83 %45\n"
452       "%86 = OpAccessChain %59 %51 %44\n"
453       "%87 = OpLoad %39 %86\n"
454       "%88 = OpCopyLogical %7 %87\n"
455       "      OpStore %85 %88\n"
456       "%90 = OpLoad %7 %53\n"
457       "      OpStore %89 %90\n"
458       "      OpStore %91 %84\n"
459       "%92 = OpFunctionCall %7 %15 %85 %89 %91\n"
460       "%93 = OpAccessChain %59 %79 %48\n"
461       "%94 = OpCopyLogical %39 %92\n"
462       "      OpStore %93 %94\n"
463       "%95 = OpAccessChain %46 %79 %69\n"
464       "      OpStore %95 %45\n"
465       "      OpBranch %76\n"
466       "%76 = OpLabel\n"
467       "      OpReturn\n"
468       "      OpFunctionEnd\n"
469       "%15 = OpFunction %7 None %11\n"
470       "%12 = OpFunctionParameter %8\n"
471       "%13 = OpFunctionParameter %8\n"
472       "%14 = OpFunctionParameter %10\n"
473       "%16 = OpLabel\n"
474       "%17 = OpLoad %9 %14\n"
475       "      OpSelectionMerge %19 None\n"
476       "      OpBranchConditional %17 %18 %22\n"
477       "%18 = OpLabel\n"
478       "%20 = OpLoad %7 %12\n"
479       "      OpReturnValue %20\n"
480       "%22 = OpLabel\n"
481       "%23 = OpLoad %7 %13\n"
482       "      OpReturnValue %23\n"
483       "%19 = OpLabel\n"
484       "      OpUnreachable\n"
485       "      OpFunctionEnd\n");
486 
487   struct VariableDefinition {
488 	  std::string name;
489 	  std::string globalVariable;
490 	  std::string spirvVariableDefinitionCode;
491 	  std::string spirvVariableFunctionDefinitionCode;
492   };
493 
494 	std::vector<VariableDefinition> variableDefinitions
495 	{
496 		{
497 			"global_variable_private",
498 
499 			"%53",
500 
501 			"%52 = OpTypePointer Private %7\n"
502 			"%53 = OpVariable %52 Private\n",
503 
504 			""
505 		},
506 
507 		{
508 			"global_variable_shared",
509 
510 			"%53",
511 
512 			"%52 = OpTypePointer Workgroup %7\n"
513 			"%53 = OpVariable %52 Workgroup\n",
514 
515 			""
516 		},
517 
518 		{
519 			"local_variable",
520 
521 			"",
522 
523 			"",
524 
525 			"%53 = OpVariable %8 Function\n"
526 		},
527 	};
528 
529 	tcu::TestContext &testCtx = group->getTestContext();
530 	std::vector<int> input = {2};
531 
532 	std::vector<deUint32> expectedOutput = {1, 0xffffffff, 1};
533 
534 	for (const auto &variableDefinition : variableDefinitions)
535 	{
536 		std::map<std::string, std::string> specializationMap
537 		{
538 			{ "GLOBAL_VARIABLE", variableDefinition.globalVariable },
539 			{ "VARIABLE_DEFINITION", variableDefinition.spirvVariableDefinitionCode },
540 			{ "VARIABLE_FUNCTION_DEFINITION", variableDefinition.spirvVariableFunctionDefinitionCode },
541 		};
542 
543 		ComputeShaderSpec spec;
544 		spec.assembly = shaderTemplate.specialize(specializationMap);
545 		spec.numWorkGroups = tcu::IVec3(2, 1, 1);
546 		spec.spirvVersion = SPIRV_VERSION_1_4;
547 		spec.requestedVulkanFeatures.extVariablePointers.variablePointersStorageBuffer = true;
548 		spec.inputs.push_back(Resource(BufferSp(new Int32Buffer(input))));
549 		spec.outputs.push_back(
550 							   Resource(BufferSp(new Uint32Buffer(expectedOutput))));
551 		spec.outputs.push_back(
552 							   Resource(BufferSp(new Uint32Buffer(expectedOutput))));
553 		spec.extensions.push_back("VK_KHR_spirv_1_4");
554 		group->addChild(new SpvAsmComputeShaderCase(
555 													testCtx, variableDefinition.name.c_str(), "", spec));
556 	}
557 }
558 
559 } // anonymous
560 
createEmptyStructComputeGroup(tcu::TestContext & testCtx)561 tcu::TestCaseGroup* createEmptyStructComputeGroup (tcu::TestContext& testCtx)
562 {
563 	de::MovePtr<tcu::TestCaseGroup> group	(new tcu::TestCaseGroup(testCtx, "empty_struct", "Tests empty structs in UBOs and SSBOs"));
564 
565 	addTestGroup(group.get(), "copying",			"Test copying struct which contains an empty struct",	addCopyingComputeGroup);
566 	addTestGroup(group.get(), "pointer_comparison",	"Test pointer comparisons of empty struct members",		addPointerComparisionComputeGroup);
567 	addTestGroup(group.get(), "function", "Test empty structs as function arguments or return type", addFunctionArgumentReturnValueGroup);
568 
569 	return group.release();
570 }
571 
572 } // SpirVAssembly
573 } // vkt
574