1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 * Copyright (c) 2022 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 Tests using VK_EXT_mesh_shader and VK_EXT_conditional_rendering
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktMeshShaderConditionalRenderingTestsEXT.hpp"
26 #include "vktMeshShaderUtil.hpp"
27 #include "vktTestCase.hpp"
28
29 #include "vkObjUtil.hpp"
30 #include "vkQueryUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkImageUtil.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "vkBufferWithMemory.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkBarrierUtil.hpp"
38
39 #include "tcuVector.hpp"
40 #include "tcuImageCompare.hpp"
41
42 #include <vector>
43 #include <sstream>
44 #include <memory>
45
46 namespace vkt
47 {
48 namespace MeshShader
49 {
50
51 namespace
52 {
53
54 using namespace vk;
55
56 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
57
58 enum class DrawType
59 {
60 DRAW,
61 DRAW_INDIRECT,
62 DRAW_INDIRECT_WITH_COUNT,
63 };
64
65 enum class CmdBufferType
66 {
67 PRIMARY,
68 SECONDARY,
69 SECONDARY_WITH_INHERITANCE,
70 };
71
72 static constexpr VkDeviceSize kBindOffset = 16u;
73
getCondValues(void)74 std::vector<uint32_t> getCondValues(void)
75 {
76 const std::vector<uint32_t> values = {
77 0x01000000u, 0x00010000u, 0x00000100u, 0x00000001u, 0x00000000u,
78 };
79
80 return values;
81 }
82
paddedHex(uint32_t value)83 std::string paddedHex(uint32_t value)
84 {
85 std::ostringstream repr;
86 repr << "0x" << std::hex << std::setw(8u) << std::setfill('0') << value;
87 return repr.str();
88 }
89
getOutputColor(void)90 tcu::Vec4 getOutputColor(void)
91 {
92 return tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
93 }
94
getClearColor(void)95 tcu::Vec4 getClearColor(void)
96 {
97 return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
98 }
99
100 struct TestParams
101 {
102 DrawType drawType;
103 CmdBufferType cmdBufferType;
104 bool bindWithOffset;
105 bool condWithOffset;
106 uint32_t condValue;
107 bool inverted;
108 bool useTask;
109
needsSecondaryCmdBuffervkt::MeshShader::__anon427f83760111::TestParams110 bool needsSecondaryCmdBuffer(void) const
111 {
112 return (cmdBufferType != CmdBufferType::PRIMARY);
113 }
114 };
115
116 class ConditionalRenderingCase : public vkt::TestCase
117 {
118 public:
ConditionalRenderingCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)119 ConditionalRenderingCase(tcu::TestContext &testCtx, const std::string &name, const TestParams ¶ms)
120 : vkt::TestCase(testCtx, name)
121 , m_params(params)
122 {
123 }
~ConditionalRenderingCase(void)124 virtual ~ConditionalRenderingCase(void)
125 {
126 }
127
128 void initPrograms(vk::SourceCollections &programCollection) const override;
129 TestInstance *createInstance(Context &context) const override;
130 void checkSupport(Context &context) const override;
131
132 protected:
133 const TestParams m_params;
134 };
135
136 class ConditionBuffer
137 {
138 public:
ConditionBuffer(const DeviceInterface & vkd,VkDevice device,Allocator & alloc,uint32_t condValue,bool bindWithOffset,bool condWithOffset)139 ConditionBuffer(const DeviceInterface &vkd, VkDevice device, Allocator &alloc, uint32_t condValue,
140 bool bindWithOffset, bool condWithOffset)
141 : m_buffer()
142 , m_allocation()
143 , m_condOffset(0ull)
144 {
145 // Create buffer with the desired size first.
146 const auto condSize = static_cast<VkDeviceSize>(sizeof(condValue));
147 const auto condOffset = (condWithOffset ? condSize : 0ull);
148 const auto bufferSize = condSize + condOffset;
149 const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT);
150 auto buffer = createBuffer(vkd, device, &bufferCreateInfo);
151
152 // Allocate memory taking bindWithOffset into account.
153 const auto bufferMemReqs = getBufferMemoryRequirements(vkd, device, buffer.get());
154 const auto bindOffset = (bindWithOffset ? de::roundUp(kBindOffset, bufferMemReqs.alignment) : 0ull);
155 const auto allocSize = bufferMemReqs.size + bindOffset;
156
157 const auto actualMemReqs =
158 makeMemoryRequirements(allocSize, bufferMemReqs.alignment, bufferMemReqs.memoryTypeBits);
159 auto allocation = alloc.allocate(actualMemReqs, MemoryRequirement::HostVisible);
160 vkd.bindBufferMemory(device, buffer.get(), allocation->getMemory(), bindOffset);
161
162 // Fill buffer data.
163 const uint32_t fillValue = ((condValue != 0u) ? 0u : 1u);
164 uint8_t *hostPtr = reinterpret_cast<uint8_t *>(allocation->getHostPtr());
165
166 deMemset(hostPtr, 0, static_cast<size_t>(actualMemReqs.size));
167 deMemcpy(hostPtr + bindOffset, &fillValue, sizeof(fillValue));
168 deMemcpy(hostPtr + bindOffset + condOffset, &condValue, sizeof(condValue));
169
170 m_buffer = buffer;
171 m_allocation = allocation;
172 m_condOffset = condOffset;
173 }
174
getCondOffset(void) const175 VkDeviceSize getCondOffset(void) const
176 {
177 return m_condOffset;
178 }
179
getBuffer(void) const180 VkBuffer getBuffer(void) const
181 {
182 return m_buffer.get();
183 }
184
185 // Cannot copy or assign this.
186 ConditionBuffer(const ConditionBuffer &) = delete;
187 ConditionBuffer &operator=(const ConditionBuffer &) = delete;
188
189 protected:
190 Move<VkBuffer> m_buffer;
191 de::MovePtr<Allocation> m_allocation;
192 VkDeviceSize m_condOffset;
193 };
194
195 class ConditionalRenderingInstance : public vkt::TestInstance
196 {
197 public:
ConditionalRenderingInstance(Context & context,const TestParams & params)198 ConditionalRenderingInstance(Context &context, const TestParams ¶ms)
199 : vkt::TestInstance(context)
200 , m_params(params)
201 , m_conditionBuffer()
202 , m_indirectDrawArgsBuffer()
203 , m_indirectDrawCountBuffer()
204 {
205 }
~ConditionalRenderingInstance(void)206 virtual ~ConditionalRenderingInstance(void)
207 {
208 }
209
210 tcu::TestStatus iterate(void) override;
211
212 protected:
213 // Creates the indirect buffers that are needed according to the test parameters.
214 void initIndirectBuffers(const DeviceInterface &vkd, const VkDevice device, Allocator &alloc);
215
216 // Calls the appropriate drawing command depending on the test parameters.
217 void drawMeshTasks(const DeviceInterface &vkd, const VkCommandBuffer cmdBuffer) const;
218
219 const TestParams m_params;
220 std::unique_ptr<ConditionBuffer> m_conditionBuffer;
221 std::unique_ptr<BufferWithMemory> m_indirectDrawArgsBuffer;
222 std::unique_ptr<BufferWithMemory> m_indirectDrawCountBuffer;
223 };
224
225 // Makes an indirect buffer with the specified contents.
226 template <class T>
makeIndirectBuffer(const DeviceInterface & vkd,const VkDevice device,Allocator & alloc,const T & data)227 std::unique_ptr<BufferWithMemory> makeIndirectBuffer(const DeviceInterface &vkd, const VkDevice device,
228 Allocator &alloc, const T &data)
229 {
230 const auto bufferSize = static_cast<VkDeviceSize>(sizeof(data));
231 const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
232
233 std::unique_ptr<BufferWithMemory> buffer(
234 new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
235
236 auto &allocation = buffer->getAllocation();
237 void *dataPtr = allocation.getHostPtr();
238
239 deMemcpy(dataPtr, &data, sizeof(data));
240 flushAlloc(vkd, device, allocation);
241
242 return buffer;
243 }
244
initIndirectBuffers(const DeviceInterface & vkd,const VkDevice device,Allocator & alloc)245 void ConditionalRenderingInstance::initIndirectBuffers(const DeviceInterface &vkd, const VkDevice device,
246 Allocator &alloc)
247 {
248 if (m_params.drawType != DrawType::DRAW)
249 {
250 const VkDrawMeshTasksIndirectCommandEXT drawArgs = {1u, 1u, 1u};
251 m_indirectDrawArgsBuffer = makeIndirectBuffer(vkd, device, alloc, drawArgs);
252 }
253
254 if (m_params.drawType == DrawType::DRAW_INDIRECT_WITH_COUNT)
255 {
256 const uint32_t drawCount = 1u;
257 m_indirectDrawCountBuffer = makeIndirectBuffer(vkd, device, alloc, drawCount);
258 }
259 }
260
drawMeshTasks(const DeviceInterface & vkd,const VkCommandBuffer cmdBuffer) const261 void ConditionalRenderingInstance::drawMeshTasks(const DeviceInterface &vkd, const VkCommandBuffer cmdBuffer) const
262 {
263 const auto stride = static_cast<uint32_t>(sizeof(VkDrawMeshTasksIndirectCommandEXT));
264
265 if (m_params.drawType == DrawType::DRAW)
266 {
267 vkd.cmdDrawMeshTasksEXT(cmdBuffer, 1u, 1u, 1u);
268 }
269 else if (m_params.drawType == DrawType::DRAW_INDIRECT)
270 {
271 vkd.cmdDrawMeshTasksIndirectEXT(cmdBuffer, m_indirectDrawArgsBuffer->get(), 0ull, 1u, stride);
272 }
273 else if (m_params.drawType == DrawType::DRAW_INDIRECT_WITH_COUNT)
274 {
275 vkd.cmdDrawMeshTasksIndirectCountEXT(cmdBuffer, m_indirectDrawArgsBuffer->get(), 0ull,
276 m_indirectDrawCountBuffer->get(), 0ull, 1u, stride);
277 }
278 else
279 DE_ASSERT(false);
280 }
281
initPrograms(vk::SourceCollections & programCollection) const282 void ConditionalRenderingCase::initPrograms(vk::SourceCollections &programCollection) const
283 {
284 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
285
286 if (m_params.useTask)
287 {
288 std::ostringstream task;
289 task << "#version 460\n"
290 << "#extension GL_EXT_mesh_shader : enable\n"
291 << "\n"
292 << "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
293 << "\n"
294 << "void main (void) {\n"
295 << " EmitMeshTasksEXT(1u, 1u, 1u);\n"
296 << "}\n";
297 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
298 }
299
300 std::ostringstream mesh;
301 mesh << "#version 460\n"
302 << "#extension GL_EXT_mesh_shader : enable\n"
303 << "\n"
304 << "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
305 << "layout (triangles) out;\n"
306 << "layout (max_vertices=3, max_primitives=1) out;\n"
307 << "\n"
308 << "void main (void) {\n"
309 << " SetMeshOutputsEXT(3u, 1u);\n"
310 << "\n"
311 << " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0u, 1u, 2u);\n"
312 << "\n"
313 << " gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
314 << " gl_MeshVerticesEXT[1].gl_Position = vec4(-1.0, 3.0, 0.0, 1.0);\n"
315 << " gl_MeshVerticesEXT[2].gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
316 << "}\n";
317 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
318
319 const auto outColor = getOutputColor();
320 std::ostringstream frag;
321 frag << "#version 460\n"
322 << "\n"
323 << "layout (location=0) out vec4 outColor;\n"
324 << "\n"
325 << "void main (void) {\n"
326 << " outColor = vec4" << outColor << ";\n"
327 << "}\n";
328 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
329 }
330
createInstance(Context & context) const331 TestInstance *ConditionalRenderingCase::createInstance(Context &context) const
332 {
333 return new ConditionalRenderingInstance(context, m_params);
334 }
335
checkSupport(Context & context) const336 void ConditionalRenderingCase::checkSupport(Context &context) const
337 {
338 checkTaskMeshShaderSupportEXT(context, m_params.useTask /*requireTask*/, true /*requireMesh*/);
339
340 context.requireDeviceFunctionality("VK_EXT_conditional_rendering");
341
342 if (m_params.drawType == DrawType::DRAW_INDIRECT_WITH_COUNT)
343 context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
344
345 if (m_params.cmdBufferType == CmdBufferType::SECONDARY_WITH_INHERITANCE)
346 {
347 const auto &condRenderingFeatures = context.getConditionalRenderingFeaturesEXT();
348 if (!condRenderingFeatures.inheritedConditionalRendering)
349 TCU_THROW(NotSupportedError, "inheritedConditionalRendering not supported");
350 }
351 }
352
iterate()353 tcu::TestStatus ConditionalRenderingInstance::iterate()
354 {
355 const auto &vkd = m_context.getDeviceInterface();
356 const auto device = m_context.getDevice();
357 auto &alloc = m_context.getDefaultAllocator();
358 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
359 const auto queue = m_context.getUniversalQueue();
360
361 const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
362 const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
363 const auto tcuFormat = mapVkFormat(colorFormat);
364 const auto colorExtent = makeExtent3D(4u, 4u, 1u);
365 const tcu::IVec3 iExtent3D(static_cast<int>(colorExtent.width), static_cast<int>(colorExtent.height),
366 static_cast<int>(colorExtent.depth));
367 const auto clearColor = getClearColor();
368 const auto drawColor = getOutputColor();
369 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
370 const auto needsSecCmd = m_params.needsSecondaryCmdBuffer();
371
372 // Create color attachment.
373 const VkImageCreateInfo colorAttCreateInfo = {
374 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
375 nullptr, // const void* pNext;
376 0u, // VkImageCreateFlags flags;
377 VK_IMAGE_TYPE_2D, // VkImageType imageType;
378 colorFormat, // VkFormat format;
379 colorExtent, // VkExtent3D extent;
380 1u, // uint32_t mipLevels;
381 1u, // uint32_t arrayLayers;
382 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
383 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
384 colorUsage, // VkImageUsageFlags usage;
385 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
386 0u, // uint32_t queueFamilyIndexCount;
387 nullptr, // const uint32_t* pQueueFamilyIndices;
388 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
389 };
390 ImageWithMemory colorAtt(vkd, device, alloc, colorAttCreateInfo, MemoryRequirement::Any);
391 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
392 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
393 const auto colorAttView = makeImageView(vkd, device, colorAtt.get(), VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSRR);
394
395 // Render pass and framebuffer.
396 const auto renderPass = makeRenderPass(vkd, device, colorFormat);
397 const auto framebuffer =
398 makeFramebuffer(vkd, device, renderPass.get(), colorAttView.get(), colorExtent.width, colorExtent.height);
399
400 // Verification buffer.
401 const auto verifBufferSize =
402 static_cast<VkDeviceSize>(tcu::getPixelSize(tcuFormat) * iExtent3D.x() * iExtent3D.y() * iExtent3D.z());
403 const auto verifBufferCreateInfo = makeBufferCreateInfo(verifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
404 BufferWithMemory verifBuffer(vkd, device, alloc, verifBufferCreateInfo, MemoryRequirement::HostVisible);
405 auto &verifBufferAlloc = verifBuffer.getAllocation();
406 void *verifBufferData = verifBufferAlloc.getHostPtr();
407
408 // Create the condition buffer.
409 m_conditionBuffer.reset(
410 new ConditionBuffer(vkd, device, alloc, m_params.condValue, m_params.bindWithOffset, m_params.condWithOffset));
411
412 // Create the indirect buffers if needed.
413 initIndirectBuffers(vkd, device, alloc);
414
415 // Pipeline.
416 const auto pipelineLayout = makePipelineLayout(vkd, device);
417 const auto &binaries = m_context.getBinaryCollection();
418 const auto taskModule =
419 (binaries.contains("task") ? createShaderModule(vkd, device, binaries.get("task")) : Move<VkShaderModule>());
420 const auto meshModule = createShaderModule(vkd, device, binaries.get("mesh"));
421 const auto fragModule = createShaderModule(vkd, device, binaries.get("frag"));
422
423 const std::vector<VkViewport> viewports(1u, makeViewport(colorExtent));
424 const std::vector<VkRect2D> scissors(1u, makeRect2D(colorExtent));
425
426 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(), taskModule.get(), meshModule.get(),
427 fragModule.get(), renderPass.get(), viewports, scissors);
428
429 // Command pool and command buffers.
430 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
431 const auto primaryCmdBuffer = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
432 const auto secondaryCmdBuffer =
433 (needsSecCmd ? allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_SECONDARY) :
434 Move<VkCommandBuffer>());
435 const auto primary = primaryCmdBuffer.get();
436 const auto secondary = secondaryCmdBuffer.get();
437
438 // Common conditional rendering begin info.
439 const auto conditionalRenderingFlags =
440 (m_params.inverted ? (VkConditionalRenderingFlagsEXT)VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT :
441 static_cast<VkConditionalRenderingFlagsEXT>(0));
442 const VkConditionalRenderingBeginInfoEXT conditionalRenderingBegin = {
443 VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT, // VkStructureType sType;
444 nullptr, // const void* pNext;
445 m_conditionBuffer->getBuffer(), // VkBuffer buffer;
446 m_conditionBuffer->getCondOffset(), // VkDeviceSize offset;
447 conditionalRenderingFlags, // VkConditionalRenderingFlagsEXT flags;
448 };
449
450 // Inheritance info for the secondary command buffer.
451 const auto conditionalRenderingEnable =
452 ((m_params.cmdBufferType == CmdBufferType::SECONDARY_WITH_INHERITANCE) ? VK_TRUE : VK_FALSE);
453 const vk::VkCommandBufferInheritanceConditionalRenderingInfoEXT conditionalRenderingInheritanceInfo = {
454 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT, // VkStructureType sType;
455 nullptr, // const void* pNext;
456 conditionalRenderingEnable, // VkBool32 conditionalRenderingEnable;
457 };
458
459 const VkCommandBufferInheritanceInfo inheritanceInfo = {
460 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // VkStructureType sType;
461 &conditionalRenderingInheritanceInfo, // const void* pNext;
462 renderPass.get(), // VkRenderPass renderPass;
463 0u, // uint32_t subpass;
464 framebuffer.get(), // VkFramebuffer framebuffer;
465 VK_FALSE, // VkBool32 occlusionQueryEnable;
466 0u, // VkQueryControlFlags queryFlags;
467 0u, // VkQueryPipelineStatisticFlags pipelineStatistics;
468 };
469
470 const VkCommandBufferUsageFlags cmdBufferUsageFlags =
471 (VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT);
472 const VkCommandBufferBeginInfo secondaryBeginInfo = {
473 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
474 nullptr, // const void* pNext;
475 cmdBufferUsageFlags, // VkCommandBufferUsageFlags flags;
476 &inheritanceInfo, // const VkCommandBufferInheritanceInfo* pInheritanceInfo;
477 };
478
479 beginCommandBuffer(vkd, primary);
480
481 if (m_params.cmdBufferType == CmdBufferType::PRIMARY)
482 {
483 // Do everything in the primary command buffer.
484 const auto cmdBuffer = primary;
485
486 vkd.cmdBeginConditionalRenderingEXT(cmdBuffer, &conditionalRenderingBegin);
487 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
488 vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get());
489 drawMeshTasks(vkd, cmdBuffer);
490 endRenderPass(vkd, cmdBuffer);
491 vkd.cmdEndConditionalRenderingEXT(cmdBuffer);
492 }
493 else if (m_params.cmdBufferType == CmdBufferType::SECONDARY)
494 {
495 // Do everything in the secondary command buffer.
496 // In addition, do the conditional rendering inside the render pass so it's a bit different from the primary case.
497 beginRenderPass(vkd, primary, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor,
498 VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
499
500 const auto cmdBuffer = secondaryCmdBuffer.get();
501
502 vkd.beginCommandBuffer(secondary, &secondaryBeginInfo);
503 vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get());
504 vkd.cmdBeginConditionalRenderingEXT(cmdBuffer, &conditionalRenderingBegin);
505 drawMeshTasks(vkd, cmdBuffer);
506 vkd.cmdEndConditionalRenderingEXT(cmdBuffer);
507 endCommandBuffer(vkd, cmdBuffer);
508
509 vkd.cmdExecuteCommands(primary, 1u, &cmdBuffer);
510 endRenderPass(vkd, primary);
511 }
512 else if (m_params.cmdBufferType == CmdBufferType::SECONDARY_WITH_INHERITANCE)
513 {
514 // Inherit everything in the secondary command buffer.
515 vkd.beginCommandBuffer(secondary, &secondaryBeginInfo);
516 vkd.cmdBindPipeline(secondary, bindPoint, pipeline.get());
517 drawMeshTasks(vkd, secondary);
518 endCommandBuffer(vkd, secondary);
519
520 vkd.cmdBeginConditionalRenderingEXT(primary, &conditionalRenderingBegin);
521 beginRenderPass(vkd, primary, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor,
522 VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
523 vkd.cmdExecuteCommands(primary, 1u, &secondary);
524 endRenderPass(vkd, primary);
525 vkd.cmdEndConditionalRenderingEXT(primary);
526 }
527 else
528 DE_ASSERT(false);
529
530 // Transfer color attachment to the verification buffer.
531 const auto postTransferBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
532 const auto copyRegion = makeBufferImageCopy(colorExtent, colorSRL);
533 const auto preTranferBarrier = makeImageMemoryBarrier(
534 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
535 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorAtt.get(), colorSRR);
536
537 cmdPipelineImageMemoryBarrier(vkd, primary, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
538 VK_PIPELINE_STAGE_TRANSFER_BIT, &preTranferBarrier);
539 vkd.cmdCopyImageToBuffer(primary, colorAtt.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verifBuffer.get(), 1u,
540 ©Region);
541 cmdPipelineMemoryBarrier(vkd, primary, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
542 &postTransferBarrier);
543
544 endCommandBuffer(vkd, primary);
545 submitCommandsAndWait(vkd, device, queue, primary);
546
547 invalidateAlloc(vkd, device, verifBufferAlloc);
548
549 const tcu::ConstPixelBufferAccess resultAccess(tcuFormat, iExtent3D, verifBufferData);
550 const bool expectDraw = ((m_params.condValue != 0u) != m_params.inverted);
551 const auto expectedColor = (expectDraw ? drawColor : clearColor);
552 const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f);
553
554 auto &log = m_context.getTestContext().getLog();
555 if (!tcu::floatThresholdCompare(log, "Result", "", expectedColor, resultAccess, threshold,
556 tcu::COMPARE_LOG_ON_ERROR))
557 TCU_FAIL("Check log for details");
558
559 return tcu::TestStatus::pass("Pass");
560 }
561
562 } // namespace
563
createMeshShaderConditionalRenderingTestsEXT(tcu::TestContext & testCtx)564 tcu::TestCaseGroup *createMeshShaderConditionalRenderingTestsEXT(tcu::TestContext &testCtx)
565 {
566 GroupPtr mainGroup(new tcu::TestCaseGroup(testCtx, "conditional_rendering"));
567
568 const struct
569 {
570 DrawType drawType;
571 const char *name;
572 } drawTypeCases[] = {
573 {DrawType::DRAW, "draw"},
574 {DrawType::DRAW_INDIRECT, "draw_indirect"},
575 {DrawType::DRAW_INDIRECT_WITH_COUNT, "draw_indirect_count"},
576 };
577
578 const struct
579 {
580 CmdBufferType cmdBufferType;
581 const char *name;
582 } cmdBufferTypeCases[] = {
583 {CmdBufferType::PRIMARY, "primary_cmd_buffer"},
584 {CmdBufferType::SECONDARY, "secondary_cmd_buffer"},
585 {CmdBufferType::SECONDARY_WITH_INHERITANCE, "secondary_cmd_buffer_inheritance"},
586 };
587
588 const struct
589 {
590 bool bindWithOffset;
591 const char *name;
592 } bindWithOffsetCases[] = {
593 {false, "bind_without_offset"},
594 {true, "bind_with_offset"},
595 };
596
597 const struct
598 {
599 bool condWithOffset;
600 const char *name;
601 } condWithOffsetCases[] = {
602 {false, "cond_without_offset"},
603 {true, "cond_with_offset"},
604 };
605
606 const struct
607 {
608 bool inverted;
609 const char *name;
610 } inversionCases[] = {
611 {false, "normal_cond"},
612 {true, "inverted_cond"},
613 };
614
615 const struct
616 {
617 bool useTask;
618 const char *name;
619 } useTaskCases[] = {
620 {false, "mesh_only"},
621 {true, "mesh_and_task"},
622 };
623
624 const auto condValues = getCondValues();
625
626 for (const auto &drawTypeCase : drawTypeCases)
627 {
628 GroupPtr drawTypeGroup(new tcu::TestCaseGroup(testCtx, drawTypeCase.name));
629
630 for (const auto &cmdBufferTypeCase : cmdBufferTypeCases)
631 {
632 GroupPtr cmdBufferTypeGroup(new tcu::TestCaseGroup(testCtx, cmdBufferTypeCase.name));
633
634 for (const auto &bindWithOffsetCase : bindWithOffsetCases)
635 {
636 GroupPtr bindWithOffsetGroup(new tcu::TestCaseGroup(testCtx, bindWithOffsetCase.name));
637
638 for (const auto &condWithOffsetCase : condWithOffsetCases)
639 {
640 GroupPtr condWithOffsetGroup(new tcu::TestCaseGroup(testCtx, condWithOffsetCase.name));
641
642 for (const auto &inversionCase : inversionCases)
643 {
644 GroupPtr inversionGroup(new tcu::TestCaseGroup(testCtx, inversionCase.name));
645
646 for (const auto &useTaskCase : useTaskCases)
647 {
648 GroupPtr useTaskGroup(new tcu::TestCaseGroup(testCtx, useTaskCase.name));
649
650 for (const auto &condValue : condValues)
651 {
652 const auto testName = "value_" + paddedHex(condValue);
653 const TestParams params = {
654 drawTypeCase.drawType, // DrawType drawType;
655 cmdBufferTypeCase.cmdBufferType, // CmdBufferType cmdBufferType;
656 bindWithOffsetCase.bindWithOffset, // bool bindWithOffset;
657 condWithOffsetCase.condWithOffset, // bool condWithOffset;
658 condValue, // uint32_t condValue;
659 inversionCase.inverted, // bool inverted;
660 useTaskCase.useTask, // bool useTask;
661 };
662 useTaskGroup->addChild(new ConditionalRenderingCase(testCtx, testName, params));
663 }
664
665 inversionGroup->addChild(useTaskGroup.release());
666 }
667
668 condWithOffsetGroup->addChild(inversionGroup.release());
669 }
670
671 bindWithOffsetGroup->addChild(condWithOffsetGroup.release());
672 }
673
674 cmdBufferTypeGroup->addChild(bindWithOffsetGroup.release());
675 }
676
677 drawTypeGroup->addChild(cmdBufferTypeGroup.release());
678 }
679
680 mainGroup->addChild(drawTypeGroup.release());
681 }
682
683 return mainGroup.release();
684 }
685
686 } // namespace MeshShader
687 } // namespace vkt
688