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