1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2018 The Khronos Group Inc.
6 * Copyright (c) 2018 Danylo Piliaiev <[email protected]>
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 Test for conditional rendering of vkCmdDraw* functions
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktConditionalDrawTests.hpp"
26 #include "vktConditionalRenderingTestUtil.hpp"
27
28 #include "vktTestCaseUtil.hpp"
29 #include "vktDrawTestCaseUtil.hpp"
30
31 #include "vktDrawBaseClass.hpp"
32
33 #include "vkTypeUtil.hpp"
34
35 #include "tcuTestLog.hpp"
36 #include "tcuResource.hpp"
37 #include "tcuImageCompare.hpp"
38 #include "tcuTextureUtil.hpp"
39 #include "tcuRGBA.hpp"
40
41 #include "vkDefs.hpp"
42 #include "vkCmdUtil.hpp"
43
44 namespace vkt
45 {
46 namespace conditional
47 {
48 namespace
49 {
50
51 enum DrawCommandType
52 {
53 DRAW_COMMAND_TYPE_DRAW = 0,
54 DRAW_COMMAND_TYPE_DRAW_INDEXED,
55 DRAW_COMMAND_TYPE_DRAW_INDIRECT,
56 DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT,
57 DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT,
58 DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT,
59
60 DRAW_COMMAND_TYPE_DRAW_LAST
61 };
62
getDrawCommandTypeName(DrawCommandType command)63 const char *getDrawCommandTypeName(DrawCommandType command)
64 {
65 switch (command)
66 {
67 case DRAW_COMMAND_TYPE_DRAW:
68 return "draw";
69 case DRAW_COMMAND_TYPE_DRAW_INDEXED:
70 return "draw_indexed";
71 case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
72 return "draw_indirect";
73 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
74 return "draw_indexed_indirect";
75 case DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT:
76 return "draw_indirect_count";
77 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT:
78 return "draw_indexed_indirect_count";
79 default:
80 DE_ASSERT(false);
81 }
82 return "";
83 }
84
85 struct ConditionalTestSpec : public Draw::TestSpecBase
86 {
87 DrawCommandType command;
88 uint32_t drawCalls;
89 ConditionalData conditionalData;
90 };
91
92 class ConditionalDraw : public Draw::DrawTestsBaseClass
93 {
94 public:
95 typedef ConditionalTestSpec TestSpec;
96
97 ConditionalDraw(Context &context, ConditionalTestSpec testSpec);
98
99 virtual tcu::TestStatus iterate(void);
100 void createAndBindIndexBuffer(vk::VkCommandBuffer cmdBuffer);
101 void createIndirectBuffer(void);
102 void createIndexedIndirectBuffer(void);
103 void createIndirectCountBuffer(void);
104 void recordDraw(vk::VkCommandBuffer cmdBuffer);
105
106 protected:
107 void createRenderPassWithClear(void);
108
109 const DrawCommandType m_command;
110 const uint32_t m_drawCalls;
111
112 const ConditionalData m_conditionalData;
113 de::SharedPtr<Draw::Buffer> m_conditionalBuffer;
114
115 vk::Move<vk::VkCommandBuffer> m_secondaryCmdBuffer;
116 vk::Move<vk::VkCommandBuffer> m_nestedCmdBuffer;
117
118 std::vector<uint32_t> m_indexes;
119 de::SharedPtr<Draw::Buffer> m_indexBuffer;
120
121 de::SharedPtr<Draw::Buffer> m_indirectBuffer;
122 de::SharedPtr<Draw::Buffer> m_indirectCountBuffer;
123
124 // For cases where we want to clear the attachment in the render pass begin operation.
125 vk::Move<vk::VkRenderPass> m_rpWithClear;
126 vk::Move<vk::VkFramebuffer> m_fbWithClear;
127 };
128
checkSupport(Context & context,DrawCommandType command)129 void checkSupport(Context &context, DrawCommandType command)
130 {
131 if (command == DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT || command == DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT)
132 context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
133 }
134
ConditionalDraw(Context & context,ConditionalTestSpec testSpec)135 ConditionalDraw::ConditionalDraw(Context &context, ConditionalTestSpec testSpec)
136 : Draw::DrawTestsBaseClass(context, testSpec.shaders[glu::SHADERTYPE_VERTEX],
137 testSpec.shaders[glu::SHADERTYPE_FRAGMENT],
138 Draw::SharedGroupParams(new Draw::GroupParams{false, false, false, false}),
139 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
140 , m_command(testSpec.command)
141 , m_drawCalls(testSpec.drawCalls)
142 , m_conditionalData(testSpec.conditionalData)
143 {
144 checkConditionalRenderingCapabilities(context, m_conditionalData);
145 checkNestedRenderPassCapabilities(context);
146 checkSupport(context, m_command);
147
148 const float minX = -0.3f;
149 const float maxX = 0.3f;
150 const float drawStep = 0.6f / static_cast<float>(m_drawCalls);
151
152 for (uint32_t drawIdx = 0; drawIdx < m_drawCalls; drawIdx++)
153 {
154 const float minY = minX + static_cast<float>(drawIdx) * drawStep;
155 const float maxY = minY + drawStep;
156
157 m_data.push_back(Draw::VertexElementData(tcu::Vec4(minX, maxY, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
158 m_data.push_back(Draw::VertexElementData(tcu::Vec4(minX, minY, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
159 m_data.push_back(Draw::VertexElementData(tcu::Vec4(maxX, maxY, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
160
161 m_data.push_back(Draw::VertexElementData(tcu::Vec4(minX, minY, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
162 m_data.push_back(Draw::VertexElementData(tcu::Vec4(maxX, maxY, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
163 m_data.push_back(Draw::VertexElementData(tcu::Vec4(maxX, minY, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
164 }
165
166 m_data.push_back(Draw::VertexElementData(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::RGBA::red().toVec(), 0));
167 m_data.push_back(Draw::VertexElementData(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::RGBA::red().toVec(), 0));
168 m_data.push_back(Draw::VertexElementData(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), tcu::RGBA::red().toVec(), 0));
169
170 m_data.push_back(Draw::VertexElementData(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::RGBA::red().toVec(), 0));
171 m_data.push_back(Draw::VertexElementData(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), tcu::RGBA::red().toVec(), 0));
172 m_data.push_back(Draw::VertexElementData(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f), tcu::RGBA::red().toVec(), 0));
173
174 for (uint32_t index = 0; index < m_data.size(); index++)
175 {
176 m_indexes.push_back(index);
177 }
178
179 initialize();
180
181 DE_ASSERT(!(m_conditionalData.clearInRenderPass && m_conditionalData.conditionInSecondaryCommandBuffer));
182
183 if (m_conditionalData.clearInRenderPass)
184 createRenderPassWithClear();
185
186 m_secondaryCmdBuffer =
187 vk::allocateCommandBuffer(m_vk, m_context.getDevice(), *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
188 m_nestedCmdBuffer =
189 vk::allocateCommandBuffer(m_vk, m_context.getDevice(), *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
190 }
191
createRenderPassWithClear(void)192 void ConditionalDraw::createRenderPassWithClear(void)
193 {
194 const auto device = m_context.getDevice();
195 Draw::RenderPassCreateInfo renderPassCreateInfo;
196
197 renderPassCreateInfo.addAttachment(Draw::AttachmentDescription(
198 m_colorAttachmentFormat, vk::VK_SAMPLE_COUNT_1_BIT,
199 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // Clear with the render pass.
200 vk::VK_ATTACHMENT_STORE_OP_STORE, vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, vk::VK_ATTACHMENT_STORE_OP_STORE,
201 vk::VK_IMAGE_LAYOUT_UNDEFINED, vk::VK_IMAGE_LAYOUT_GENERAL));
202
203 const vk::VkAttachmentReference colorAttachmentReference{0, vk::VK_IMAGE_LAYOUT_GENERAL};
204
205 renderPassCreateInfo.addSubpass(Draw::SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, 1,
206 &colorAttachmentReference, DE_NULL,
207 Draw::AttachmentReference(), 0, DE_NULL));
208
209 m_rpWithClear = vk::createRenderPass(m_vk, device, &renderPassCreateInfo);
210
211 // Framebuffer.
212 std::vector<vk::VkImageView> colorAttachments{*m_colorTargetView};
213 const Draw::FramebufferCreateInfo framebufferCreateInfo(*m_rpWithClear, colorAttachments, WIDTH, HEIGHT, 1);
214
215 m_fbWithClear = vk::createFramebuffer(m_vk, device, &framebufferCreateInfo);
216 }
217
createAndBindIndexBuffer(vk::VkCommandBuffer cmdBuffer)218 void ConditionalDraw::createAndBindIndexBuffer(vk::VkCommandBuffer cmdBuffer)
219 {
220 const vk::VkDeviceSize indexDataSize = m_indexes.size() * sizeof(uint32_t);
221 m_indexBuffer = Draw::Buffer::createAndAlloc(
222 m_vk, m_context.getDevice(), Draw::BufferCreateInfo(indexDataSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
223 m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
224
225 uint8_t *indexBufferPtr = reinterpret_cast<uint8_t *>(m_indexBuffer->getBoundMemory().getHostPtr());
226 deMemcpy(indexBufferPtr, &m_indexes[0], static_cast<size_t>(indexDataSize));
227
228 vk::flushAlloc(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory());
229
230 const vk::VkBuffer indexBuffer = m_indexBuffer->object();
231 m_vk.cmdBindIndexBuffer(cmdBuffer, indexBuffer, 0, vk::VK_INDEX_TYPE_UINT32);
232 }
233
createIndirectBuffer(void)234 void ConditionalDraw::createIndirectBuffer(void)
235 {
236 const vk::VkDrawIndirectCommand badDrawCommand = {
237 6u, // vertexCount
238 1u, // instanceCount
239 m_drawCalls * 6u, // firstVertex
240 0u // firstInstance
241 };
242
243 std::vector<vk::VkDrawIndirectCommand> drawCommands;
244 for (uint32_t drawIdx = 0; drawIdx < m_drawCalls; drawIdx++)
245 {
246 const vk::VkDrawIndirectCommand goodDrawCommand = {
247 6u, // vertexCount
248 1u, // instanceCount
249 6u * drawIdx, // firstVertex
250 0u // firstInstance
251 };
252
253 drawCommands.push_back(goodDrawCommand);
254 // *Bad* commands should not be rendered by vkCmdDrawIndirectCountKHR
255 drawCommands.push_back(badDrawCommand);
256 drawCommands.push_back(badDrawCommand);
257 }
258
259 const vk::VkDeviceSize drawCommandsSize = drawCommands.size() * sizeof(vk::VkDrawIndirectCommand);
260
261 m_indirectBuffer = Draw::Buffer::createAndAlloc(
262 m_vk, m_context.getDevice(), Draw::BufferCreateInfo(drawCommandsSize, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
263 m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
264
265 uint8_t *ptr = reinterpret_cast<uint8_t *>(m_indirectBuffer->getBoundMemory().getHostPtr());
266 deMemcpy(ptr, &drawCommands[0], static_cast<size_t>(drawCommandsSize));
267
268 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
269 }
270
createIndexedIndirectBuffer(void)271 void ConditionalDraw::createIndexedIndirectBuffer(void)
272 {
273 const vk::VkDrawIndexedIndirectCommand badDrawCommand = {
274 6u, // indexCount
275 1u, // instanceCount
276 m_drawCalls * 6u, // firstIndex
277 0u, // vertexOffset
278 0u, // firstInstance
279 };
280
281 std::vector<vk::VkDrawIndexedIndirectCommand> drawCommands;
282 for (uint32_t drawIdx = 0; drawIdx < m_drawCalls; drawIdx++)
283 {
284 const vk::VkDrawIndexedIndirectCommand goodDrawCommand = {
285 6u, // indexCount
286 1u, // instanceCount
287 6u * drawIdx, // firstIndex
288 0u, // vertexOffset
289 0u, // firstInstance
290 };
291
292 drawCommands.push_back(goodDrawCommand);
293 // *Bad* commands should not be rendered by vkCmdDrawIndexedIndirectCountKHR
294 drawCommands.push_back(badDrawCommand);
295 drawCommands.push_back(badDrawCommand);
296 }
297
298 const vk::VkDeviceSize drawCommandsSize = drawCommands.size() * sizeof(vk::VkDrawIndexedIndirectCommand);
299
300 m_indirectBuffer = Draw::Buffer::createAndAlloc(
301 m_vk, m_context.getDevice(), Draw::BufferCreateInfo(drawCommandsSize, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
302 m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
303
304 uint8_t *ptr = reinterpret_cast<uint8_t *>(m_indirectBuffer->getBoundMemory().getHostPtr());
305 deMemcpy(ptr, &drawCommands[0], static_cast<size_t>(drawCommandsSize));
306
307 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
308 }
309
createIndirectCountBuffer(void)310 void ConditionalDraw::createIndirectCountBuffer(void)
311 {
312 m_indirectCountBuffer = Draw::Buffer::createAndAlloc(
313 m_vk, m_context.getDevice(), Draw::BufferCreateInfo(sizeof(uint32_t), vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
314 m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
315
316 uint8_t *countBufferPtr = reinterpret_cast<uint8_t *>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
317 *(uint32_t *)(countBufferPtr) = 1;
318
319 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
320 }
321
recordDraw(vk::VkCommandBuffer cmdBuffer)322 void ConditionalDraw::recordDraw(vk::VkCommandBuffer cmdBuffer)
323 {
324 for (uint32_t drawIdx = 0; drawIdx < m_drawCalls; drawIdx++)
325 {
326 /* Indirect buffer has next layout:
327 * goodCommand badCommand badCommand goodCommand badCommand badCommand ...
328 */
329 const vk::VkDeviceSize indirectOffset = sizeof(vk::VkDrawIndirectCommand) * drawIdx * 3;
330 const vk::VkDeviceSize indexedIndirectOffset = sizeof(vk::VkDrawIndexedIndirectCommand) * drawIdx * 3;
331 switch (m_command)
332 {
333 case DRAW_COMMAND_TYPE_DRAW:
334 {
335 m_vk.cmdDraw(cmdBuffer, 6, 1, 6 * drawIdx, 0);
336 break;
337 }
338 case DRAW_COMMAND_TYPE_DRAW_INDEXED:
339 {
340 m_vk.cmdDrawIndexed(cmdBuffer, 6, 1, 6 * drawIdx, 0, 0);
341 break;
342 }
343 case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
344 {
345 m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), indirectOffset, 1, 0);
346 break;
347 }
348 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
349 {
350 m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), indexedIndirectOffset, 1, 0);
351 break;
352 }
353 case DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT:
354 {
355 m_vk.cmdDrawIndirectCount(cmdBuffer, m_indirectBuffer->object(), indirectOffset,
356 m_indirectCountBuffer->object(), 0, 3, sizeof(vk::VkDrawIndirectCommand));
357 break;
358 }
359 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT:
360 {
361 m_vk.cmdDrawIndexedIndirectCount(cmdBuffer, m_indirectBuffer->object(), indexedIndirectOffset,
362 m_indirectCountBuffer->object(), 0, 3,
363 sizeof(vk::VkDrawIndexedIndirectCommand));
364 break;
365 }
366 default:
367 DE_ASSERT(false);
368 }
369 }
370 }
371
iterate(void)372 tcu::TestStatus ConditionalDraw::iterate(void)
373 {
374 tcu::TestLog &log = m_context.getTestContext().getLog();
375 const vk::VkQueue queue = m_context.getUniversalQueue();
376 const vk::VkDevice device = m_context.getDevice();
377
378 // We will clear to a different color to be sure.
379 const auto clearColor =
380 (m_conditionalData.clearInRenderPass ? tcu::RGBA::white().toVec() : tcu::RGBA::black().toVec());
381
382 m_conditionalBuffer = createConditionalRenderingBuffer(m_context, m_conditionalData);
383
384 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
385 preRenderBarriers();
386
387 const bool useSecondaryCmdBuffer =
388 m_conditionalData.conditionInherited || m_conditionalData.conditionInSecondaryCommandBuffer;
389 const auto subpassContents =
390 (useSecondaryCmdBuffer ? vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : vk::VK_SUBPASS_CONTENTS_INLINE);
391
392 if (m_conditionalData.clearInRenderPass)
393 {
394 // When clearing in the render pass we want to check the render pass clear is executed properly.
395 beginConditionalRendering(m_vk, *m_cmdBuffer, *m_conditionalBuffer, m_conditionalData);
396 vk::beginRenderPass(m_vk, *m_cmdBuffer, *m_rpWithClear, *m_fbWithClear, vk::makeRect2D(WIDTH, HEIGHT),
397 clearColor, subpassContents);
398 }
399 else
400 {
401 beginLegacyRender(*m_cmdBuffer, subpassContents);
402 }
403
404 vk::VkCommandBuffer targetCmdBuffer = *m_cmdBuffer;
405
406 if (useSecondaryCmdBuffer)
407 {
408 const vk::VkCommandBufferInheritanceConditionalRenderingInfoEXT conditionalRenderingInheritanceInfo = {
409 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT, DE_NULL,
410 m_conditionalData.conditionInherited ? VK_TRUE : VK_FALSE // conditionalRenderingEnable
411 };
412
413 const vk::VkCommandBufferInheritanceInfo inheritanceInfo = {
414 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
415 &conditionalRenderingInheritanceInfo,
416 *m_renderPass, // renderPass
417 0u, // subpass
418 *m_framebuffer, // framebuffer
419 VK_FALSE, // occlusionQueryEnable
420 (vk::VkQueryControlFlags)0u, // queryFlags
421 (vk::VkQueryPipelineStatisticFlags)0u, // pipelineStatistics
422 };
423
424 const vk::VkCommandBufferBeginInfo commandBufferBeginInfo = {
425 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, DE_NULL,
426 vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inheritanceInfo};
427
428 if (m_conditionalData.secondaryCommandBufferNested)
429 {
430 VK_CHECK(m_vk.beginCommandBuffer(*m_nestedCmdBuffer, &commandBufferBeginInfo));
431 }
432
433 VK_CHECK(m_vk.beginCommandBuffer(*m_secondaryCmdBuffer, &commandBufferBeginInfo));
434
435 targetCmdBuffer = *m_secondaryCmdBuffer;
436 }
437
438 const vk::VkDeviceSize vertexBufferOffset = 0;
439 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
440
441 m_vk.cmdBindVertexBuffers(targetCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
442
443 switch (m_command)
444 {
445 case DRAW_COMMAND_TYPE_DRAW:
446 {
447 break;
448 }
449 case DRAW_COMMAND_TYPE_DRAW_INDEXED:
450 {
451 createAndBindIndexBuffer(targetCmdBuffer);
452 break;
453 }
454 case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
455 {
456 createIndirectBuffer();
457 break;
458 }
459 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
460 {
461 createAndBindIndexBuffer(targetCmdBuffer);
462 createIndexedIndirectBuffer();
463 break;
464 }
465 case DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT:
466 {
467 createIndirectBuffer();
468 createIndirectCountBuffer();
469 break;
470 }
471 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT:
472 {
473 createAndBindIndexBuffer(targetCmdBuffer);
474 createIndexedIndirectBuffer();
475 createIndirectCountBuffer();
476 break;
477 }
478 default:
479 DE_ASSERT(false);
480 }
481
482 m_vk.cmdBindPipeline(targetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
483
484 if (m_conditionalData.conditionInSecondaryCommandBuffer)
485 {
486 beginConditionalRendering(m_vk, *m_secondaryCmdBuffer, *m_conditionalBuffer, m_conditionalData);
487 recordDraw(*m_secondaryCmdBuffer);
488 m_vk.cmdEndConditionalRenderingEXT(*m_secondaryCmdBuffer);
489 m_vk.endCommandBuffer(*m_secondaryCmdBuffer);
490 }
491 else if (m_conditionalData.conditionInherited)
492 {
493 recordDraw(*m_secondaryCmdBuffer);
494 m_vk.endCommandBuffer(*m_secondaryCmdBuffer);
495 }
496
497 if (useSecondaryCmdBuffer && m_conditionalData.secondaryCommandBufferNested)
498 {
499 m_vk.cmdExecuteCommands(*m_nestedCmdBuffer, 1, &m_secondaryCmdBuffer.get());
500 m_vk.endCommandBuffer(*m_nestedCmdBuffer);
501 }
502
503 if (m_conditionalData.conditionInPrimaryCommandBuffer)
504 {
505 if (!m_conditionalData.clearInRenderPass)
506 beginConditionalRendering(m_vk, *m_cmdBuffer, *m_conditionalBuffer, m_conditionalData);
507
508 if (m_conditionalData.conditionInherited)
509 {
510 if (m_conditionalData.secondaryCommandBufferNested)
511 {
512 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1, &m_nestedCmdBuffer.get());
513 }
514 else
515 {
516 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1, &m_secondaryCmdBuffer.get());
517 }
518 }
519 else
520 {
521 recordDraw(*m_cmdBuffer);
522 }
523
524 if (!m_conditionalData.clearInRenderPass)
525 m_vk.cmdEndConditionalRenderingEXT(*m_cmdBuffer);
526 }
527 else if (useSecondaryCmdBuffer)
528 {
529 if (m_conditionalData.secondaryCommandBufferNested)
530 {
531 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1, &m_nestedCmdBuffer.get());
532 }
533 else
534 {
535 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1, &m_secondaryCmdBuffer.get());
536 }
537 }
538
539 if (m_conditionalData.clearInRenderPass)
540 {
541 // Finish conditional rendering outside the render pass.
542 vk::endRenderPass(m_vk, *m_cmdBuffer);
543 m_vk.cmdEndConditionalRenderingEXT(*m_cmdBuffer);
544 }
545 else
546 {
547 endLegacyRender(*m_cmdBuffer);
548 }
549
550 endCommandBuffer(m_vk, *m_cmdBuffer);
551
552 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
553
554 // Validation
555 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
556 (int)(0.5f + static_cast<float>(HEIGHT)));
557 referenceFrame.allocLevel(0);
558
559 const int32_t frameWidth = referenceFrame.getWidth();
560 const int32_t frameHeight = referenceFrame.getHeight();
561
562 tcu::clear(referenceFrame.getLevel(0), clearColor);
563
564 const tcu::Vec4 drawColor = tcu::RGBA::blue().toVec();
565 const tcu::Vec4 referenceColor = m_conditionalData.expectCommandExecution ? drawColor : clearColor;
566
567 Draw::ReferenceImageCoordinates refCoords;
568
569 for (int y = 0; y < frameHeight; y++)
570 {
571 const float yCoord = (float)(y / (0.5 * frameHeight)) - 1.0f;
572
573 for (int x = 0; x < frameWidth; x++)
574 {
575 const float xCoord = (float)(x / (0.5 * frameWidth)) - 1.0f;
576
577 if ((yCoord >= refCoords.bottom && yCoord <= refCoords.top && xCoord >= refCoords.left &&
578 xCoord <= refCoords.right))
579 referenceFrame.getLevel(0).setPixel(referenceColor, x, y);
580 }
581 }
582
583 const vk::VkOffset3D zeroOffset = {0, 0, 0};
584 const tcu::ConstPixelBufferAccess renderedFrame =
585 m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset,
586 WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
587
588 qpTestResult res = QP_TEST_RESULT_PASS;
589
590 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame.getLevel(0), renderedFrame, 0.05f,
591 tcu::COMPARE_LOG_RESULT))
592 {
593 res = QP_TEST_RESULT_FAIL;
594 }
595
596 return tcu::TestStatus(res, qpGetTestResultName(res));
597 }
598
599 } // namespace
600
ConditionalDrawTests(tcu::TestContext & testCtx)601 ConditionalDrawTests::ConditionalDrawTests(tcu::TestContext &testCtx) : TestCaseGroup(testCtx, "draw")
602 {
603 /* Left blank on purpose */
604 }
605
~ConditionalDrawTests(void)606 ConditionalDrawTests::~ConditionalDrawTests(void)
607 {
608 }
609
init(void)610 void ConditionalDrawTests::init(void)
611 {
612 for (int conditionNdx = 0; conditionNdx < DE_LENGTH_OF_ARRAY(conditional::s_testsData); conditionNdx++)
613 {
614 const ConditionalData &conditionData = conditional::s_testsData[conditionNdx];
615
616 tcu::TestCaseGroup *conditionalDrawRootGroup =
617 new tcu::TestCaseGroup(m_testCtx, de::toString(conditionData).c_str());
618
619 for (uint32_t commandTypeIdx = 0; commandTypeIdx < DRAW_COMMAND_TYPE_DRAW_LAST; ++commandTypeIdx)
620 {
621 const DrawCommandType command = DrawCommandType(commandTypeIdx);
622
623 ConditionalTestSpec testSpec;
624 testSpec.command = command;
625 testSpec.drawCalls = 4;
626 testSpec.conditionalData = conditionData;
627 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/dynamic_state/VertexFetch.vert";
628 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/dynamic_state/VertexFetch.frag";
629
630 conditionalDrawRootGroup->addChild(
631 new Draw::InstanceFactory<ConditionalDraw>(m_testCtx, getDrawCommandTypeName(command), testSpec));
632 }
633
634 addChild(conditionalDrawRootGroup);
635 }
636 }
637
638 } // namespace conditional
639 } // namespace vkt
640