1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2021 The Khronos Group Inc.
6 * Copyright (c) 2021 Valve Corporation.
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 Pipeline Bind Point Tests
23 *//*--------------------------------------------------------------------*/
24 #include "vktPipelineBindPointTests.hpp"
25 #include "vktPipelineImageUtil.hpp"
26
27 #include "vkObjUtil.hpp"
28 #include "vkBuilderUtil.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "vkRayTracingUtil.hpp"
36
37 #include "tcuVector.hpp"
38
39 #include <algorithm>
40 #include <string>
41 #include <sstream>
42 #include <type_traits>
43 #include <utility>
44
45 namespace vkt
46 {
47 namespace pipeline
48 {
49
50 namespace
51 {
52
53 using namespace vk;
54
55 // These operations will be tried in different orders.
56 // To avoid combinatory explosions, we'll only use two pipeline types per test, which means 2 pipeline bind operations and 2 related set bind operations.
57 // The following types will be mixed: (graphics, compute), (graphics, ray tracing) and (compute, ray tracing).
58 enum class SetupOp
59 {
60 BIND_GRAPHICS_PIPELINE = 0,
61 BIND_COMPUTE_PIPELINE = 1,
62 BIND_RAYTRACING_PIPELINE = 2,
63 BIND_GRAPHICS_SET = 3,
64 BIND_COMPUTE_SET = 4,
65 BIND_RAYTRACING_SET = 5,
66 OP_COUNT = 6,
67 };
68
69 // How to bind each set.
70 enum class SetUpdateType
71 {
72 WRITE = 0,
73 PUSH = 1,
74 PUSH_WITH_TEMPLATE = 2,
75 TYPE_COUNT = 3,
76 };
77
78 // Types of operations to dispatch. They will be tried in different orders and are related to the setup sequence.
79 enum class DispatchOp
80 {
81 DRAW = 0,
82 COMPUTE = 1,
83 TRACE_RAYS = 2,
84 OP_COUNT = 3,
85 };
86
87 constexpr auto kTestBindPoints = 2; // Two bind points per test.
88 constexpr auto kSetupSequenceSize = kTestBindPoints * 2; // For each bind point: bind pipeline and bind set.
89 constexpr auto kDispatchSequenceSize = kTestBindPoints; // Dispatch two types of work, matching the bind points being used.
90
91 using SetupSequence = tcu::Vector<SetupOp, kSetupSequenceSize>;
92 using DispatchSequence = tcu::Vector<DispatchOp, kDispatchSequenceSize>;
93
94 // Test parameters.
95 struct TestParams
96 {
97 PipelineConstructionType pipelineConstructionType;
98 SetUpdateType graphicsSetUpdateType;
99 SetUpdateType computeSetUpdateType;
100 SetUpdateType rayTracingSetUpdateType;
101 SetupSequence setupSequence;
102 DispatchSequence dispatchSequence;
103
104 protected:
hasSetupOpvkt::pipeline::__anon29380::TestParams105 bool hasSetupOp (SetupOp op) const
106 {
107 for (int i = 0; i < decltype(setupSequence)::SIZE; ++i)
108 {
109 if (setupSequence[i] == op)
110 return true;
111 }
112 return false;
113 }
114
hasAnyOfvkt::pipeline::__anon29380::TestParams115 bool hasAnyOf (const std::vector<SetupOp>& opVec) const
116 {
117 for (const auto& op : opVec)
118 {
119 if (hasSetupOp(op))
120 return true;
121 }
122 return false;
123 }
124
125 public:
hasGraphicsvkt::pipeline::__anon29380::TestParams126 bool hasGraphics (void) const
127 {
128 const std::vector<SetupOp> setupOps {SetupOp::BIND_GRAPHICS_PIPELINE, SetupOp::BIND_GRAPHICS_SET};
129 return hasAnyOf(setupOps);
130 }
131
hasComputevkt::pipeline::__anon29380::TestParams132 bool hasCompute (void) const
133 {
134 const std::vector<SetupOp> setupOps {SetupOp::BIND_COMPUTE_PIPELINE, SetupOp::BIND_COMPUTE_SET};
135 return hasAnyOf(setupOps);
136 }
137
hasRayTracingvkt::pipeline::__anon29380::TestParams138 bool hasRayTracing (void) const
139 {
140 const std::vector<SetupOp> setupOps {SetupOp::BIND_RAYTRACING_PIPELINE, SetupOp::BIND_RAYTRACING_SET};
141 return hasAnyOf(setupOps);
142 }
143
144 };
145
146 // Expected output values in each buffer.
147 constexpr deUint32 kExpectedBufferValueGraphics = 1u;
148 constexpr deUint32 kExpectedBufferValueCompute = 2u;
149 constexpr deUint32 kExpectedBufferValueRayTracing = 3u;
150
151 class BindPointTest : public vkt::TestCase
152 {
153 public:
154 BindPointTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
~BindPointTest(void)155 virtual ~BindPointTest (void) {}
156
157 virtual void checkSupport (Context& context) const;
158 virtual void initPrograms (vk::SourceCollections& programCollection) const;
159 virtual TestInstance* createInstance (Context& context) const;
160
161 protected:
162 TestParams m_params;
163 };
164
165 class BindPointInstance : public vkt::TestInstance
166 {
167 public:
168 BindPointInstance (Context& context, const TestParams& params);
~BindPointInstance(void)169 virtual ~BindPointInstance (void) {}
170
171 virtual tcu::TestStatus iterate (void);
172
173 protected:
174 TestParams m_params;
175 };
176
BindPointTest(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)177 BindPointTest::BindPointTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
178 : vkt::TestCase (testCtx, name, description)
179 , m_params (params)
180 {}
181
checkSupport(Context& context) const182 void BindPointTest::checkSupport (Context& context) const
183 {
184 if ((m_params.hasGraphics() && m_params.graphicsSetUpdateType != SetUpdateType::WRITE) ||
185 (m_params.hasCompute() && m_params.computeSetUpdateType != SetUpdateType::WRITE) ||
186 (m_params.hasRayTracing() && m_params.rayTracingSetUpdateType != SetUpdateType::WRITE))
187 {
188 context.requireDeviceFunctionality("VK_KHR_push_descriptor");
189
190 if ((m_params.hasGraphics() && m_params.graphicsSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) ||
191 (m_params.hasCompute() && m_params.computeSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) ||
192 (m_params.hasRayTracing() && m_params.rayTracingSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE))
193 {
194 context.requireDeviceFunctionality("VK_KHR_descriptor_update_template");
195 }
196 }
197
198 if (m_params.hasRayTracing())
199 context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
200
201 checkPipelineLibraryRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_params.pipelineConstructionType);
202 }
203
initPrograms(vk::SourceCollections& programCollection) const204 void BindPointTest::initPrograms (vk::SourceCollections& programCollection) const
205 {
206 // The flags array will only have 1 element.
207 const std::string descriptorDecl = "layout(set=0, binding=0, std430) buffer BufferBlock { uint flag[]; } outBuffer;\n";
208
209 if (m_params.hasGraphics())
210 {
211 std::ostringstream vert;
212 vert
213 << "#version 450\n"
214 << "\n"
215 << "void main()\n"
216 << "{\n"
217 // Full-screen clockwise triangle strip with 4 vertices.
218 << " const float x = (-1.0+2.0*((gl_VertexIndex & 2)>>1));\n"
219 << " const float y = ( 1.0-2.0* (gl_VertexIndex % 2));\n"
220 << " gl_Position = vec4(x, y, 0.0, 1.0);\n"
221 << "}\n"
222 ;
223
224 // Note: the color attachment will be a 1x1 image, so gl_FragCoord.xy is (0.5, 0.5).
225 std::ostringstream frag;
226 frag
227 << "#version 450\n"
228 << descriptorDecl
229 << "layout(location=0) out vec4 outColor;\n"
230 << "\n"
231 << "void main()\n"
232 << "{\n"
233 << " const uint xCoord = uint(trunc(gl_FragCoord.x));\n"
234 << " const uint yCoord = uint(trunc(gl_FragCoord.y));\n"
235 << " outBuffer.flag[xCoord + yCoord] = " << kExpectedBufferValueGraphics << "u;\n"
236 << " outColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
237 << "}\n"
238 ;
239
240 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
241 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
242 }
243
244 if (m_params.hasCompute())
245 {
246 // Note: we will only dispatch 1 group.
247 std::ostringstream comp;
248 comp
249 << "#version 450\n"
250 << descriptorDecl
251 << "layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
252 << "\n"
253 << "void main()\n"
254 << "{\n"
255 << " const uint index = gl_GlobalInvocationID.x + gl_GlobalInvocationID.y + gl_GlobalInvocationID.z;\n"
256 << " outBuffer.flag[index] = " << kExpectedBufferValueCompute << "u;\n"
257 << "}\n"
258 ;
259
260 programCollection.glslSources.add("comp") << glu::ComputeSource(comp.str());
261 }
262
263 if (m_params.hasRayTracing())
264 {
265 // We will only call the ray gen shader once.
266 std::ostringstream rgen;
267 rgen
268 << "#version 460\n"
269 << "#extension GL_EXT_ray_tracing : require\n"
270 << descriptorDecl
271 << "\n"
272 << "void main()\n"
273 << "{\n"
274 << " const uint index = gl_LaunchIDEXT.x + gl_LaunchIDEXT.y + gl_LaunchIDEXT.z;\n"
275 << " outBuffer.flag[index] = " << kExpectedBufferValueRayTracing << "u;\n"
276 << "}\n"
277 ;
278
279 const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
280 programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions;
281 }
282 }
283
createInstance(Context& context) const284 vkt::TestInstance* BindPointTest::createInstance (Context& context) const
285 {
286 return new BindPointInstance(context, m_params);
287 }
288
BindPointInstance(Context& context, const TestParams& params)289 BindPointInstance::BindPointInstance (Context& context, const TestParams& params)
290 : vkt::TestInstance (context)
291 , m_params (params)
292 {}
293
makeSetLayout(const DeviceInterface& vkd, VkDevice device, VkShaderStageFlags stages, bool push)294 Move<VkDescriptorSetLayout> makeSetLayout(const DeviceInterface& vkd, VkDevice device, VkShaderStageFlags stages, bool push)
295 {
296 VkDescriptorSetLayoutCreateFlags createFlags = 0u;
297 if (push)
298 createFlags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
299
300 DescriptorSetLayoutBuilder builder;
301 builder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages);
302 return builder.build(vkd, device, createFlags);
303 }
304
zeroOutAndFlush(const DeviceInterface& vkd, VkDevice device, BufferWithMemory& buffer, VkDeviceSize bufferSize)305 void zeroOutAndFlush (const DeviceInterface& vkd, VkDevice device, BufferWithMemory& buffer, VkDeviceSize bufferSize)
306 {
307 auto& alloc = buffer.getAllocation();
308 void* hostPtr = alloc.getHostPtr();
309
310 deMemset(hostPtr, 0, static_cast<size_t>(bufferSize));
311 flushAlloc(vkd, device, alloc);
312 }
313
makePoolAndSet(const DeviceInterface& vkd, VkDevice device, VkDescriptorSetLayout layout, Move<VkDescriptorPool>& pool, Move<VkDescriptorSet>& set)314 void makePoolAndSet (const DeviceInterface& vkd, VkDevice device, VkDescriptorSetLayout layout, Move<VkDescriptorPool>& pool, Move<VkDescriptorSet>& set)
315 {
316 DescriptorPoolBuilder poolBuilder;
317 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
318 pool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
319 set = makeDescriptorSet(vkd, device, pool.get(), layout);
320 }
321
writeSetUpdate(const DeviceInterface& vkd, VkDevice device, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size, VkDescriptorSet set)322 void writeSetUpdate (const DeviceInterface& vkd, VkDevice device, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size, VkDescriptorSet set)
323 {
324 DescriptorSetUpdateBuilder updateBuilder;
325 const auto bufferInfo = makeDescriptorBufferInfo(buffer, offset, size);
326 updateBuilder.writeSingle(set, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferInfo);
327 updateBuilder.update(vkd, device);
328 }
329
makeUpdateTemplate(const DeviceInterface& vkd, VkDevice device, VkDescriptorSetLayout setLayout, VkPipelineBindPoint bindPoint, VkPipelineLayout pipelineLayout)330 Move<VkDescriptorUpdateTemplate> makeUpdateTemplate (const DeviceInterface& vkd, VkDevice device, VkDescriptorSetLayout setLayout, VkPipelineBindPoint bindPoint, VkPipelineLayout pipelineLayout)
331 {
332 const auto templateEntry = makeDescriptorUpdateTemplateEntry(0u, 0u, 1u, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, static_cast<deUintptr>(0), static_cast<deUintptr>(sizeof(VkDescriptorBufferInfo)));
333 const VkDescriptorUpdateTemplateCreateInfo templateCreateInfo =
334 {
335 VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, // VkStructureType sType;
336 nullptr, // const void* pNext;
337 0u, // VkDescriptorUpdateTemplateCreateFlags flags;
338 1u, // deUint32 descriptorUpdateEntryCount;
339 &templateEntry, // const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries;
340 VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR, // VkDescriptorUpdateTemplateType templateType;
341 setLayout, // VkDescriptorSetLayout descriptorSetLayout;
342 bindPoint, // VkPipelineBindPoint pipelineBindPoint;
343 pipelineLayout, // VkPipelineLayout pipelineLayout;
344 0u, // deUint32 set;
345 };
346 return createDescriptorUpdateTemplate(vkd, device, &templateCreateInfo);
347 }
348
pushBufferDescriptor(const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, VkPipelineBindPoint bindPoint, VkPipelineLayout layout, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size)349 void pushBufferDescriptor(const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, VkPipelineBindPoint bindPoint, VkPipelineLayout layout, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size)
350 {
351 const auto bufferInfo = makeDescriptorBufferInfo(buffer, offset, size);
352 const VkWriteDescriptorSet write =
353 {
354 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType;
355 nullptr, // const void* pNext;
356 DE_NULL, // VkDescriptorSet dstSet;
357 0u, // deUint32 dstBinding;
358 0u, // deUint32 dstArrayElement;
359 1u, // deUint32 descriptorCount;
360 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, // VkDescriptorType descriptorType;
361 nullptr, // const VkDescriptorImageInfo* pImageInfo;
362 &bufferInfo, // const VkDescriptorBufferInfo* pBufferInfo;
363 nullptr, // const VkBufferView* pTexelBufferView;
364 };
365 vkd.cmdPushDescriptorSetKHR(cmdBuffer, bindPoint, layout, 0u, 1u, &write);
366 }
367
verifyBufferContents(const DeviceInterface& vkd, VkDevice device, const BufferWithMemory& buffer, const std::string& bufferName, deUint32 expected)368 void verifyBufferContents (const DeviceInterface& vkd, VkDevice device, const BufferWithMemory& buffer, const std::string& bufferName, deUint32 expected)
369 {
370 auto& bufferAlloc = buffer.getAllocation();
371 const auto dataPtr = reinterpret_cast<deUint32*>(bufferAlloc.getHostPtr());
372 deUint32 data;
373
374 invalidateAlloc(vkd, device, bufferAlloc);
375 deMemcpy(&data, dataPtr, sizeof(data));
376
377 if (data != expected)
378 {
379 std::ostringstream msg;
380 msg << "Invalid value found in " << bufferName << " buffer: expected " << expected << " and found " << data;
381 TCU_FAIL(msg.str());
382 }
383 }
384
makeBufferBarrier(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size)385 VkBufferMemoryBarrier makeBufferBarrier (VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size)
386 {
387 return makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, buffer, offset, size);
388 }
389
recordBufferBarrier(const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, VkPipelineStageFlagBits stage, const VkBufferMemoryBarrier& barrier)390 void recordBufferBarrier (const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, VkPipelineStageFlagBits stage, const VkBufferMemoryBarrier& barrier)
391 {
392 vkd.cmdPipelineBarrier(cmdBuffer, stage, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, nullptr, 1u, &barrier, 0u, nullptr);
393 }
394
iterate(void)395 tcu::TestStatus BindPointInstance::iterate (void)
396 {
397 const auto& vki = m_context.getInstanceInterface();
398 const auto physDev = m_context.getPhysicalDevice();
399 const auto& vkd = m_context.getDeviceInterface();
400 const auto device = m_context.getDevice();
401 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
402 const auto queue = m_context.getUniversalQueue();
403 auto& alloc = m_context.getDefaultAllocator();
404
405 const auto imageFormat = VK_FORMAT_R8G8B8A8_UNORM;
406 const auto imageExtent = makeExtent3D(1u, 1u, 1u);
407 const auto imageType = VK_IMAGE_TYPE_2D;
408 const auto imageViewType = VK_IMAGE_VIEW_TYPE_2D;
409 const auto imageUsage = static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
410
411 const std::vector<VkViewport> viewports { makeViewport(imageExtent) };
412 const std::vector<VkRect2D> scissors { makeRect2D(imageExtent) };
413
414 const auto hasGraphics = m_params.hasGraphics();
415 const auto hasCompute = m_params.hasCompute();
416 const auto hasRayTracing = m_params.hasRayTracing();
417
418 // Storage buffers.
419 const auto bufferSize = static_cast<VkDeviceSize>(sizeof(deUint32));
420 const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
421
422 using BufferWithMemoryPtr = de::MovePtr<BufferWithMemory>;
423 using ImageWithMemoryPtr = de::MovePtr<ImageWithMemory>;
424
425 BufferWithMemoryPtr graphicsBuffer;
426 BufferWithMemoryPtr computeBuffer;
427 BufferWithMemoryPtr rayTracingBuffer;
428
429 if (hasGraphics) graphicsBuffer = BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
430 if (hasCompute) computeBuffer = BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
431 if (hasRayTracing) rayTracingBuffer = BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
432
433 if (hasGraphics) zeroOutAndFlush(vkd, device, *graphicsBuffer, bufferSize);
434 if (hasCompute) zeroOutAndFlush(vkd, device, *computeBuffer, bufferSize);
435 if (hasRayTracing) zeroOutAndFlush(vkd, device, *rayTracingBuffer, bufferSize);
436
437 ImageWithMemoryPtr colorAttachment;
438 Move<VkImageView> colorAttachmentView;
439
440 if (hasGraphics)
441 {
442 // Color attachment.
443 const VkImageCreateInfo imageCreateInfo =
444 {
445 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
446 nullptr, // const void* pNext;
447 0u, // VkImageCreateFlags flags;
448 imageType, // VkImageType imageType;
449 imageFormat, // VkFormat format;
450 imageExtent, // VkExtent3D extent;
451 1u, // deUint32 mipLevels;
452 1u, // deUint32 arrayLayers;
453 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
454 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
455 imageUsage, // VkImageUsageFlags usage;
456 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
457 1u, // deUint32 queueFamilyIndexCount;
458 &qIndex, // const deUint32* pQueueFamilyIndices;
459 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
460 };
461
462 const auto subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
463 colorAttachment = ImageWithMemoryPtr(new ImageWithMemory(vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any));
464 colorAttachmentView = makeImageView(vkd, device, colorAttachment->get(), imageViewType, imageFormat, subresourceRange);
465 }
466
467 // Command buffer and pool.
468 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
469 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
470 const auto cmdBuffer = cmdBufferPtr.get();
471
472 // Set and pipeline layouts.
473 Move<VkDescriptorSetLayout> graphicsSetLayout;
474 Move<VkDescriptorSetLayout> computeSetLayout;
475 Move<VkDescriptorSetLayout> rayTracingSetLayout;
476
477 if (hasGraphics) graphicsSetLayout = makeSetLayout(vkd, device, VK_SHADER_STAGE_FRAGMENT_BIT, (m_params.graphicsSetUpdateType != SetUpdateType::WRITE));
478 if (hasCompute) computeSetLayout = makeSetLayout(vkd, device, VK_SHADER_STAGE_COMPUTE_BIT, (m_params.computeSetUpdateType != SetUpdateType::WRITE));
479 if (hasRayTracing) rayTracingSetLayout = makeSetLayout(vkd, device, VK_SHADER_STAGE_RAYGEN_BIT_KHR, (m_params.rayTracingSetUpdateType != SetUpdateType::WRITE));
480
481 Move<VkPipelineLayout> graphicsPipelineLayout;
482 Move<VkPipelineLayout> computePipelineLayout;
483 Move<VkPipelineLayout> rayTracingPipelineLayout;
484
485 if (hasGraphics) graphicsPipelineLayout = makePipelineLayout(vkd, device, graphicsSetLayout.get());
486 if (hasCompute) computePipelineLayout = makePipelineLayout(vkd, device, computeSetLayout.get());
487 if (hasRayTracing) rayTracingPipelineLayout = makePipelineLayout(vkd, device, rayTracingSetLayout.get());
488
489 // Shader modules.
490 Move<VkShaderModule> vertShader;
491 Move<VkShaderModule> fragShader;
492 Move<VkShaderModule> compShader;
493 Move<VkShaderModule> rgenShader;
494
495 if (hasGraphics) vertShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
496 if (hasGraphics) fragShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
497 if (hasCompute) compShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0u);
498 if (hasRayTracing) rgenShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("rgen"), 0u);
499
500 Move<VkRenderPass> renderPass;
501 Move<VkFramebuffer> framebuffer;
502 GraphicsPipelineWrapper graphicsPipeline(vkd, device, m_params.pipelineConstructionType);
503
504 if (hasGraphics)
505 {
506 // Render pass and framebuffer.
507 renderPass = makeRenderPass(vkd, device, imageFormat);
508 framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorAttachmentView.get(), imageExtent.width, imageExtent.height);
509
510 // Graphics pipeline.
511 const VkPipelineVertexInputStateCreateInfo vertexInputState =
512 {
513 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType
514 nullptr, // const void* pNext
515 0u, // VkPipelineVertexInputStateCreateFlags flags
516 0u, // deUint32 vertexBindingDescriptionCount
517 nullptr, // const VkVertexInputBindingDescription* pVertexBindingDescriptions
518 0u, // deUint32 vertexAttributeDescriptionCount
519 nullptr, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions
520 };
521
522 graphicsPipeline.setDefaultTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
523 .setDefaultRasterizationState()
524 .setDefaultMultisampleState()
525 .setDefaultDepthStencilState()
526 .setDefaultColorBlendState()
527 .setupVertexInputState(&vertexInputState)
528 .setupPreRasterizationShaderState(
529 viewports,
530 scissors,
531 *graphicsPipelineLayout,
532 *renderPass,
533 0u,
534 *vertShader)
535 .setupFragmentShaderState(*graphicsPipelineLayout, *renderPass, 0u, *fragShader)
536 .setupFragmentOutputState(*renderPass, 0u)
537 .setMonolithicPipelineLayout(*graphicsPipelineLayout)
538 .buildPipeline();
539 }
540
541 // Compute pipeline.
542 Move<VkPipeline> computePipeline;
543
544 if (hasCompute)
545 {
546 const VkPipelineShaderStageCreateInfo computeShaderStageInfo =
547 {
548 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
549 nullptr, // const void* pNext;
550 0u, // VkPipelineShaderStageCreateFlags flags;
551 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
552 compShader.get(), // VkShaderModule module;
553 "main", // const char* pName;
554 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
555 };
556
557 const VkComputePipelineCreateInfo computePipelineCreateInfo =
558 {
559 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
560 nullptr, // const void* pNext;
561 0u, // VkPipelineCreateFlags flags;
562 computeShaderStageInfo, // VkPipelineShaderStageCreateInfo stage;
563 computePipelineLayout.get(), // VkPipelineLayout layout;
564 DE_NULL, // VkPipeline basePipelineHandle;
565 0u, // deInt32 basePipelineIndex;
566 };
567
568 computePipeline = createComputePipeline(vkd, device, DE_NULL, &computePipelineCreateInfo);
569 }
570
571 // Ray tracing pipeline and shader binding tables.
572 using RayTracingPipelineHelperPtr = de::MovePtr<RayTracingPipeline>;
573
574 RayTracingPipelineHelperPtr rayTracingPipelineHelper;
575 Move<VkPipeline> rayTracingPipeline;
576 BufferWithMemoryPtr raygenSBT;
577
578 VkStridedDeviceAddressRegionKHR raygenSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
579 VkStridedDeviceAddressRegionKHR missSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
580 VkStridedDeviceAddressRegionKHR hitSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
581 VkStridedDeviceAddressRegionKHR callableSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
582
583 if (hasRayTracing)
584 {
585 const auto rtProperties = makeRayTracingProperties(vki, physDev);
586 const auto shaderGroupHandleSize = rtProperties->getShaderGroupHandleSize();
587 const auto shaderGroupBaseAlignment = rtProperties->getShaderGroupBaseAlignment();
588 rayTracingPipelineHelper = RayTracingPipelineHelperPtr(new RayTracingPipeline());
589
590 rayTracingPipelineHelper->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenShader, 0);
591 rayTracingPipeline = rayTracingPipelineHelper->createPipeline(vkd, device, rayTracingPipelineLayout.get());
592
593 raygenSBT = rayTracingPipelineHelper->createShaderBindingTable(vkd, device, rayTracingPipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
594 raygenSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
595 }
596
597 // Descriptor pools and sets if needed.
598 Move<VkDescriptorPool> graphicsDescriptorPool;
599 Move<VkDescriptorPool> computeDescriptorPool;
600 Move<VkDescriptorPool> rayTracingDescriptorPool;
601 Move<VkDescriptorSet> graphicsDescritorSet;
602 Move<VkDescriptorSet> computeDescriptorSet;
603 Move<VkDescriptorSet> rayTracingDescriptorSet;
604
605 if (m_params.graphicsSetUpdateType == SetUpdateType::WRITE)
606 {
607 makePoolAndSet(vkd, device, graphicsSetLayout.get(), graphicsDescriptorPool, graphicsDescritorSet);
608 writeSetUpdate(vkd, device, graphicsBuffer->get(), 0ull, bufferSize, graphicsDescritorSet.get());
609 }
610
611 if (m_params.computeSetUpdateType == SetUpdateType::WRITE)
612 {
613 makePoolAndSet(vkd, device, computeSetLayout.get(), computeDescriptorPool, computeDescriptorSet);
614 writeSetUpdate(vkd, device, computeBuffer->get(), 0ull, bufferSize, computeDescriptorSet.get());
615 }
616
617 if (m_params.rayTracingSetUpdateType == SetUpdateType::WRITE)
618 {
619 makePoolAndSet(vkd, device, rayTracingSetLayout.get(), rayTracingDescriptorPool, rayTracingDescriptorSet);
620 writeSetUpdate(vkd, device, rayTracingBuffer->get(), 0ull, bufferSize, rayTracingDescriptorSet.get());
621 }
622
623 // Templates if needed.
624 Move<VkDescriptorUpdateTemplate> graphicsUpdateTemplate;
625 Move<VkDescriptorUpdateTemplate> computeUpdateTemplate;
626 Move<VkDescriptorUpdateTemplate> rayTracingUpdateTemplate;
627
628 if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
629 graphicsUpdateTemplate = makeUpdateTemplate(vkd, device, graphicsSetLayout.get(), VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout.get());
630
631 if (m_params.computeSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
632 computeUpdateTemplate = makeUpdateTemplate(vkd, device, computeSetLayout.get(), VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout.get());
633
634 if (m_params.rayTracingSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
635 rayTracingUpdateTemplate = makeUpdateTemplate(vkd, device, rayTracingSetLayout.get(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipelineLayout.get());
636
637 beginCommandBuffer(vkd, cmdBuffer);
638
639 // Helper flags to check the test has been specified properly.
640 bool boundGraphicsPipeline = false;
641 bool boundGraphicsSet = false;
642 bool boundComputePipeline = false;
643 bool boundComputeSet = false;
644 bool boundRayTracingPipeline = false;
645 bool boundRayTracingSet = false;
646
647 // Setup operations in desired order.
648 for (int i = 0; i < decltype(m_params.setupSequence)::SIZE; ++i)
649 {
650 const auto& setupOp = m_params.setupSequence[i];
651 switch (setupOp)
652 {
653 case SetupOp::BIND_GRAPHICS_PIPELINE:
654 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.getPipeline());
655 boundGraphicsPipeline = true;
656 break;
657
658 case SetupOp::BIND_COMPUTE_PIPELINE:
659 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.get());
660 boundComputePipeline = true;
661 break;
662
663 case SetupOp::BIND_RAYTRACING_PIPELINE:
664 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipeline.get());
665 boundRayTracingPipeline = true;
666 break;
667
668 case SetupOp::BIND_GRAPHICS_SET:
669 if (m_params.graphicsSetUpdateType == SetUpdateType::WRITE)
670 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout.get(), 0u, 1u, &graphicsDescritorSet.get(), 0u, nullptr);
671 else if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH)
672 pushBufferDescriptor(vkd, cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout.get(), graphicsBuffer->get(), 0ull, bufferSize);
673 else if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
674 {
675 const auto bufferInfo = makeDescriptorBufferInfo(graphicsBuffer->get(), 0ull, bufferSize);
676 vkd.cmdPushDescriptorSetWithTemplateKHR(cmdBuffer, graphicsUpdateTemplate.get(), graphicsPipelineLayout.get(), 0u, &bufferInfo);
677 }
678 else
679 DE_ASSERT(false);
680 boundGraphicsSet = true;
681 break;
682
683 case SetupOp::BIND_COMPUTE_SET:
684 if (m_params.computeSetUpdateType == SetUpdateType::WRITE)
685 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout.get(), 0u, 1u, &computeDescriptorSet.get(), 0u, nullptr);
686 else if (m_params.computeSetUpdateType == SetUpdateType::PUSH)
687 pushBufferDescriptor(vkd, cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout.get(), computeBuffer->get(), 0ull, bufferSize);
688 else if (m_params.computeSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
689 {
690 const auto bufferInfo = makeDescriptorBufferInfo(computeBuffer->get(), 0ull, bufferSize);
691 vkd.cmdPushDescriptorSetWithTemplateKHR(cmdBuffer, computeUpdateTemplate.get(), computePipelineLayout.get(), 0u, &bufferInfo);
692 }
693 else
694 DE_ASSERT(false);
695 boundComputeSet = true;
696 break;
697
698 case SetupOp::BIND_RAYTRACING_SET:
699 if (m_params.rayTracingSetUpdateType == SetUpdateType::WRITE)
700 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipelineLayout.get(), 0u, 1u, &rayTracingDescriptorSet.get(), 0u, nullptr);
701 else if (m_params.rayTracingSetUpdateType == SetUpdateType::PUSH)
702 pushBufferDescriptor(vkd, cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipelineLayout.get(), rayTracingBuffer->get(), 0ull, bufferSize);
703 else if (m_params.rayTracingSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
704 {
705 const auto bufferInfo = makeDescriptorBufferInfo(rayTracingBuffer->get(), 0ull, bufferSize);
706 vkd.cmdPushDescriptorSetWithTemplateKHR(cmdBuffer, rayTracingUpdateTemplate.get(), rayTracingPipelineLayout.get(), 0u, &bufferInfo);
707 }
708 else
709 DE_ASSERT(false);
710 boundRayTracingSet = true;
711 break;
712
713 default:
714 DE_ASSERT(false);
715 break;
716 }
717 }
718
719 // Avoid warning in release builds.
720 DE_UNREF(boundGraphicsPipeline);
721 DE_UNREF(boundGraphicsSet);
722 DE_UNREF(boundComputePipeline);
723 DE_UNREF(boundComputeSet);
724 DE_UNREF(boundRayTracingPipeline);
725 DE_UNREF(boundRayTracingSet);
726
727 // Dispatch operations in desired order.
728 for (int i = 0; i < decltype(m_params.dispatchSequence)::SIZE; ++i)
729 {
730 const auto& dispatchOp = m_params.dispatchSequence[i];
731 switch (dispatchOp)
732 {
733 case DispatchOp::DRAW:
734 DE_ASSERT(boundGraphicsPipeline && boundGraphicsSet);
735 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors[0], tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
736 vkd.cmdDraw(cmdBuffer, 4u, 1u, 0u, 0u);
737 endRenderPass(vkd, cmdBuffer);
738 break;
739
740 case DispatchOp::COMPUTE:
741 DE_ASSERT(boundComputePipeline && boundComputeSet);
742 vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
743 break;
744
745 case DispatchOp::TRACE_RAYS:
746 DE_ASSERT(boundRayTracingPipeline && boundRayTracingSet);
747 cmdTraceRays(vkd, cmdBuffer, &raygenSBTRegion, &missSBTRegion, &hitSBTRegion, &callableSBTRegion, 1u, 1u, 1u);
748 break;
749
750 default:
751 DE_ASSERT(false);
752 break;
753 }
754 }
755
756 if (hasGraphics)
757 {
758 const auto graphicsBufferBarrier = makeBufferBarrier(graphicsBuffer->get(), 0ull, bufferSize);
759 recordBufferBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, graphicsBufferBarrier);
760 }
761 if (hasCompute)
762 {
763 const auto computeBufferBarrier = makeBufferBarrier(computeBuffer->get(), 0ull, bufferSize);
764 recordBufferBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, computeBufferBarrier);
765 }
766 if (hasRayTracing)
767 {
768 const auto rayTracingBufferBarrier = makeBufferBarrier(rayTracingBuffer->get(), 0ull, bufferSize);
769 recordBufferBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, rayTracingBufferBarrier);
770 }
771
772 endCommandBuffer(vkd, cmdBuffer);
773 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
774
775 // Verify storage buffers.
776 if (hasGraphics) verifyBufferContents(vkd, device, *graphicsBuffer, "graphics", kExpectedBufferValueGraphics);
777 if (hasCompute) verifyBufferContents(vkd, device, *computeBuffer, "compute", kExpectedBufferValueCompute);
778 if (hasRayTracing) verifyBufferContents(vkd, device, *rayTracingBuffer, "raytracing", kExpectedBufferValueRayTracing);
779
780 // Verify color attachment.
781 if (hasGraphics)
782 {
783 const auto textureLevel = readColorAttachment(vkd, device, queue, qIndex, alloc, colorAttachment->get(), imageFormat, tcu::UVec2(imageExtent.width, imageExtent.height));
784 const auto pixelBuffer = textureLevel->getAccess();
785 const auto iWidth = static_cast<int>(imageExtent.width);
786 const auto iHeight = static_cast<int>(imageExtent.height);
787 const tcu::Vec4 expectedColor (0.0f, 1.0f, 0.0f, 1.0f);
788
789 for (int y = 0; y < iHeight; ++y)
790 for (int x = 0; x < iWidth; ++x)
791 {
792 const auto value = pixelBuffer.getPixel(x, y);
793 if (value != expectedColor)
794 {
795 std::ostringstream msg;
796 msg << "Unexpected color found in attachment: expected " << expectedColor << " but found " << value;
797 TCU_FAIL(msg.str());
798 }
799 }
800 }
801
802 return tcu::TestStatus::pass("Pass");
803 }
804
805 // Auxiliar string conversion functions.
806
toString(SetUpdateType updateType)807 std::string toString(SetUpdateType updateType)
808 {
809 switch (updateType)
810 {
811 case SetUpdateType::WRITE: return "write";
812 case SetUpdateType::PUSH: return "push";
813 case SetUpdateType::PUSH_WITH_TEMPLATE: return "template_push";
814 default: DE_ASSERT(false); break;
815 }
816
817 return "";
818 }
819
toString(const SetupSequence& setupSequence)820 std::string toString(const SetupSequence& setupSequence)
821 {
822 std::ostringstream out;
823
824 out << "setup";
825 for (int i = 0; i < std::remove_reference<decltype(setupSequence)>::type::SIZE; ++i)
826 {
827 out << "_";
828 switch (setupSequence[i])
829 {
830 case SetupOp::BIND_GRAPHICS_PIPELINE: out << "gp"; break;
831 case SetupOp::BIND_COMPUTE_PIPELINE: out << "cp"; break;
832 case SetupOp::BIND_RAYTRACING_PIPELINE: out << "rp"; break;
833 case SetupOp::BIND_GRAPHICS_SET: out << "gs"; break;
834 case SetupOp::BIND_COMPUTE_SET: out << "cs"; break;
835 case SetupOp::BIND_RAYTRACING_SET: out << "rs"; break;
836 default: DE_ASSERT(false); break;
837 }
838 }
839
840 return out.str();
841 }
842
toString(const DispatchSequence& dispatchSequence)843 std::string toString(const DispatchSequence& dispatchSequence)
844 {
845 std::ostringstream out;
846
847 out << "cmd";
848 for (int i = 0; i < std::remove_reference<decltype(dispatchSequence)>::type::SIZE; ++i)
849 {
850 out << "_";
851 switch (dispatchSequence[i])
852 {
853 case DispatchOp::COMPUTE: out << "dispatch"; break;
854 case DispatchOp::DRAW: out << "draw"; break;
855 case DispatchOp::TRACE_RAYS: out << "tracerays"; break;
856 default: DE_ASSERT(false); break;
857 }
858 }
859
860 return out.str();
861 }
862
toString(VkPipelineBindPoint point)863 std::string toString(VkPipelineBindPoint point)
864 {
865 if (point == VK_PIPELINE_BIND_POINT_GRAPHICS) return "graphics";
866 if (point == VK_PIPELINE_BIND_POINT_COMPUTE) return "compute";
867 if (point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) return "raytracing";
868
869 DE_ASSERT(false);
870 return "";
871 }
872
873 } // anonymous
874
createBindPointTests(tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)875 tcu::TestCaseGroup* createBindPointTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
876 {
877 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
878 using BindPointPair = tcu::Vector<VkPipelineBindPoint, kTestBindPoints>;
879
880 GroupPtr bindPointGroup(new tcu::TestCaseGroup(testCtx, "bind_point", "Tests checking bind points are independent and used properly"));
881
882 // Bind point combinations to test.
883 const BindPointPair testPairs[] =
884 {
885 BindPointPair(VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE),
886 BindPointPair(VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR),
887 BindPointPair(VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR),
888 };
889
890 for (int testPairIdx = 0; testPairIdx < DE_LENGTH_OF_ARRAY(testPairs); ++testPairIdx)
891 {
892 const auto& testPair = testPairs[testPairIdx];
893
894 // dont repeat tests if there is no graphics pipeline
895 if (pipelineConstructionType != PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
896 {
897 bool skipTests = true;
898 for (int elemIdx = 0; elemIdx < std::remove_reference<decltype(testPair)>::type::SIZE; ++elemIdx)
899 {
900 if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_GRAPHICS)
901 {
902 skipTests = false;
903 break;
904 }
905 }
906
907 if (skipTests)
908 continue;
909 }
910
911 // Default values. Two of them will be overwritten later.
912 TestParams params;
913 params.pipelineConstructionType = pipelineConstructionType;
914 params.graphicsSetUpdateType = SetUpdateType::TYPE_COUNT;
915 params.computeSetUpdateType = SetUpdateType::TYPE_COUNT;
916 params.rayTracingSetUpdateType = SetUpdateType::TYPE_COUNT;
917
918 // What to test based on the test pair.
919 // Note: updateTypePtrs will tell us which of the set update type members above we need to vary (graphics, compute, ray tracing).
920 SetUpdateType* updateTypePtrs [kTestBindPoints] = { nullptr, nullptr };
921 SetupOp pipelineBinds [kTestBindPoints] = { SetupOp::OP_COUNT, SetupOp::OP_COUNT };
922 SetupOp setBinds [kTestBindPoints] = { SetupOp::OP_COUNT, SetupOp::OP_COUNT };
923 DispatchOp dispatches [kTestBindPoints] = { DispatchOp::OP_COUNT, DispatchOp::OP_COUNT };
924
925 for (int elemIdx = 0; elemIdx < std::remove_reference<decltype(testPair)>::type::SIZE; ++elemIdx)
926 {
927 if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_GRAPHICS)
928 {
929 updateTypePtrs[elemIdx] = ¶ms.graphicsSetUpdateType; // Test different graphics set update types.
930 pipelineBinds[elemIdx] = SetupOp::BIND_GRAPHICS_PIPELINE;
931 setBinds[elemIdx] = SetupOp::BIND_GRAPHICS_SET;
932 dispatches[elemIdx] = DispatchOp::DRAW;
933 }
934 else if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_COMPUTE)
935 {
936 updateTypePtrs[elemIdx] = ¶ms.computeSetUpdateType; // Test different compute set update types.
937 pipelineBinds[elemIdx] = SetupOp::BIND_COMPUTE_PIPELINE;
938 setBinds[elemIdx] = SetupOp::BIND_COMPUTE_SET;
939 dispatches[elemIdx] = DispatchOp::COMPUTE;
940 }
941 else if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR)
942 {
943 updateTypePtrs[elemIdx] = ¶ms.rayTracingSetUpdateType; // Test different ray tracing set update types.
944 pipelineBinds[elemIdx] = SetupOp::BIND_RAYTRACING_PIPELINE;
945 setBinds[elemIdx] = SetupOp::BIND_RAYTRACING_SET;
946 dispatches[elemIdx] = DispatchOp::TRACE_RAYS;
947 }
948 }
949
950 const std::string pairName = toString(testPair[0]) + "_" + toString(testPair[1]);
951 GroupPtr pairGroup (new tcu::TestCaseGroup(testCtx, pairName.c_str(), ""));
952
953 // Combine two update types.
954 for (int firstUpdateTypeIdx = 0; firstUpdateTypeIdx < static_cast<int>(SetUpdateType::TYPE_COUNT); ++firstUpdateTypeIdx)
955 for (int secondUpdateTypeIdx = 0; secondUpdateTypeIdx < static_cast<int>(SetUpdateType::TYPE_COUNT); ++ secondUpdateTypeIdx)
956 {
957 const auto firstUpdateType = static_cast<SetUpdateType>(firstUpdateTypeIdx);
958 const auto secondUpdateType = static_cast<SetUpdateType>(secondUpdateTypeIdx);
959 const std::string updateGroupName = toString(firstUpdateType) + "_" + toString(secondUpdateType);
960 GroupPtr updateGroup (new tcu::TestCaseGroup(testCtx, updateGroupName.c_str(), ""));
961
962 // Change update types of the relevant sets.
963 *updateTypePtrs[0] = firstUpdateType;
964 *updateTypePtrs[1] = secondUpdateType;
965
966 // Prepare initial permutation of test parameters.
967 params.setupSequence[0] = pipelineBinds[0];
968 params.setupSequence[1] = pipelineBinds[1];
969 params.setupSequence[2] = setBinds[0];
970 params.setupSequence[3] = setBinds[1];
971
972 // Permutate setup sequence and dispatch sequence.
973 const auto ssBegin = params.setupSequence.m_data;
974 const auto ssEnd = ssBegin + decltype(params.setupSequence)::SIZE;
975 do
976 {
977 const auto setupGroupName = toString(params.setupSequence);
978 GroupPtr setupGroup (new tcu::TestCaseGroup(testCtx, setupGroupName.c_str(), ""));
979
980 // Reset dispatch sequence permutation.
981 params.dispatchSequence = dispatches;
982
983 const auto dsBegin = params.dispatchSequence.m_data;
984 const auto dsEnd = dsBegin + decltype(params.dispatchSequence)::SIZE;
985 do
986 {
987 const auto testName = toString(params.dispatchSequence);
988 setupGroup->addChild(new BindPointTest(testCtx, testName, "", params));
989 } while (std::next_permutation(dsBegin, dsEnd));
990
991 updateGroup->addChild(setupGroup.release());
992
993 } while (std::next_permutation(ssBegin, ssEnd));
994
995 pairGroup->addChild(updateGroup.release());
996 }
997
998 bindPointGroup->addChild(pairGroup.release());
999 }
1000
1001
1002 return bindPointGroup.release();
1003 }
1004
1005 } // pipeline
1006 } // vkt
1007
1008