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