xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/draw/vktDrawShaderDrawParametersTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief VK_KHR_shader_draw_parameters tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktDrawShaderDrawParametersTests.hpp"
25 
26 #include "vktTestCaseUtil.hpp"
27 #include "vktDrawTestCaseUtil.hpp"
28 #include "vktDrawBaseClass.hpp"
29 
30 #include "vkQueryUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 
33 #include "tcuTestLog.hpp"
34 #include "tcuImageCompare.hpp"
35 #include "tcuTextureUtil.hpp"
36 
37 namespace vkt
38 {
39 namespace Draw
40 {
41 namespace
42 {
43 
44 enum TestFlagBits
45 {
46     TEST_FLAG_INSTANCED      = 1u << 0,
47     TEST_FLAG_INDEXED        = 1u << 1,
48     TEST_FLAG_INDIRECT       = 1u << 2,
49     TEST_FLAG_MULTIDRAW      = 1u << 3, //!< multiDrawIndirect
50     TEST_FLAG_FIRST_INSTANCE = 1u << 4, //!< drawIndirectFirstInstance
51 };
52 typedef uint32_t TestFlags;
53 
54 struct FlagsTestSpec : public TestSpecBase
55 {
56     TestFlags flags;
57 
FlagsTestSpecvkt::Draw::__anon633254010111::FlagsTestSpec58     FlagsTestSpec(const SharedGroupParams groupParams_)
59         : TestSpecBase{{}, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, groupParams_}
60     {
61     }
62 };
63 
64 enum Constants
65 {
66     // \note Data layout in buffers (junk data and good data is intertwined).
67     //       Values are largely arbitrary, but we try to avoid "nice" numbers to make sure the test doesn't pass by accident.
68     NUM_VERTICES            = 4,  //!< number of consecutive good vertices
69     NDX_FIRST_VERTEX        = 2,  //!< index of first good vertex data
70     NDX_SECOND_VERTEX       = 9,  //!< index of second good vertex data
71     NDX_FIRST_INDEX         = 11, //!< index of a first good index (in index data)
72     NDX_SECOND_INDEX        = 17, //!< index of a second good index
73     OFFSET_FIRST_INDEX      = 1,  //!< offset added to the first index
74     OFFSET_SECOND_INDEX     = 4,  //!< offset added to the second index
75     MAX_INSTANCE_COUNT      = 3,  //!< max number of draw instances
76     MAX_INDIRECT_DRAW_COUNT = 3,  //!< max drawCount of indirect calls
77 };
78 
79 class DrawTest : public DrawTestsBaseClass
80 {
81 public:
82     typedef FlagsTestSpec TestSpec;
83     DrawTest(Context &context, TestSpec testSpec);
84     tcu::TestStatus iterate(void);
85 
86 private:
87     template <typename T, std::size_t N>
88     void setIndirectCommand(const T (&pCmdData)[N]);
89 
90     void drawReferenceImage(const tcu::PixelBufferAccess &refImage) const;
91 
isInstanced(void) const92     bool isInstanced(void) const
93     {
94         return (m_flags & TEST_FLAG_INSTANCED) != 0;
95     }
isIndexed(void) const96     bool isIndexed(void) const
97     {
98         return (m_flags & TEST_FLAG_INDEXED) != 0;
99     }
isIndirect(void) const100     bool isIndirect(void) const
101     {
102         return (m_flags & TEST_FLAG_INDIRECT) != 0;
103     }
isMultiDraw(void) const104     bool isMultiDraw(void) const
105     {
106         return (m_flags & TEST_FLAG_MULTIDRAW) != 0;
107     }
isFirstInstance(void) const108     bool isFirstInstance(void) const
109     {
110         return (m_flags & TEST_FLAG_FIRST_INSTANCE) != 0;
111     }
112     void draw(vk::VkCommandBuffer cmdBuffer);
113 
114 #ifndef CTS_USES_VULKANSC
115     void beginSecondaryCmdBuffer(vk::VkRenderingFlagsKHR renderingFlags = 0u);
116 #endif // CTS_USES_VULKANSC
117 
118     const TestFlags m_flags;
119     de::SharedPtr<Buffer> m_indexBuffer;
120     de::SharedPtr<Buffer> m_indirectBuffer;
121 };
122 
DrawTest(Context & context,TestSpec testSpec)123 DrawTest::DrawTest(Context &context, TestSpec testSpec)
124     : DrawTestsBaseClass(context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT],
125                          testSpec.groupParams, testSpec.topology)
126     , m_flags(testSpec.flags)
127 {
128     DE_ASSERT(m_topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
129     DE_ASSERT(!isMultiDraw() || isIndirect());
130     DE_ASSERT(!isFirstInstance() || (isIndirect() && isInstanced()));
131 
132     // Vertex data
133     {
134         int refIndex = NDX_FIRST_VERTEX - OFFSET_FIRST_INDEX;
135 
136         m_data.push_back(VertexElementData(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
137         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
138 
139         if (!isIndexed())
140             refIndex = 0;
141 
142         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
143         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
144         m_data.push_back(VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
145         m_data.push_back(VertexElementData(tcu::Vec4(0.3f, 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
146 
147         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
148         m_data.push_back(VertexElementData(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
149         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
150 
151         if (!isIndexed())
152             refIndex = 0;
153 
154         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
155         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
156         m_data.push_back(VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
157         m_data.push_back(VertexElementData(tcu::Vec4(0.3f, 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
158 
159         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
160         m_data.push_back(VertexElementData(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
161 
162         // Make sure constants are up to date
163         DE_ASSERT(m_data.size() == NDX_SECOND_VERTEX + NUM_VERTICES + 2);
164         DE_ASSERT(NDX_SECOND_VERTEX - NDX_FIRST_VERTEX - NUM_VERTICES == 3);
165     }
166 
167     if (isIndirect())
168     {
169         const std::size_t indirectBufferSize =
170             MAX_INDIRECT_DRAW_COUNT * 32; // space for COUNT commands plus some gratuitous padding
171         m_indirectBuffer = Buffer::createAndAlloc(
172             m_vk, m_context.getDevice(), BufferCreateInfo(indirectBufferSize, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
173             m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
174 
175         deMemset(m_indirectBuffer->getBoundMemory().getHostPtr(), 0, indirectBufferSize);
176         vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory().getMemory(),
177                                    m_indirectBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
178     }
179 
180     if (isIndexed())
181     {
182         DE_ASSERT(NDX_FIRST_INDEX + NUM_VERTICES <= NDX_SECOND_INDEX);
183         const std::size_t indexBufferSize = sizeof(uint32_t) * (NDX_SECOND_INDEX + NUM_VERTICES);
184         m_indexBuffer                     = Buffer::createAndAlloc(m_vk, m_context.getDevice(),
185                                                                    BufferCreateInfo(indexBufferSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
186                                                                    m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
187         uint32_t *indices                 = static_cast<uint32_t *>(m_indexBuffer->getBoundMemory().getHostPtr());
188 
189         deMemset(indices, 0, indexBufferSize);
190 
191         for (int i = 0; i < NUM_VERTICES; i++)
192         {
193             indices[NDX_FIRST_INDEX + i]  = static_cast<uint32_t>(NDX_FIRST_VERTEX + i) - OFFSET_FIRST_INDEX;
194             indices[NDX_SECOND_INDEX + i] = static_cast<uint32_t>(NDX_SECOND_VERTEX + i) - OFFSET_SECOND_INDEX;
195         }
196 
197         vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory().getMemory(),
198                                    m_indexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
199     }
200 
201     initialize();
202 }
203 
204 template <typename T, std::size_t N>
setIndirectCommand(const T (& pCmdData)[N])205 void DrawTest::setIndirectCommand(const T (&pCmdData)[N])
206 {
207     DE_ASSERT(N != 0 && N <= MAX_INDIRECT_DRAW_COUNT);
208 
209     const std::size_t dataSize = N * sizeof(T);
210 
211     deMemcpy(m_indirectBuffer->getBoundMemory().getHostPtr(), pCmdData, dataSize);
212     vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory().getMemory(),
213                                m_indirectBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
214 }
215 
216 //! This function must be kept in sync with the shader.
drawReferenceImage(const tcu::PixelBufferAccess & refImage) const217 void DrawTest::drawReferenceImage(const tcu::PixelBufferAccess &refImage) const
218 {
219     using tcu::IVec4;
220     using tcu::Vec2;
221     using tcu::Vec4;
222 
223     const Vec2 perInstanceOffset[] = {Vec2(0.0f, 0.0f), Vec2(-0.3f, 0.0f), Vec2(0.0f, 0.3f)};
224     const Vec2 perDrawOffset[]     = {Vec2(0.0f, 0.0f), Vec2(-0.3f, -0.3f), Vec2(0.3f, 0.3f)};
225     const Vec4 allColors[]         = {Vec4(1.0f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), Vec4(0.0f, 1.0f, 0.0f, 1.0f)};
226     const int numInstances         = isInstanced() ? MAX_INSTANCE_COUNT : 1;
227     const int numIndirectDraws     = isMultiDraw() ? MAX_INDIRECT_DRAW_COUNT : 1;
228     const int rectWidth            = static_cast<int>(static_cast<float>(WIDTH) * 0.6f / 2.0f);
229     const int rectHeight           = static_cast<int>(static_cast<float>(HEIGHT) * 0.6f / 2.0f);
230 
231     DE_ASSERT(DE_LENGTH_OF_ARRAY(perInstanceOffset) >= numInstances);
232     DE_ASSERT(DE_LENGTH_OF_ARRAY(allColors) >= numInstances && DE_LENGTH_OF_ARRAY(allColors) >= numIndirectDraws);
233     DE_ASSERT(DE_LENGTH_OF_ARRAY(perDrawOffset) >= numIndirectDraws);
234 
235     tcu::clear(refImage, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
236 
237     for (int drawNdx = 0; drawNdx < numIndirectDraws; ++drawNdx)
238         for (int instanceNdx = 0; instanceNdx < numInstances; ++instanceNdx)
239         {
240             const Vec2 offset = perInstanceOffset[instanceNdx] + perDrawOffset[drawNdx];
241             const Vec4 &color = allColors[isMultiDraw() ? drawNdx : instanceNdx];
242             int x             = static_cast<int>(static_cast<float>(WIDTH) * (1.0f - 0.3f + offset.x()) / 2.0f);
243             int y             = static_cast<int>(static_cast<float>(HEIGHT) * (1.0f - 0.3f + offset.y()) / 2.0f);
244 
245             tcu::clear(tcu::getSubregion(refImage, x, y, rectWidth, rectHeight), color);
246         }
247 }
248 
iterate(void)249 tcu::TestStatus DrawTest::iterate(void)
250 {
251     // Draw
252 #ifndef CTS_USES_VULKANSC
253     if (m_groupParams->useSecondaryCmdBuffer)
254     {
255         // record secondary command buffer
256         if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
257         {
258             beginSecondaryCmdBuffer(vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
259             beginDynamicRender(*m_secCmdBuffer);
260         }
261         else
262             beginSecondaryCmdBuffer();
263 
264         draw(*m_secCmdBuffer);
265 
266         if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
267             endDynamicRender(*m_secCmdBuffer);
268 
269         endCommandBuffer(m_vk, *m_secCmdBuffer);
270 
271         // record primary command buffer
272         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
273 
274         preRenderBarriers();
275 
276         if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
277             beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
278 
279         m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
280 
281         if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
282             endDynamicRender(*m_cmdBuffer);
283 
284         endCommandBuffer(m_vk, *m_cmdBuffer);
285     }
286     else if (m_groupParams->useDynamicRendering)
287     {
288         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
289         preRenderBarriers();
290         beginDynamicRender(*m_cmdBuffer);
291         draw(*m_cmdBuffer);
292         endDynamicRender(*m_cmdBuffer);
293         endCommandBuffer(m_vk, *m_cmdBuffer);
294     }
295 #endif // CTS_USES_VULKANSC
296 
297     if (!m_groupParams->useDynamicRendering)
298     {
299         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
300         preRenderBarriers();
301         beginLegacyRender(*m_cmdBuffer);
302         draw(*m_cmdBuffer);
303         endLegacyRender(*m_cmdBuffer);
304         endCommandBuffer(m_vk, *m_cmdBuffer);
305     }
306 
307     // Submit
308     {
309         const vk::VkQueue queue   = m_context.getUniversalQueue();
310         const vk::VkDevice device = m_context.getDevice();
311 
312         submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
313     }
314 
315     // Validate
316     {
317         tcu::TextureLevel referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat),
318                                          static_cast<int>(0.5f + static_cast<float>(WIDTH)),
319                                          static_cast<int>(0.5f + static_cast<float>(HEIGHT)));
320 
321         drawReferenceImage(referenceFrame.getAccess());
322 
323         const vk::VkOffset3D zeroOffset                 = {0, 0, 0};
324         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(
325             m_context.getUniversalQueue(), m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset,
326             WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
327 
328         if (!tcu::fuzzyCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result",
329                                referenceFrame.getAccess(), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
330             return tcu::TestStatus::fail("Rendered image is incorrect");
331         else
332             return tcu::TestStatus::pass("OK");
333     }
334 }
335 
336 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(vk::VkRenderingFlagsKHR renderingFlags)337 void DrawTest::beginSecondaryCmdBuffer(vk::VkRenderingFlagsKHR renderingFlags)
338 {
339     vk::VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo{
340         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
341         DE_NULL,                                                             // const void* pNext;
342         renderingFlags,                                                      // VkRenderingFlagsKHR flags;
343         0u,                                                                  // uint32_t viewMask;
344         1u,                                                                  // uint32_t colorAttachmentCount;
345         &m_colorAttachmentFormat,                                            // const VkFormat* pColorAttachmentFormats;
346         vk::VK_FORMAT_UNDEFINED,                                             // VkFormat depthAttachmentFormat;
347         vk::VK_FORMAT_UNDEFINED,                                             // VkFormat stencilAttachmentFormat;
348         vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
349     };
350     const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo = vk::initVulkanStructure(&inheritanceRenderingInfo);
351 
352     vk::VkCommandBufferUsageFlags usageFlags = vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
353     if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
354         usageFlags |= vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
355 
356     const vk::VkCommandBufferBeginInfo commandBufBeginParams{
357         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
358         DE_NULL,                                         // const void* pNext;
359         usageFlags,                                      // VkCommandBufferUsageFlags flags;
360         &bufferInheritanceInfo};
361 
362     VK_CHECK(m_vk.beginCommandBuffer(*m_secCmdBuffer, &commandBufBeginParams));
363 }
364 #endif // CTS_USES_VULKANSC
365 
draw(vk::VkCommandBuffer cmdBuffer)366 void DrawTest::draw(vk::VkCommandBuffer cmdBuffer)
367 {
368     const vk::VkDeviceSize vertexBufferOffset = 0;
369     const vk::VkBuffer vertexBuffer           = m_vertexBuffer->object();
370 
371     m_vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
372     m_vk.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
373 
374     if (isIndexed())
375         m_vk.cmdBindIndexBuffer(cmdBuffer, m_indexBuffer->object(), 0ull, vk::VK_INDEX_TYPE_UINT32);
376 
377     const uint32_t numInstances = isInstanced() ? MAX_INSTANCE_COUNT : 1;
378 
379     if (isIndirect())
380     {
381         if (isIndexed())
382         {
383             const vk::VkDrawIndexedIndirectCommand commands[]{
384                 // indexCount, instanceCount, firstIndex, vertexOffset, firstInstance
385                 {NUM_VERTICES, numInstances, NDX_FIRST_INDEX, OFFSET_FIRST_INDEX, (isFirstInstance() ? 2u : 0u)},
386                 {NUM_VERTICES, numInstances, NDX_SECOND_INDEX, OFFSET_SECOND_INDEX, (isFirstInstance() ? 1u : 0u)},
387                 {NUM_VERTICES, numInstances, NDX_FIRST_INDEX, OFFSET_FIRST_INDEX, (isFirstInstance() ? 3u : 0u)},
388             };
389             setIndirectCommand(commands);
390         }
391         else
392         {
393             const vk::VkDrawIndirectCommand commands[]{
394                 // vertexCount, instanceCount, firstVertex, firstInstance
395                 {NUM_VERTICES, numInstances, NDX_FIRST_VERTEX, (isFirstInstance() ? 2u : 0u)},
396                 {NUM_VERTICES, numInstances, NDX_SECOND_VERTEX, (isFirstInstance() ? 1u : 0u)},
397                 {NUM_VERTICES, numInstances, NDX_FIRST_VERTEX, (isFirstInstance() ? 3u : 0u)},
398             };
399             setIndirectCommand(commands);
400         }
401     }
402 
403     if (isIndirect())
404     {
405         const uint32_t numIndirectDraws = isMultiDraw() ? MAX_INDIRECT_DRAW_COUNT : 1;
406 
407         if (isIndexed())
408             m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), 0ull, numIndirectDraws,
409                                         sizeof(vk::VkDrawIndexedIndirectCommand));
410         else
411             m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), 0ull, numIndirectDraws,
412                                  sizeof(vk::VkDrawIndirectCommand));
413     }
414     else
415     {
416         const uint32_t firstInstance = 2;
417 
418         if (isIndexed())
419             m_vk.cmdDrawIndexed(cmdBuffer, NUM_VERTICES, numInstances, NDX_FIRST_INDEX, OFFSET_FIRST_INDEX,
420                                 firstInstance);
421         else
422             m_vk.cmdDraw(cmdBuffer, NUM_VERTICES, numInstances, NDX_FIRST_VERTEX, firstInstance);
423     }
424 }
425 
checkSupport(Context & context,DrawTest::TestSpec testSpec)426 void checkSupport(Context &context, DrawTest::TestSpec testSpec)
427 {
428     context.requireDeviceFunctionality("VK_KHR_shader_draw_parameters");
429 
430     // Shader draw parameters is part of Vulkan 1.1 but is optional
431     if (context.contextSupports(vk::ApiVersion(0, 1, 1, 0)))
432     {
433         // Check if shader draw parameters is supported on the physical device.
434         vk::VkPhysicalDeviceShaderDrawParametersFeatures drawParameters = {
435             vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, // sType
436             DE_NULL,                                                               // pNext
437             VK_FALSE                                                               // shaderDrawParameters
438         };
439 
440         vk::VkPhysicalDeviceFeatures features;
441         deMemset(&features, 0, sizeof(vk::VkPhysicalDeviceFeatures));
442 
443         vk::VkPhysicalDeviceFeatures2 featuresExt = {vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, // sType
444                                                      &drawParameters,                                  // pNext
445                                                      features};
446 
447         context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &featuresExt);
448 
449         if (drawParameters.shaderDrawParameters == VK_FALSE)
450             TCU_THROW(NotSupportedError, "shaderDrawParameters feature not supported by the device");
451     }
452 
453     if (testSpec.groupParams->useDynamicRendering)
454         context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
455 
456     if (testSpec.flags & TEST_FLAG_MULTIDRAW)
457         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_DRAW_INDIRECT);
458 
459     if (testSpec.flags & TEST_FLAG_FIRST_INSTANCE)
460         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_DRAW_INDIRECT_FIRST_INSTANCE);
461 }
462 
addDrawCase(tcu::TestCaseGroup * group,DrawTest::TestSpec testSpec,const TestFlags flags)463 void addDrawCase(tcu::TestCaseGroup *group, DrawTest::TestSpec testSpec, const TestFlags flags)
464 {
465     std::ostringstream name;
466     name << "draw";
467 
468     if (flags & TEST_FLAG_INDEXED)
469         name << "_indexed";
470     if (flags & TEST_FLAG_INDIRECT)
471         name << "_indirect";
472     if (flags & TEST_FLAG_INSTANCED)
473         name << "_instanced";
474     if (flags & TEST_FLAG_FIRST_INSTANCE)
475         name << "_first_instance";
476 
477     testSpec.flags |= flags;
478 
479     group->addChild(new InstanceFactory<DrawTest, FunctionSupport1<DrawTest::TestSpec>>(
480         group->getTestContext(), name.str(), testSpec,
481         FunctionSupport1<DrawTest::TestSpec>::Args(checkSupport, testSpec)));
482 }
483 
484 } // namespace
485 
ShaderDrawParametersTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)486 ShaderDrawParametersTests::ShaderDrawParametersTests(tcu::TestContext &testCtx, const SharedGroupParams groupParams)
487     : TestCaseGroup(testCtx, "shader_draw_parameters")
488     , m_groupParams(groupParams)
489 {
490 }
491 
init(void)492 void ShaderDrawParametersTests::init(void)
493 {
494     {
495         DrawTest::TestSpec testSpec(m_groupParams);
496         testSpec.shaders[glu::SHADERTYPE_VERTEX]   = "vulkan/draw/VertexFetchShaderDrawParameters.vert";
497         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
498         testSpec.topology                          = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
499         testSpec.flags                             = 0;
500 
501         de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "base_vertex"));
502         addDrawCase(group.get(), testSpec, 0);
503         addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
504         addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT);
505         addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INDIRECT);
506         addChild(group.release());
507     }
508     {
509         DrawTest::TestSpec testSpec(m_groupParams);
510         testSpec.shaders[glu::SHADERTYPE_VERTEX]   = "vulkan/draw/VertexFetchShaderDrawParameters.vert";
511         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
512         testSpec.topology                          = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
513         testSpec.flags                             = TEST_FLAG_INSTANCED;
514 
515         de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "base_instance"));
516         addDrawCase(group.get(), testSpec, 0);
517         addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
518         addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT);
519         addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT | TEST_FLAG_FIRST_INSTANCE);
520         addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INDIRECT);
521         addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INDIRECT | TEST_FLAG_FIRST_INSTANCE);
522         addChild(group.release());
523     }
524     {
525         DrawTest::TestSpec testSpec(m_groupParams);
526         testSpec.shaders[glu::SHADERTYPE_VERTEX]   = "vulkan/draw/VertexFetchShaderDrawParametersDrawIndex.vert";
527         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
528         testSpec.topology                          = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
529         testSpec.flags                             = TEST_FLAG_INDIRECT | TEST_FLAG_MULTIDRAW;
530 
531         de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "draw_index"));
532         addDrawCase(group.get(), testSpec, 0);
533         addDrawCase(group.get(), testSpec, TEST_FLAG_INSTANCED);
534         addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
535         addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INSTANCED);
536         addChild(group.release());
537     }
538 }
539 
540 } // namespace Draw
541 } // namespace vkt
542