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