1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 LunarG, Inc.
6  * Copyright (c) 2023 Google LLC
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 "vktConditionalTransformFeedbackTests.hpp"
26 
27 #include "vktConditionalRenderingTestUtil.hpp"
28 #include "vktTestCaseUtil.hpp"
29 #include "vktDrawTestCaseUtil.hpp"
30 #include "vktDrawBaseClass.hpp"
31 #include "vkDefs.hpp"
32 #include "vkCmdUtil.hpp"
33 #include "vkBarrierUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "tcuTestLog.hpp"
36 #include "tcuResource.hpp"
37 #include "tcuImageCompare.hpp"
38 #include "tcuTextureUtil.hpp"
39 #include "tcuRGBA.hpp"
40 #include "vktDrawCreateInfoUtil.hpp"
41 
42 namespace vkt
43 {
44 namespace conditional
45 {
46 namespace
47 {
48 
49 enum DrawCommandType
50 {
51     DRAW_COMMAND_TYPE_DRAW = 0,
52     DRAW_COMMAND_TYPE_DRAW_INDEXED,
53     DRAW_COMMAND_TYPE_DRAW_INDIRECT,
54     DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT,
55     DRAW_COMMAND_TYPE_DRAW_MULTI_EXT,
56     DRAW_COMMAND_TYPE_DRAW_MULTI_INDEXED_EXT,
57     DRAW_COMMAND_TYPE_INDIRECT_BYTE_COUNT_EXT,
58     DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT,
59     DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT,
60 
61     DRAW_COMMAND_TYPE_DRAW_LAST
62 };
63 
getDrawCommandTypeName(DrawCommandType command)64 const char *getDrawCommandTypeName(DrawCommandType command)
65 {
66     switch (command)
67     {
68     case DRAW_COMMAND_TYPE_DRAW:
69         return "draw";
70     case DRAW_COMMAND_TYPE_DRAW_INDEXED:
71         return "draw_indexed";
72     case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
73         return "draw_indirect";
74     case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
75         return "draw_indexed_indirect";
76     case DRAW_COMMAND_TYPE_DRAW_MULTI_EXT:
77         return "draw_multi_ext";
78     case DRAW_COMMAND_TYPE_DRAW_MULTI_INDEXED_EXT:
79         return "draw_multi_indexed_ext";
80     case DRAW_COMMAND_TYPE_INDIRECT_BYTE_COUNT_EXT:
81         return "draw_indirect_byte_count_ext";
82     case DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT:
83         return "draw_indirect_count";
84     case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT:
85         return "draw_indexed_indirect_count";
86     default:
87         DE_ASSERT(false);
88     }
89     return "";
90 }
91 
92 struct ConditionalTestSpec : public Draw::TestSpecBase
93 {
94     DrawCommandType command;
95 };
96 
97 class ConditionalTransformFeedbackDraw : public Draw::DrawTestsBaseClass
98 {
99 public:
100     typedef ConditionalTestSpec TestSpec;
101 
102     ConditionalTransformFeedbackDraw(Context &context, ConditionalTestSpec testSpec);
103 
104     virtual tcu::TestStatus iterate(void);
105     void createAndBindIndexBuffer(vk::VkCommandBuffer cmdBuffer);
106     void createIndirectBuffer(void);
107     void createIndexedIndirectBuffer(void);
108     void createIndirectCountBuffer(void);
109     void createCountBuffer(void);
110     void createXfbBuffer(void);
111     void createStreamPipeline(void);
112     void recordDraw(vk::VkCommandBuffer cmdBuffer, uint32_t index);
113 
114 protected:
115     const DrawCommandType m_command;
116 
117     std::vector<uint32_t> m_indexes;
118     de::SharedPtr<Draw::Buffer> m_indexBuffer;
119 
120     de::SharedPtr<Draw::Buffer> m_indirectBuffer;
121     de::SharedPtr<Draw::Buffer> m_indirectCountBuffer;
122     de::SharedPtr<Draw::Buffer> m_countBuffer;
123 
124     de::SharedPtr<Draw::Buffer> m_xfbBuffer;
125     de::SharedPtr<Draw::Buffer> m_queryBuffer;
126 
127     vk::Move<vk::VkPipelineLayout> m_streamPipelineLayout;
128     vk::Move<vk::VkPipeline> m_streamPipeline;
129 };
130 
checkSupport(Context & context,ConditionalTestSpec testSpec)131 void checkSupport(Context &context, ConditionalTestSpec testSpec)
132 {
133     context.requireDeviceFunctionality("VK_EXT_conditional_rendering");
134     context.requireDeviceFunctionality("VK_EXT_transform_feedback");
135 
136     if (context.getConditionalRenderingFeaturesEXT().conditionalRendering == VK_FALSE)
137         TCU_THROW(NotSupportedError, "conditionalRendering feature not supported");
138 
139     if (testSpec.command == DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT ||
140         testSpec.command == DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT)
141         context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
142 
143     if (testSpec.command == DRAW_COMMAND_TYPE_DRAW_MULTI_EXT ||
144         testSpec.command == DRAW_COMMAND_TYPE_DRAW_MULTI_INDEXED_EXT)
145         context.requireDeviceFunctionality("VK_EXT_multi_draw");
146 
147     if (!context.getTransformFeedbackFeaturesEXT().geometryStreams)
148         TCU_THROW(NotSupportedError, "geometryStreams feature not supported");
149     if (context.getTransformFeedbackPropertiesEXT().transformFeedbackDraw == VK_FALSE)
150         TCU_THROW(NotSupportedError, "transformFeedbackDraw feature not supported");
151     if (context.getTransformFeedbackPropertiesEXT().maxTransformFeedbackBuffers < 4)
152         TCU_THROW(NotSupportedError, "maxTransformFeedbackBuffers is less than required");
153     if (context.getTransformFeedbackPropertiesEXT().maxTransformFeedbackStreams < 4)
154         TCU_THROW(NotSupportedError, "maxTransformFeedbackStreams is less than required");
155 }
156 
ConditionalTransformFeedbackDraw(Context & context,ConditionalTestSpec testSpec)157 ConditionalTransformFeedbackDraw::ConditionalTransformFeedbackDraw(Context &context, ConditionalTestSpec testSpec)
158     : Draw::DrawTestsBaseClass(context, testSpec.shaders[glu::SHADERTYPE_VERTEX],
159                                testSpec.shaders[glu::SHADERTYPE_FRAGMENT],
160                                Draw::SharedGroupParams(new Draw::GroupParams{false, false, false, false}),
161                                vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
162     , m_command(testSpec.command)
163 {
164     checkSupport(context, testSpec);
165 
166     m_data.push_back(Draw::VertexElementData(tcu::Vec4(-0.3f, 0.3f, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
167     m_data.push_back(Draw::VertexElementData(tcu::Vec4(-0.3f, -0.3f, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
168     m_data.push_back(Draw::VertexElementData(tcu::Vec4(0.3f, 0.3f, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
169 
170     m_data.push_back(Draw::VertexElementData(tcu::Vec4(-0.3f, -0.3f, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
171     m_data.push_back(Draw::VertexElementData(tcu::Vec4(0.3f, 0.3f, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
172     m_data.push_back(Draw::VertexElementData(tcu::Vec4(0.3f, -0.3f, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
173 
174     m_data.push_back(Draw::VertexElementData(tcu::Vec4(-0.3f, 0.3f, 0.5f, 1.0f), tcu::RGBA::black().toVec(), 0));
175     m_data.push_back(Draw::VertexElementData(tcu::Vec4(-0.3f, -0.3f, 0.5f, 1.0f), tcu::RGBA::black().toVec(), 0));
176     m_data.push_back(Draw::VertexElementData(tcu::Vec4(0.3f, 0.3f, 0.5f, 1.0f), tcu::RGBA::black().toVec(), 0));
177 
178     m_data.push_back(Draw::VertexElementData(tcu::Vec4(-0.3f, -0.3f, 0.5f, 1.0f), tcu::RGBA::black().toVec(), 0));
179     m_data.push_back(Draw::VertexElementData(tcu::Vec4(0.3f, 0.3f, 0.5f, 1.0f), tcu::RGBA::black().toVec(), 0));
180     m_data.push_back(Draw::VertexElementData(tcu::Vec4(0.3f, -0.3f, 0.5f, 1.0f), tcu::RGBA::black().toVec(), 0));
181 
182     m_data.push_back(Draw::VertexElementData(tcu::Vec4(5.3f, 6.3f, 0.5f, 1.0f), tcu::RGBA::red().toVec(), 0));
183     m_data.push_back(Draw::VertexElementData(tcu::Vec4(5.3f, 5.3f, 0.5f, 1.0f), tcu::RGBA::red().toVec(), 0));
184     m_data.push_back(Draw::VertexElementData(tcu::Vec4(6.3f, 6.3f, 0.5f, 1.0f), tcu::RGBA::red().toVec(), 0));
185 
186     m_data.push_back(Draw::VertexElementData(tcu::Vec4(5.3f, 5.3f, 0.5f, 1.0f), tcu::RGBA::red().toVec(), 0));
187     m_data.push_back(Draw::VertexElementData(tcu::Vec4(6.3f, 6.3f, 0.5f, 1.0f), tcu::RGBA::red().toVec(), 0));
188     m_data.push_back(Draw::VertexElementData(tcu::Vec4(6.3f, 5.3f, 0.5f, 1.0f), tcu::RGBA::red().toVec(), 0));
189 
190     for (uint32_t index = 0; index < m_data.size(); index++)
191     {
192         m_indexes.push_back(index);
193     }
194 
195     initialize();
196 }
197 
createAndBindIndexBuffer(vk::VkCommandBuffer cmdBuffer)198 void ConditionalTransformFeedbackDraw::createAndBindIndexBuffer(vk::VkCommandBuffer cmdBuffer)
199 {
200     const vk::VkDeviceSize indexDataSize = m_indexes.size() * sizeof(uint32_t);
201     m_indexBuffer                        = Draw::Buffer::createAndAlloc(
202         m_vk, m_context.getDevice(), Draw::BufferCreateInfo(indexDataSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
203         m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
204 
205     uint8_t *indexBufferPtr = reinterpret_cast<uint8_t *>(m_indexBuffer->getBoundMemory().getHostPtr());
206     deMemcpy(indexBufferPtr, &m_indexes[0], static_cast<size_t>(indexDataSize));
207 
208     vk::flushAlloc(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory());
209 
210     const vk::VkBuffer indexBuffer = m_indexBuffer->object();
211     m_vk.cmdBindIndexBuffer(cmdBuffer, indexBuffer, 0, vk::VK_INDEX_TYPE_UINT32);
212 }
213 
createIndirectBuffer(void)214 void ConditionalTransformFeedbackDraw::createIndirectBuffer(void)
215 {
216     const vk::VkDrawIndirectCommand drawCommands[] = {
217         {6u, 1u, 0u, 0u},
218         {6u, 1u, 6u, 0u},
219         {6u, 1u, 12u, 0u},
220     };
221 
222     m_indirectBuffer = Draw::Buffer::createAndAlloc(
223         m_vk, m_context.getDevice(),
224         Draw::BufferCreateInfo(sizeof(drawCommands), vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
225         m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
226 
227     uint8_t *ptr = reinterpret_cast<uint8_t *>(m_indirectBuffer->getBoundMemory().getHostPtr());
228     deMemcpy(ptr, &drawCommands[0], static_cast<size_t>(sizeof(drawCommands)));
229 
230     vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
231 }
232 
createIndexedIndirectBuffer(void)233 void ConditionalTransformFeedbackDraw::createIndexedIndirectBuffer(void)
234 {
235     const vk::VkDrawIndexedIndirectCommand drawCommand[] = {
236         {
237             6u,
238             1u,
239             0u,
240             0u,
241             0u,
242         },
243         {
244             6u,
245             1u,
246             6u,
247             0u,
248             0u,
249         },
250         {
251             6u,
252             1u,
253             12u,
254             0u,
255             0u,
256         },
257     };
258 
259     m_indirectBuffer = Draw::Buffer::createAndAlloc(
260         m_vk, m_context.getDevice(),
261         Draw::BufferCreateInfo(sizeof(drawCommand), vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
262         m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
263 
264     uint8_t *ptr = reinterpret_cast<uint8_t *>(m_indirectBuffer->getBoundMemory().getHostPtr());
265     deMemcpy(ptr, &drawCommand, static_cast<size_t>(sizeof(drawCommand)));
266 
267     vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
268 }
269 
createIndirectCountBuffer(void)270 void ConditionalTransformFeedbackDraw::createIndirectCountBuffer(void)
271 {
272     m_indirectCountBuffer = Draw::Buffer::createAndAlloc(
273         m_vk, m_context.getDevice(), Draw::BufferCreateInfo(sizeof(uint32_t), vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
274         m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
275 
276     uint8_t *countBufferPtr       = reinterpret_cast<uint8_t *>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
277     *(uint32_t *)(countBufferPtr) = 1;
278 
279     vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
280 }
281 
createCountBuffer(void)282 void ConditionalTransformFeedbackDraw::createCountBuffer(void)
283 {
284     m_countBuffer = Draw::Buffer::createAndAlloc(
285         m_vk, m_context.getDevice(),
286         Draw::BufferCreateInfo(sizeof(uint32_t) * 2, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
287         m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
288 
289     uint32_t *countBufferPtr = reinterpret_cast<uint32_t *>(m_countBuffer->getBoundMemory().getHostPtr());
290     countBufferPtr[0]        = 6u * 4;
291     countBufferPtr[1]        = 0u;
292 
293     vk::flushAlloc(m_vk, m_context.getDevice(), m_countBuffer->getBoundMemory());
294 }
295 
createXfbBuffer(void)296 void ConditionalTransformFeedbackDraw::createXfbBuffer(void)
297 {
298     const uint32_t output_count = 4 * 6; // 4 stream, 6 points
299     m_xfbBuffer                 = Draw::Buffer::createAndAlloc(
300         m_vk, m_context.getDevice(),
301         Draw::BufferCreateInfo(sizeof(float) * output_count, vk::VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT),
302         m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
303 
304     float *xfbBufferPtr = reinterpret_cast<float *>(m_xfbBuffer->getBoundMemory().getHostPtr());
305     for (uint32_t i = 0; i < output_count; ++i)
306         xfbBufferPtr[i] = 0.0f;
307 
308     vk::flushAlloc(m_vk, m_context.getDevice(), m_xfbBuffer->getBoundMemory());
309 }
310 
createStreamPipeline(void)311 void ConditionalTransformFeedbackDraw::createStreamPipeline(void)
312 {
313     using namespace vkt::Draw;
314 
315     vk::VkPushConstantRange push_const_range;
316     push_const_range.stageFlags = vk::VK_SHADER_STAGE_GEOMETRY_BIT;
317     push_const_range.offset     = 0u;
318     push_const_range.size       = sizeof(int);
319 
320     PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
321     pipelineLayoutCreateInfo.pushConstantRangeCount = 1u;
322     pipelineLayoutCreateInfo.pPushConstantRanges    = &push_const_range;
323     m_streamPipelineLayout = vk::createPipelineLayout(m_vk, m_context.getDevice(), &pipelineLayoutCreateInfo);
324 
325     const vk::Unique<vk::VkShaderModule> vs(
326         createShaderModule(m_vk, m_context.getDevice(), m_context.getBinaryCollection().get(m_vertexShaderName), 0));
327     std::string geom_name = m_context.getDeviceFeatures().shaderTessellationAndGeometryPointSize ?
328                                 "VertexFetchWritePoint.geom" :
329                                 "VertexFetch.geom";
330     const vk::Unique<vk::VkShaderModule> gs(
331         createShaderModule(m_vk, m_context.getDevice(), m_context.getBinaryCollection().get(geom_name), 0));
332 
333     const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
334 
335     vk::VkViewport viewport = vk::makeViewport(WIDTH, HEIGHT);
336     vk::VkRect2D scissor    = vk::makeRect2D(WIDTH, HEIGHT);
337 
338     const vk::VkVertexInputBindingDescription vertexInputBindingDescription = {0, sizeof(VertexElementData),
339                                                                                vk::VK_VERTEX_INPUT_RATE_VERTEX};
340 
341     const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = {
342         {0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u},
343         {1u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<uint32_t>(sizeof(tcu::Vec4))},
344         {2u, 0u, vk::VK_FORMAT_R32_SINT, static_cast<uint32_t>(sizeof(tcu::Vec4)) * 2}};
345 
346     const auto vertexInputState = PipelineCreateInfo::VertexInputState(
347         1, &vertexInputBindingDescription, DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),
348         vertexInputAttributeDescriptions);
349 
350     PipelineCreateInfo pipelineCreateInfo(*m_streamPipelineLayout, *m_renderPass, 0, 0);
351     pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
352     pipelineCreateInfo.addShader(
353         PipelineCreateInfo::PipelineShaderStage(*gs, "main", vk::VK_SHADER_STAGE_GEOMETRY_BIT));
354     pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
355     pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST));
356     pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
357     pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport),
358                                                                   std::vector<vk::VkRect2D>(1, scissor)));
359     pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
360     pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
361     pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
362 
363 #ifndef CTS_USES_VULKANSC
364     const auto viewMask = getDefaultViewMask();
365 
366     vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo{vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
367                                                              DE_NULL,
368                                                              viewMask,
369                                                              1u,
370                                                              &m_colorAttachmentFormat,
371                                                              vk::VK_FORMAT_UNDEFINED,
372                                                              vk::VK_FORMAT_UNDEFINED};
373 
374     if (m_groupParams->useDynamicRendering)
375         pipelineCreateInfo.pNext = &renderingCreateInfo;
376 #endif // CTS_USES_VULKANSC
377 
378     m_streamPipeline = vk::createGraphicsPipeline(m_vk, m_context.getDevice(), DE_NULL, &pipelineCreateInfo);
379 }
380 
recordDraw(vk::VkCommandBuffer cmdBuffer,uint32_t index)381 void ConditionalTransformFeedbackDraw::recordDraw(vk::VkCommandBuffer cmdBuffer, uint32_t index)
382 {
383     const uint32_t firstVertex = 6u * index;
384     const uint32_t firstIndex  = 6u * index;
385     vk::VkMultiDrawInfoEXT multiDrawInfo;
386     multiDrawInfo.firstVertex = firstVertex;
387     multiDrawInfo.vertexCount = 6u;
388     vk::VkMultiDrawIndexedInfoEXT multiDrawIndexedInfo;
389     multiDrawIndexedInfo.firstIndex              = firstVertex;
390     multiDrawIndexedInfo.indexCount              = 6u;
391     multiDrawIndexedInfo.vertexOffset            = 0u;
392     const int32_t vertexOffset                   = 0u;
393     const vk::VkDeviceSize indirectOffset        = sizeof(vk::VkDrawIndirectCommand) * index;
394     const vk::VkDeviceSize indexedIndirectOffset = sizeof(vk::VkDrawIndexedIndirectCommand) * index;
395     switch (m_command)
396     {
397     case DRAW_COMMAND_TYPE_DRAW:
398     {
399         m_vk.cmdDraw(cmdBuffer, 6, 1, firstVertex, 0);
400         break;
401     }
402     case DRAW_COMMAND_TYPE_DRAW_INDEXED:
403     {
404         m_vk.cmdDrawIndexed(cmdBuffer, 6, 1, firstIndex, 0, 0);
405         break;
406     }
407     case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
408     {
409         m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), indirectOffset, 1,
410                              sizeof(vk::VkDrawIndirectCommand));
411         break;
412     }
413     case DRAW_COMMAND_TYPE_DRAW_MULTI_EXT:
414     {
415         m_vk.cmdDrawMultiEXT(cmdBuffer, 1u, &multiDrawInfo, 1, 0, sizeof(vk::VkMultiDrawInfoEXT));
416         break;
417     }
418     case DRAW_COMMAND_TYPE_DRAW_MULTI_INDEXED_EXT:
419     {
420         m_vk.cmdDrawMultiIndexedEXT(cmdBuffer, 1u, &multiDrawIndexedInfo, 1, 0, sizeof(vk::VkMultiDrawIndexedInfoEXT),
421                                     &vertexOffset);
422         break;
423     }
424     case DRAW_COMMAND_TYPE_INDIRECT_BYTE_COUNT_EXT:
425     {
426         m_vk.cmdDrawIndirectByteCountEXT(cmdBuffer, 1, 0, m_countBuffer->object(), (index - 1u) * 4u, 0u, 4u);
427         break;
428     }
429     case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
430     {
431         m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), indexedIndirectOffset, 1, 0);
432         break;
433     }
434     case DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT:
435     {
436         m_vk.cmdDrawIndirectCount(cmdBuffer, m_indirectBuffer->object(), indirectOffset,
437                                   m_indirectCountBuffer->object(), 0, 1, sizeof(vk::VkDrawIndirectCommand));
438         break;
439     }
440     case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT:
441     {
442         m_vk.cmdDrawIndexedIndirectCount(cmdBuffer, m_indirectBuffer->object(), indexedIndirectOffset,
443                                          m_indirectCountBuffer->object(), 0, 1,
444                                          sizeof(vk::VkDrawIndexedIndirectCommand));
445         break;
446     }
447     default:
448         DE_ASSERT(false);
449     }
450 }
451 
iterate(void)452 tcu::TestStatus ConditionalTransformFeedbackDraw::iterate(void)
453 {
454     tcu::TestLog &log         = m_context.getTestContext().getLog();
455     const vk::VkQueue queue   = m_context.getUniversalQueue();
456     const vk::VkDevice device = m_context.getDevice();
457 
458     createStreamPipeline();
459 
460     vk::VkQueryPoolCreateInfo queryPoolInfo{
461         vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, // VkStructureType sType;
462         DE_NULL,                                      // const void* pNext;
463         (vk::VkQueryPoolCreateFlags)0,                // VkQueryPoolCreateFlags flags;
464         vk::VK_QUERY_TYPE_OCCLUSION,                  // VkQueryType queryType;
465         2u,                                           // uint32_t queryCount;
466         0u,                                           // VkQueryPipelineStatisticFlags pipelineStatistics;
467     };
468 
469     vk::Move<vk::VkQueryPool> queryPool = vk::createQueryPool(m_vk, device, &queryPoolInfo);
470 
471     m_queryBuffer = Draw::Buffer::createAndAlloc(
472         m_vk, m_context.getDevice(),
473         Draw::BufferCreateInfo(sizeof(uint32_t) * 2u, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT |
474                                                           vk::VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT),
475         m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
476 
477     createXfbBuffer();
478 
479     beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
480     preRenderBarriers();
481 
482     m_vk.cmdResetQueryPool(*m_cmdBuffer, *queryPool, 0u, 2u);
483     beginLegacyRender(*m_cmdBuffer, vk::VK_SUBPASS_CONTENTS_INLINE);
484 
485     const vk::VkDeviceSize vertexBufferOffset = 0;
486     const vk::VkBuffer vertexBuffer           = m_vertexBuffer->object();
487 
488     m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
489 
490     m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
491 
492     switch (m_command)
493     {
494     case DRAW_COMMAND_TYPE_DRAW:
495     {
496         break;
497     }
498     case DRAW_COMMAND_TYPE_DRAW_INDEXED:
499     {
500         createAndBindIndexBuffer(*m_cmdBuffer);
501         break;
502     }
503     case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
504     {
505         createIndirectBuffer();
506         break;
507     }
508     case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
509     {
510         createAndBindIndexBuffer(*m_cmdBuffer);
511         createIndexedIndirectBuffer();
512         break;
513     }
514     case DRAW_COMMAND_TYPE_DRAW_MULTI_EXT:
515     {
516         break;
517     }
518     case DRAW_COMMAND_TYPE_DRAW_MULTI_INDEXED_EXT:
519     {
520         createAndBindIndexBuffer(*m_cmdBuffer);
521         break;
522     }
523     case DRAW_COMMAND_TYPE_INDIRECT_BYTE_COUNT_EXT:
524     {
525         createCountBuffer();
526         break;
527     }
528     case DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT:
529     {
530         createIndirectBuffer();
531         createIndirectCountBuffer();
532         break;
533     }
534     case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT:
535     {
536         createAndBindIndexBuffer(*m_cmdBuffer);
537         createIndexedIndirectBuffer();
538         createIndirectCountBuffer();
539         break;
540     }
541     default:
542         DE_ASSERT(false);
543     }
544 
545     m_vk.cmdBeginQuery(*m_cmdBuffer, *queryPool, 0u, 0u);
546     recordDraw(*m_cmdBuffer, 2);
547     m_vk.cmdEndQuery(*m_cmdBuffer, *queryPool, 0u);
548     m_vk.cmdBeginQuery(*m_cmdBuffer, *queryPool, 1u, 0u);
549     recordDraw(*m_cmdBuffer, 1);
550     m_vk.cmdEndQuery(*m_cmdBuffer, *queryPool, 1u);
551 
552     endLegacyRender(*m_cmdBuffer);
553     m_vk.cmdCopyQueryPoolResults(*m_cmdBuffer, *queryPool, 0u, 2u, m_queryBuffer->object(), 0u, sizeof(uint32_t),
554                                  vk::VK_QUERY_RESULT_WAIT_BIT);
555 
556     vk::VkBufferMemoryBarrier bufferMemoryBarrier =
557         vk::makeBufferMemoryBarrier(vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT,
558                                     m_queryBuffer->object(), 0u, sizeof(uint32_t) * 2);
559 
560     m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
561                             vk::VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT, 0, 0, DE_NULL, 1, &bufferMemoryBarrier,
562                             0, DE_NULL);
563 
564     vk::VkConditionalRenderingBeginInfoEXT conditionalRenderingBeginInfo;
565     conditionalRenderingBeginInfo.sType  = vk::VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT;
566     conditionalRenderingBeginInfo.pNext  = nullptr;
567     conditionalRenderingBeginInfo.buffer = m_queryBuffer->object();
568     conditionalRenderingBeginInfo.offset = sizeof(uint32_t);
569     conditionalRenderingBeginInfo.flags  = 0;
570 
571     beginLegacyRender(*m_cmdBuffer, vk::VK_SUBPASS_CONTENTS_INLINE);
572 
573     m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_streamPipeline);
574     const vk::VkDeviceSize xfbSize = sizeof(float) * 6;
575     const vk::VkBuffer xfbBuffer   = m_xfbBuffer->object();
576     for (uint32_t stream = 0u; stream < 4u; ++stream)
577     {
578         const vk::VkDeviceSize xfbOffset = stream * sizeof(float) * 6;
579         m_vk.cmdBindTransformFeedbackBuffersEXT(*m_cmdBuffer, stream, 1u, &xfbBuffer, &xfbOffset, &xfbSize);
580         m_vk.cmdPushConstants(*m_cmdBuffer, *m_streamPipelineLayout, vk::VK_SHADER_STAGE_GEOMETRY_BIT, 0u, sizeof(int),
581                               &stream);
582 
583         conditionalRenderingBeginInfo.offset = sizeof(uint32_t) * (stream % 2);
584         m_vk.cmdBeginConditionalRenderingEXT(*m_cmdBuffer, &conditionalRenderingBeginInfo);
585         m_vk.cmdBeginTransformFeedbackEXT(*m_cmdBuffer, 0u, 0u, DE_NULL, DE_NULL);
586         recordDraw(*m_cmdBuffer, 1u);
587         m_vk.cmdEndTransformFeedbackEXT(*m_cmdBuffer, 0u, 0u, DE_NULL, DE_NULL);
588         m_vk.cmdEndConditionalRenderingEXT(*m_cmdBuffer);
589     }
590     endLegacyRender(*m_cmdBuffer);
591     const vk::VkMemoryBarrier tfMemoryBarrier =
592         vk::makeMemoryBarrier(vk::VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, vk::VK_ACCESS_HOST_READ_BIT);
593     m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
594                             vk::VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
595     endCommandBuffer(m_vk, *m_cmdBuffer);
596     submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
597 
598     invalidateAlloc(m_vk, device, m_xfbBuffer->getBoundMemory());
599 
600     uint32_t *queryBufferPtr = reinterpret_cast<uint32_t *>(m_queryBuffer->getBoundMemory().getHostPtr());
601     float *xfbBufferPtr      = reinterpret_cast<float *>(m_xfbBuffer.get()->getHostPtr());
602 
603     if (queryBufferPtr[0] != 0)
604     {
605         log << tcu::TestLog::Message << "Occlusion query 0 expected result was 0, but query reported "
606             << queryBufferPtr[0] << tcu::TestLog::EndMessage;
607     }
608     else if (queryBufferPtr[1] == 0)
609     {
610         log << tcu::TestLog::Message << "Occlusion query 1 expected result was not 0, but query reported "
611             << queryBufferPtr[1] << tcu::TestLog::EndMessage;
612     }
613     for (uint32_t i = 0; i < 24; ++i)
614     {
615         float expected = 0.0f;
616         if (i >= 6 && i < 12)
617             expected = 2.0f;
618         else if (i >= 18)
619             expected = 4.0f;
620         if (xfbBufferPtr[i] != expected)
621         {
622             log << tcu::TestLog::Message << "Expected value at index " << i << "was " << expected
623                 << ", but actual value was " << xfbBufferPtr[i] << tcu::TestLog::EndMessage;
624             return tcu::TestStatus::fail("Fail");
625         }
626     }
627 
628     return tcu::TestStatus::pass("Pass");
629 }
630 
631 struct AddProgramsDraw
632 {
initvkt::conditional::__anonca6804f20111::AddProgramsDraw633     void init(vk::SourceCollections &sources, ConditionalTestSpec testParams) const
634     {
635         DE_UNREF(testParams);
636 
637         const char *const vertexShader = "#version 450\n"
638 
639                                          "layout(location = 0) in vec4 in_position;\n"
640                                          "layout(location = 1) in vec4 in_color;\n"
641 
642                                          "layout(location = 0) out vec4 out_color;\n"
643                                          "out gl_PerVertex{ vec4 gl_Position; };\n"
644 
645                                          "void main() {\n"
646                                          "    gl_Position = in_position;\n"
647                                          "    out_color = in_color;\n"
648                                          "}\n";
649 
650         sources.glslSources.add("VertexFetch.vert") << glu::VertexSource(vertexShader);
651 
652         for (uint32_t i = 0; i < 2; ++i)
653         {
654             std::string geometryShader =
655                 "#version 450\n"
656 
657                 "layout (points) in;\n"
658                 "layout(points, max_vertices = 1) out;\n"
659                 "layout(location = 0, stream = 0, xfb_offset = 0, xfb_stride = 4, xfb_buffer = 0) out float output1;\n"
660                 "layout(location = 1, stream = 1, xfb_offset = 0, xfb_stride = 4, xfb_buffer = 1) out float output2;\n"
661                 "layout(location = 2, stream = 2, xfb_offset = 0, xfb_stride = 4, xfb_buffer = 2) out float output3;\n"
662                 "layout(location = 3, stream = 3, xfb_offset = 0, xfb_stride = 4, xfb_buffer = 3) out float output4;\n"
663                 "layout(push_constant) uniform PushConst {\n"
664                 "    int stream;\n"
665                 "} pushConst;\n"
666 
667                 "void main() {\n"
668                 "    if (pushConst.stream == 0) {\n"
669                 "        output1 = 1.0;\n"
670                 "        EmitStreamVertex(0);\n"
671                 "        EndStreamPrimitive(0);\n"
672                 "    }\n"
673                 "    if (pushConst.stream == 1) {\n"
674                 "        output2 = 2.0;\n"
675                 "        EmitStreamVertex(1);\n"
676                 "        EndStreamPrimitive(1);\n"
677                 "    }\n"
678                 "    if (pushConst.stream == 2) {\n"
679                 "        output3 = 3.0;\n"
680                 "        EmitStreamVertex(2);\n"
681                 "        EndStreamPrimitive(2);\n"
682                 "    }\n"
683                 "    if (pushConst.stream == 3) {\n"
684                 "        output4 = 4.0;\n"
685                 "        EmitStreamVertex(3);\n"
686                 "        EndStreamPrimitive(3);\n"
687                 "    }\n";
688             if (i == 1)
689             {
690                 geometryShader += "gl_PointSize = 1.0f;\n";
691             }
692             geometryShader += "}\n";
693 
694             std::string name = i == 0 ? "VertexFetch.geom" : "VertexFetchWritePoint.geom";
695             sources.glslSources.add(name) << glu::GeometrySource(geometryShader);
696         }
697 
698         const char *const fragmentShader = "#version 450\n"
699 
700                                            "layout(location = 0) in vec4 in_color;\n"
701                                            "layout(location = 0) out vec4 out_color;\n"
702 
703                                            "void main()\n"
704                                            "{\n"
705                                            "    out_color = in_color;\n"
706                                            "}\n";
707 
708         sources.glslSources.add("VertexFetch.frag") << glu::FragmentSource(fragmentShader);
709     }
710 };
711 
712 } // namespace
713 
ConditionalTransformFeedbackTests(tcu::TestContext & testCtx)714 ConditionalTransformFeedbackTests::ConditionalTransformFeedbackTests(tcu::TestContext &testCtx)
715     : TestCaseGroup(testCtx, "transform_feedback")
716 {
717 }
718 
~ConditionalTransformFeedbackTests(void)719 ConditionalTransformFeedbackTests::~ConditionalTransformFeedbackTests(void)
720 {
721 }
722 
init(void)723 void ConditionalTransformFeedbackTests::init(void)
724 {
725     for (uint32_t commandTypeIdx = 0; commandTypeIdx < DRAW_COMMAND_TYPE_DRAW_LAST; ++commandTypeIdx)
726     {
727         const DrawCommandType command = DrawCommandType(commandTypeIdx);
728 
729         ConditionalTestSpec testSpec;
730         testSpec.command                           = command;
731         testSpec.shaders[glu::SHADERTYPE_VERTEX]   = "VertexFetch.vert";
732         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "VertexFetch.frag";
733 
734         addChild(new InstanceFactory1WithSupport<ConditionalTransformFeedbackDraw, ConditionalTestSpec,
735                                                  FunctionSupport1<ConditionalTestSpec>, AddProgramsDraw>(
736             m_testCtx, std::string(getDrawCommandTypeName(command)), AddProgramsDraw(), testSpec,
737             FunctionSupport1<ConditionalTestSpec>::Args(checkSupport, testSpec)));
738     }
739 }
740 
741 } // namespace conditional
742 } // namespace vkt
743