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