1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2023 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 multiple entry points.
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktSpvAsmMultipleShadersTests.hpp"
25 #include "vktTestCaseUtil.hpp"
26 #include "vkPrograms.hpp"
27 #include "vkObjUtil.hpp"
28 #include "vkRefUtil.hpp"
29 #include "vkTypeUtil.hpp"
30 #include "vkQueryUtil.hpp"
31 #include "vkBuilderUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkCmdUtil.hpp"
35
36 namespace vkt
37 {
38 namespace SpirVAssembly
39 {
40
41 namespace
42 {
43
44 using namespace vk;
45
46 using BufferWithMemorySp = de::SharedPtr<BufferWithMemory>;
47
48 enum class TestType
49 {
50 // two entry points where each OpEntryPoint has associated OpExectionModeId
51 TWO_ENTRY_POINTS_EXECUTION_MODE_ID = 0,
52
53 // two entry points where each has different interfaces
54 TWO_ENTRY_POINTS_DIFFERENT_INTERFACES,
55 };
56
57 struct TestConfig
58 {
59 TestType type;
60 };
61
62 class EntryPointsTest : public TestInstance
63 {
64 public:
65 EntryPointsTest(Context &context, TestConfig config);
66 virtual ~EntryPointsTest(void) = default;
67
68 tcu::TestStatus iterate(void);
69
70 private:
71 TestConfig m_config;
72 };
73
EntryPointsTest(Context & context,TestConfig config)74 EntryPointsTest::EntryPointsTest(Context &context, TestConfig config) : TestInstance(context), m_config(config)
75 {
76 }
77
iterate(void)78 tcu::TestStatus EntryPointsTest::iterate(void)
79 {
80 const DeviceInterface &vk = m_context.getDeviceInterface();
81 const VkDevice device = m_context.getDevice();
82 const VkQueue queue = m_context.getUniversalQueue();
83 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
84 Allocator &memAlloc = m_context.getDefaultAllocator();
85
86 // Create test buffers
87 const uint32_t bufferItems = 24u;
88 const VkDeviceSize bufferSize = static_cast<VkDeviceSize>(bufferItems * sizeof(uint32_t));
89 const VkBufferUsageFlags bufferusage =
90 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
91 const bool useTwoBuffers = (m_config.type == TestType::TWO_ENTRY_POINTS_DIFFERENT_INTERFACES);
92 VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSize, bufferusage);
93 BufferWithMemorySp bufferA = BufferWithMemorySp(
94 new BufferWithMemory(vk, device, memAlloc, bufferCreateInfo, MemoryRequirement::HostVisible));
95 ;
96 BufferWithMemorySp bufferB = BufferWithMemorySp(
97 new BufferWithMemory(vk, device, memAlloc, bufferCreateInfo, MemoryRequirement::HostVisible));
98 ;
99
100 // Write data to test buffers
101 int dataASrc[bufferItems];
102 int dataBSrc[bufferItems];
103 for (int i = 0; i < DE_LENGTH_OF_ARRAY(dataASrc); ++i)
104 {
105 dataASrc[i] = deAbs32(9 * deAbs32(int(i / 6) - 1) - (i % 6)) + (i == 6);
106 dataBSrc[i] = 1 + i * 2;
107 }
108 auto fillBuffer = [&](BufferWithMemorySp buffer, int *dataSrc)
109 {
110 Allocation &allocation = buffer->getAllocation();
111 int *bufferPtr = static_cast<int *>(allocation.getHostPtr());
112 deMemcpy(bufferPtr, dataSrc, bufferSize);
113 flushAlloc(vk, device, allocation);
114 };
115 fillBuffer(bufferA, dataASrc);
116 fillBuffer(bufferB, dataBSrc);
117
118 // Create descriptor set
119 const VkDescriptorType descType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
120 DescriptorSetLayoutBuilder dsLayoutBuilder;
121 dsLayoutBuilder.addSingleBinding(descType, VK_SHADER_STAGE_COMPUTE_BIT);
122 if (useTwoBuffers)
123 dsLayoutBuilder.addSingleBinding(descType, VK_SHADER_STAGE_COMPUTE_BIT);
124 const Unique<VkDescriptorSetLayout> descriptorSetLayout(dsLayoutBuilder.build(vk, device));
125
126 const Unique<VkDescriptorPool> descriptorPool(
127 DescriptorPoolBuilder()
128 .addType(descType, 1 + useTwoBuffers)
129 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
130
131 const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
132
133 const VkDescriptorBufferInfo bufferADescriptorInfo = makeDescriptorBufferInfo(**bufferA, 0ull, bufferSize);
134 const VkDescriptorBufferInfo bufferBDescriptorInfo = makeDescriptorBufferInfo(**bufferB, 0ull, bufferSize);
135 DescriptorSetUpdateBuilder descriptorSetUpdateBuilder;
136 descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), descType,
137 &bufferADescriptorInfo);
138 if (useTwoBuffers)
139 descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
140 descType, &bufferBDescriptorInfo);
141 descriptorSetUpdateBuilder.update(vk, device);
142
143 // Perform the computation
144 const Unique<VkShaderModule> shaderModule(
145 createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u));
146 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
147
148 const VkPipelineShaderStageCreateInfo pipelineAShaderStageParams{
149 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
150 DE_NULL,
151 static_cast<VkPipelineShaderStageCreateFlags>(0u),
152 VK_SHADER_STAGE_COMPUTE_BIT,
153 *shaderModule,
154 "mainA",
155 DE_NULL,
156 };
157 const VkPipelineShaderStageCreateInfo pipelineBShaderStageParams{
158 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
159 DE_NULL,
160 static_cast<VkPipelineShaderStageCreateFlags>(0u),
161 VK_SHADER_STAGE_COMPUTE_BIT,
162 *shaderModule,
163 "mainB",
164 DE_NULL,
165 };
166 VkComputePipelineCreateInfo pipelineCreateInfo{
167 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
168 DE_NULL,
169 static_cast<VkPipelineCreateFlags>(0u),
170 pipelineBShaderStageParams,
171 *pipelineLayout,
172 DE_NULL,
173 0,
174 };
175
176 Unique<VkPipeline> pipelineB(createComputePipeline(vk, device, DE_NULL, &pipelineCreateInfo));
177 pipelineCreateInfo.stage = pipelineAShaderStageParams;
178 Unique<VkPipeline> pipelineA(createComputePipeline(vk, device, DE_NULL, &pipelineCreateInfo));
179
180 const VkMemoryBarrier hostWriteBarrier(makeMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT));
181 const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
182 const Unique<VkCommandBuffer> cmdBuffer(
183 allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
184
185 // Start recording commands
186 beginCommandBuffer(vk, *cmdBuffer);
187
188 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1,
189 &hostWriteBarrier, 0, 0, 0, 0);
190
191 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineB);
192 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u,
193 0);
194 vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
195
196 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineA);
197 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u,
198 0);
199 vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
200
201 endCommandBuffer(vk, *cmdBuffer);
202
203 // Wait for completion
204 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
205
206 invalidateAlloc(vk, device, bufferA->getAllocation());
207
208 // Validate the results
209 if (m_config.type == TestType::TWO_ENTRY_POINTS_EXECUTION_MODE_ID)
210 {
211 int *bufferPtr = static_cast<int *>(bufferA->getAllocation().getHostPtr());
212 for (int i = 0; i < 6; i++)
213 {
214 if ((bufferPtr[12 + i] != (dataASrc[i] - dataASrc[6 + i])) ||
215 (bufferPtr[18 + i] != (dataASrc[i] * dataASrc[6 + i])))
216 return tcu::TestStatus::fail("Fail");
217 }
218 }
219 else if (m_config.type == TestType::TWO_ENTRY_POINTS_DIFFERENT_INTERFACES)
220 {
221 invalidateAlloc(vk, device, bufferB->getAllocation());
222 int *bufferAPtr = static_cast<int *>(bufferA->getAllocation().getHostPtr());
223 int *bufferBPtr = static_cast<int *>(bufferB->getAllocation().getHostPtr());
224 for (int i = 0; i < 6; i++)
225 {
226 if ((bufferAPtr[12 + i] != (dataASrc[i] + dataASrc[6 + i])) ||
227 (bufferBPtr[12 + i] != (dataBSrc[5 - i] * dataBSrc[11 - i])))
228 return tcu::TestStatus::fail("Fail");
229 }
230 }
231
232 return tcu::TestStatus::pass("Pass");
233 }
234
235 struct Programs
236 {
initvkt::SpirVAssembly::__anon0346374f0111::Programs237 void init(vk::SourceCollections &dst, TestConfig config) const
238 {
239 const SpirVAsmBuildOptions buildOptionsSpr(dst.usedVulkanVersion, SPIRV_VERSION_1_5, false, true);
240 std::string compSrc = "OpCapability Shader\n"
241 "%1 = OpExtInstImport \"GLSL.std.450\"\n"
242 "OpMemoryModel Logical GLSL450\n";
243
244 if (config.type == TestType::TWO_ENTRY_POINTS_EXECUTION_MODE_ID)
245 {
246 // #version 450
247 // layout(local_size_x = 2, local_size_y = 3) in;
248 // layout(binding = 0, std430) buffer InOut { int v[]; } inOut;
249 // void mainA()
250 // {
251 // uint id = gl_LocalInvocationIndex;
252 // inOut.v[12+id] = inOut.v[id] - inOut.v[6+id];
253 // }
254 // void mainB()
255 // {
256 // uint id = gl_LocalInvocationIndex;
257 // inOut.v[18+id] = inOut.v[id] * inOut.v[6+id];
258 // }
259
260 compSrc += "OpEntryPoint GLCompute %mainA \"mainA\" %inOutVar %gl_LocalInvocationIndex\n"
261 "OpEntryPoint GLCompute %mainB \"mainB\" %inOutVar %gl_LocalInvocationIndex\n"
262 "OpExecutionModeId %mainA LocalSizeId %uint_2 %uint_3 %uint_1\n"
263 "OpExecutionModeId %mainB LocalSizeId %uint_2 %uint_3 %uint_1\n"
264
265 "OpDecorate %runtimearr_int ArrayStride 4\n"
266 "OpMemberDecorate %InOut 0 Offset 0\n"
267 "OpDecorate %InOut Block\n"
268 "OpDecorate %inOutVar DescriptorSet 0\n"
269 "OpDecorate %inOutVar Binding 0\n"
270 "OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex\n"
271 "OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize\n"
272
273 "%void = OpTypeVoid\n"
274 "%int = OpTypeInt 32 1\n"
275 "%uint = OpTypeInt 32 0\n"
276 "%v3uint = OpTypeVector %uint 3\n"
277 "%void_fun = OpTypeFunction %void\n"
278 "%uint_fun = OpTypeFunction %uint\n"
279 "%runtimearr_int = OpTypeRuntimeArray %int\n"
280 "%InOut = OpTypeStruct %runtimearr_int\n"
281 "%ptr_Uniform_InOut = OpTypePointer StorageBuffer %InOut\n"
282 "%ptr_Uniform_int = OpTypePointer StorageBuffer %int\n"
283 "%ptr_uint_fun = OpTypePointer Function %uint\n"
284 "%ptr_v3uint_input = OpTypePointer Input %v3uint\n"
285 "%ptr_uint_input = OpTypePointer Input %uint\n"
286
287 "%int_0 = OpConstant %int 0\n"
288 "%uint_1 = OpConstant %uint 1\n"
289 "%uint_2 = OpConstant %uint 2\n"
290 "%uint_3 = OpConstant %uint 3\n"
291 "%uint_6 = OpConstant %uint 6\n"
292 "%uint_12 = OpConstant %uint 12\n"
293 "%uint_18 = OpConstant %uint 18\n"
294
295 "%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_2 %uint_3 %uint_1\n"
296 "%gl_LocalInvocationIndex = OpVariable %ptr_uint_input Input\n"
297 "%inOutVar = OpVariable %ptr_Uniform_InOut StorageBuffer\n"
298
299 "%mainA = OpFunction %void None %void_fun\n"
300 "%labelA = OpLabel\n"
301 "%idxA = OpLoad %uint %gl_LocalInvocationIndex\n"
302 "%30 = OpIAdd %uint %uint_12 %idxA\n"
303 "%33 = OpAccessChain %ptr_Uniform_int %inOutVar %int_0 %idxA\n"
304 "%34 = OpLoad %int %33\n"
305 "%37 = OpIAdd %uint %uint_6 %idxA\n"
306 "%38 = OpAccessChain %ptr_Uniform_int %inOutVar %int_0 %37\n"
307 "%39 = OpLoad %int %38\n"
308 "%40 = OpISub %int %34 %39\n"
309 "%41 = OpAccessChain %ptr_Uniform_int %inOutVar %int_0 %30\n"
310 "OpStore %41 %40\n"
311 "OpReturn\n"
312 "OpFunctionEnd\n"
313
314 "%mainB = OpFunction %void None %void_fun\n"
315 "%labelB = OpLabel\n"
316 "%idxB = OpLoad %uint %gl_LocalInvocationIndex\n"
317 "%60 = OpIAdd %uint %uint_18 %idxB\n"
318 "%63 = OpAccessChain %ptr_Uniform_int %inOutVar %int_0 %idxB\n"
319 "%64 = OpLoad %int %63\n"
320 "%67 = OpIAdd %uint %uint_6 %idxB\n"
321 "%68 = OpAccessChain %ptr_Uniform_int %inOutVar %int_0 %67\n"
322 "%69 = OpLoad %int %68\n"
323 "%70 = OpIMul %int %64 %69\n"
324 "%71 = OpAccessChain %ptr_Uniform_int %inOutVar %int_0 %60\n"
325 "OpStore %71 %70\n"
326 "OpReturn\n"
327 "OpFunctionEnd\n";
328
329 dst.spirvAsmSources.add("comp") << compSrc << buildOptionsSpr;
330 }
331 else if (config.type == TestType::TWO_ENTRY_POINTS_DIFFERENT_INTERFACES)
332 {
333 // #version 450
334 // layout(local_size_x = 3, local_size_y = 2) in;
335 // layout(binding = 0, std430) buffer BufferA { int v[]; } bufferA;
336 // layout(binding = 1, std430) buffer BufferB { int v[]; } bufferB;
337 // void mainA()
338 // {
339 // uint idx = gl_LocalInvocationIndex;
340 // bufferA.v[12+idx] = bufferA.v[idx] - bufferA.v[6+idx];
341 // }
342 // void mainB()
343 // {
344 // uint idxOut = 2 * gl_LocalInvocationID.x + gl_LocalInvocationID.y;
345 // uint idxIn = 6 - gl_NumWorkGroups.x - idxOut;
346 // bufferB.v[12+idxOut] = bufferB.v[idxIn] * bufferB.v[6+idxIn];
347 // }
348
349 compSrc += "OpEntryPoint GLCompute %mainA \"mainA\" %gl_LocalInvocationIndex\n"
350 "OpEntryPoint GLCompute %mainB \"mainB\" %gl_NumWorkGroups %gl_LocalInvocationId\n"
351 "OpExecutionMode %mainA LocalSize 3 2 1\n"
352 "OpExecutionMode %mainB LocalSize 3 2 1\n"
353 "OpDecorate %gl_NumWorkGroups BuiltIn NumWorkgroups\n"
354 "OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex\n"
355 "OpDecorate %gl_LocalInvocationId BuiltIn LocalInvocationId\n"
356 "OpDecorate %int_runtime_array ArrayStride 4\n"
357 "OpMemberDecorate %struct_type 0 Offset 0\n"
358 "OpDecorate %struct_type BufferBlock\n"
359 "OpDecorate %var_BufferA DescriptorSet 0\n"
360 "OpDecorate %var_BufferA Binding 0\n"
361 "OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize\n"
362 "OpDecorate %var_BufferB DescriptorSet 0\n"
363 "OpDecorate %var_BufferB Binding 1\n"
364
365 "%void = OpTypeVoid\n"
366 "%void_fun = OpTypeFunction %void\n"
367 "%uint = OpTypeInt 32 0\n"
368 "%int = OpTypeInt 32 1\n"
369 "%ptr_uint_fun = OpTypePointer Function %uint\n"
370 "%v3uint = OpTypeVector %uint 3\n"
371 "%ptr_uint_input = OpTypePointer Input %uint\n"
372 "%ptr_v3uint_input = OpTypePointer Input %v3uint\n"
373 "%int_runtime_array = OpTypeRuntimeArray %int\n"
374 "%struct_type = OpTypeStruct %int_runtime_array\n"
375 "%25 = OpTypePointer Uniform %struct_type\n"
376 "%ptr_uniform_int = OpTypePointer Uniform %int\n"
377
378 "%int_0 = OpConstant %int 0\n"
379 "%uint_0 = OpConstant %uint 0\n"
380 "%uint_1 = OpConstant %uint 1\n"
381 "%uint_2 = OpConstant %uint 2\n"
382 "%uint_3 = OpConstant %uint 3\n"
383 "%uint_6 = OpConstant %uint 6\n"
384 "%uint_12 = OpConstant %uint 12\n"
385 "%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_3 %uint_2 %uint_1\n"
386
387 "%gl_LocalInvocationIndex = OpVariable %ptr_uint_input Input\n"
388 "%gl_NumWorkGroups = OpVariable %ptr_v3uint_input Input\n"
389 "%gl_LocalInvocationId = OpVariable %ptr_v3uint_input Input\n"
390 "%var_BufferA = OpVariable %25 Uniform\n"
391 "%var_BufferB = OpVariable %25 Uniform\n"
392
393 "%mainA = OpFunction %void None %void_fun\n"
394 "%labelA = OpLabel\n"
395 "%idxA = OpLoad %uint %gl_LocalInvocationIndex\n"
396 "%inA1_location = OpAccessChain %ptr_uniform_int %var_BufferA %int_0 %idxA\n"
397 "%inA1 = OpLoad %int %inA1_location\n"
398 "%inA2_index = OpIAdd %uint %uint_6 %idxA\n"
399 "%inA2_location = OpAccessChain %ptr_uniform_int %var_BufferA %int_0 %inA2_index\n"
400 "%inA2 = OpLoad %int %inA2_location\n"
401 "%outA_index = OpIAdd %uint %uint_12 %idxA\n"
402 "%add_result = OpIAdd %int %inA1 %inA2\n"
403 "%outA_location = OpAccessChain %ptr_uniform_int %var_BufferA %int_0 %outA_index\n"
404 "OpStore %outA_location %add_result\n"
405 "OpReturn\n"
406 "OpFunctionEnd\n"
407
408 "%mainB = OpFunction %void None %void_fun\n"
409 "%labelB = OpLabel\n"
410
411 "%local_x_location = OpAccessChain %ptr_uint_input %gl_LocalInvocationId %uint_0\n"
412 "%local_x = OpLoad %uint %local_x_location\n"
413 "%local_x_times_2 = OpIMul %uint %local_x %uint_2\n"
414 "%local_y_location = OpAccessChain %ptr_uint_input %gl_LocalInvocationId %uint_1\n"
415 "%local_y = OpLoad %uint %local_y_location\n"
416 "%idxOut = OpIAdd %int %local_x_times_2 %local_y\n"
417
418 "%group_count_location = OpAccessChain %ptr_uint_input %gl_NumWorkGroups %uint_0\n"
419 "%group_count = OpLoad %uint %group_count_location\n"
420 "%sub_result = OpISub %int %uint_6 %group_count\n"
421 "%idxIn = OpISub %int %sub_result %idxOut\n"
422
423 "%inB1_location = OpAccessChain %ptr_uniform_int %var_BufferB %int_0 %idxIn\n"
424 "%inB1 = OpLoad %int %inB1_location\n"
425 "%inB2_index = OpIAdd %uint %uint_6 %idxIn\n"
426 "%inB2_location = OpAccessChain %ptr_uniform_int %var_BufferB %int_0 %inB2_index\n"
427 "%inB2 = OpLoad %int %inB2_location\n"
428 "%outB_index = OpIAdd %uint %uint_12 %idxOut\n"
429 "%mul_result = OpIMul %int %inB1 %inB2\n"
430 "%outB_location = OpAccessChain %ptr_uniform_int %var_BufferB %int_0 %outB_index\n"
431 "OpStore %outB_location %mul_result\n"
432
433 "OpReturn\n"
434 "OpFunctionEnd\n";
435
436 dst.spirvAsmSources.add("comp") << compSrc;
437 }
438 }
439 };
440
checkSupport(vkt::Context & context,TestConfig testConfig)441 void checkSupport(vkt::Context &context, TestConfig testConfig)
442 {
443 if (testConfig.type == TestType::TWO_ENTRY_POINTS_EXECUTION_MODE_ID)
444 context.requireDeviceFunctionality("VK_KHR_maintenance4");
445 }
446
447 } // namespace
448
createMultipleShaderExtendedGroup(tcu::TestContext & testCtx)449 tcu::TestCaseGroup *createMultipleShaderExtendedGroup(tcu::TestContext &testCtx)
450 {
451 typedef InstanceFactory1WithSupport<EntryPointsTest, TestConfig, FunctionSupport1<TestConfig>, Programs>
452 EntryPointsTestCase;
453 de::MovePtr<tcu::TestCaseGroup> mainGroup(new tcu::TestCaseGroup(testCtx, "multiple_shaders_extended"));
454
455 TestConfig testConfig = {TestType::TWO_ENTRY_POINTS_EXECUTION_MODE_ID};
456 mainGroup->addChild(new EntryPointsTestCase(testCtx, "two_entry_points_execution_mode_id", testConfig,
457 typename FunctionSupport1<TestConfig>::Args(checkSupport, testConfig)));
458 testConfig = {TestType::TWO_ENTRY_POINTS_DIFFERENT_INTERFACES};
459 mainGroup->addChild(new EntryPointsTestCase(testCtx, "two_entry_points_different_interfaces", testConfig,
460 typename FunctionSupport1<TestConfig>::Args(checkSupport, testConfig)));
461
462 return mainGroup.release();
463 }
464
465 } // namespace SpirVAssembly
466 } // namespace vkt
467