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