Fix missing dependency on sparse binds
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / draw / vktDrawShaderDrawParametersTests.cpp
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 deUint32 TestFlags;
53
54 struct FlagsTestSpec : public TestSpecBase
55 {
56         TestFlags       flags;
57
58         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
92         bool                                    isInstanced                             (void) const { return (m_flags & TEST_FLAG_INSTANCED)           != 0; }
93         bool                                    isIndexed                               (void) const { return (m_flags & TEST_FLAG_INDEXED)                     != 0; }
94         bool                                    isIndirect                              (void) const { return (m_flags & TEST_FLAG_INDIRECT)            != 0; }
95         bool                                    isMultiDraw                             (void) const { return (m_flags & TEST_FLAG_MULTIDRAW)           != 0; }
96         bool                                    isFirstInstance                 (void) const { return (m_flags & TEST_FLAG_FIRST_INSTANCE)      != 0; }
97         void                                    draw                                    (vk::VkCommandBuffer cmdBuffer);
98
99 #ifndef CTS_USES_VULKANSC
100         void                                    beginSecondaryCmdBuffer (vk::VkRenderingFlagsKHR renderingFlags = 0u);
101 #endif // CTS_USES_VULKANSC
102
103         const TestFlags                 m_flags;
104         de::SharedPtr<Buffer>   m_indexBuffer;
105         de::SharedPtr<Buffer>   m_indirectBuffer;
106 };
107
108 DrawTest::DrawTest (Context &context, TestSpec testSpec)
109         : DrawTestsBaseClass(context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], testSpec.groupParams, testSpec.topology)
110         , m_flags                       (testSpec.flags)
111 {
112         DE_ASSERT(m_topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
113         DE_ASSERT(!isMultiDraw()     || isIndirect());
114         DE_ASSERT(!isFirstInstance() || (isIndirect() && isInstanced()));
115
116         // Vertex data
117         {
118                 int refIndex = NDX_FIRST_VERTEX - OFFSET_FIRST_INDEX;
119
120                 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
121                 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
122
123                 if (!isIndexed())
124                         refIndex = 0;
125
126                 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
127                 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
128                 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
129                 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
130
131                 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
132                 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
133                 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
134
135                 if (!isIndexed())
136                         refIndex = 0;
137
138                 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
139                 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
140                 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
141                 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
142
143                 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
144                 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
145
146                 // Make sure constants are up to date
147                 DE_ASSERT(m_data.size() == NDX_SECOND_VERTEX + NUM_VERTICES + 2);
148                 DE_ASSERT(NDX_SECOND_VERTEX - NDX_FIRST_VERTEX - NUM_VERTICES == 3);
149         }
150
151         if (isIndirect())
152         {
153                 const std::size_t       indirectBufferSize      = MAX_INDIRECT_DRAW_COUNT * 32; // space for COUNT commands plus some gratuitous padding
154                                                         m_indirectBuffer        = Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(indirectBufferSize, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
155                                                                                                   m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
156
157                 deMemset(m_indirectBuffer->getBoundMemory().getHostPtr(), 0, indirectBufferSize);
158                 vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory().getMemory(), m_indirectBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
159         }
160
161         if (isIndexed())
162         {
163                 DE_ASSERT(NDX_FIRST_INDEX + NUM_VERTICES <= NDX_SECOND_INDEX);
164                 const std::size_t       indexBufferSize = sizeof(deUint32) * (NDX_SECOND_INDEX + NUM_VERTICES);
165                                                         m_indexBuffer   = Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(indexBufferSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
166                                                                                                                                          m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
167                 deUint32*                       indices                 = static_cast<deUint32*>(m_indexBuffer->getBoundMemory().getHostPtr());
168
169                 deMemset(indices, 0, indexBufferSize);
170
171                 for (int i = 0; i < NUM_VERTICES; i++)
172                 {
173                         indices[NDX_FIRST_INDEX  + i] = static_cast<deUint32>(NDX_FIRST_VERTEX  + i) - OFFSET_FIRST_INDEX;
174                         indices[NDX_SECOND_INDEX + i] = static_cast<deUint32>(NDX_SECOND_VERTEX + i) - OFFSET_SECOND_INDEX;
175                 }
176
177                 vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory().getMemory(), m_indexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
178         }
179
180         initialize();
181 }
182
183 template<typename T, std::size_t N>
184 void DrawTest::setIndirectCommand (const T (&pCmdData)[N])
185 {
186         DE_ASSERT(N != 0 && N <= MAX_INDIRECT_DRAW_COUNT);
187
188         const std::size_t dataSize = N * sizeof(T);
189
190         deMemcpy(m_indirectBuffer->getBoundMemory().getHostPtr(), pCmdData, dataSize);
191         vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory().getMemory(), m_indirectBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
192 }
193
194 //! This function must be kept in sync with the shader.
195 void DrawTest::drawReferenceImage (const tcu::PixelBufferAccess& refImage) const
196 {
197         using tcu::Vec2;
198         using tcu::Vec4;
199         using tcu::IVec4;
200
201         const Vec2      perInstanceOffset[]     = { Vec2(0.0f, 0.0f), Vec2(-0.3f,  0.0f), Vec2(0.0f, 0.3f) };
202         const Vec2      perDrawOffset[]         = { Vec2(0.0f, 0.0f), Vec2(-0.3f, -0.3f), Vec2(0.3f, 0.3f) };
203         const Vec4      allColors[]                     = { Vec4(1.0f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), Vec4(0.0f, 1.0f, 0.0f, 1.0f) };
204         const int       numInstances            = isInstanced() ? MAX_INSTANCE_COUNT            : 1;
205         const int       numIndirectDraws        = isMultiDraw() ? MAX_INDIRECT_DRAW_COUNT       : 1;
206         const int       rectWidth                       = static_cast<int>(static_cast<float>(WIDTH)  * 0.6f / 2.0f);
207         const int       rectHeight                      = static_cast<int>(static_cast<float>(HEIGHT) * 0.6f / 2.0f);
208
209         DE_ASSERT(DE_LENGTH_OF_ARRAY(perInstanceOffset) >= numInstances);
210         DE_ASSERT(DE_LENGTH_OF_ARRAY(allColors) >= numInstances && DE_LENGTH_OF_ARRAY(allColors) >= numIndirectDraws);
211         DE_ASSERT(DE_LENGTH_OF_ARRAY(perDrawOffset) >= numIndirectDraws);
212
213         tcu::clear(refImage, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
214
215         for (int drawNdx     = 0; drawNdx     < numIndirectDraws; ++drawNdx)
216         for (int instanceNdx = 0; instanceNdx < numInstances;     ++instanceNdx)
217         {
218                 const Vec2      offset  = perInstanceOffset[instanceNdx] + perDrawOffset[drawNdx];
219                 const Vec4&     color   = allColors[isMultiDraw() ? drawNdx : instanceNdx];
220                 int                     x               = static_cast<int>(static_cast<float>(WIDTH)  * (1.0f - 0.3f + offset.x()) / 2.0f);
221                 int                     y               = static_cast<int>(static_cast<float>(HEIGHT) * (1.0f - 0.3f + offset.y()) / 2.0f);
222
223                 tcu::clear(tcu::getSubregion(refImage, x, y, rectWidth, rectHeight), color);
224         }
225 }
226
227 tcu::TestStatus DrawTest::iterate (void)
228 {
229         // Draw
230 #ifndef CTS_USES_VULKANSC
231         if (m_groupParams->useSecondaryCmdBuffer)
232         {
233                 // record secondary command buffer
234                 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
235                 {
236                         beginSecondaryCmdBuffer(vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
237                         beginDynamicRender(*m_secCmdBuffer);
238                 }
239                 else
240                         beginSecondaryCmdBuffer();
241
242                 draw(*m_secCmdBuffer);
243
244                 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
245                         endDynamicRender(*m_secCmdBuffer);
246
247                 endCommandBuffer(m_vk, *m_secCmdBuffer);
248
249                 // record primary command buffer
250                 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
251
252                 preRenderBarriers();
253
254                 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
255                         beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
256
257                 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
258
259                 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
260                         endDynamicRender(*m_cmdBuffer);
261
262                 endCommandBuffer(m_vk, *m_cmdBuffer);
263         }
264         else if (m_groupParams->useDynamicRendering)
265         {
266                 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
267                 preRenderBarriers();
268                 beginDynamicRender(*m_cmdBuffer);
269                 draw(*m_cmdBuffer);
270                 endDynamicRender(*m_cmdBuffer);
271                 endCommandBuffer(m_vk, *m_cmdBuffer);
272         }
273 #endif // CTS_USES_VULKANSC
274
275         if (!m_groupParams->useDynamicRendering)
276         {
277                 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
278                 preRenderBarriers();
279                 beginLegacyRender(*m_cmdBuffer);
280                 draw(*m_cmdBuffer);
281                 endLegacyRender(*m_cmdBuffer);
282                 endCommandBuffer(m_vk, *m_cmdBuffer);
283         }
284
285         // Submit
286         {
287                 const vk::VkQueue               queue           = m_context.getUniversalQueue();
288                 const vk::VkDevice              device          = m_context.getDevice();
289
290                 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
291         }
292
293         // Validate
294         {
295                 tcu::TextureLevel referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), static_cast<int>(0.5f + static_cast<float>(WIDTH)), static_cast<int>(0.5f + static_cast<float>(HEIGHT)));
296
297                 drawReferenceImage(referenceFrame.getAccess());
298
299                 const vk::VkOffset3D                            zeroOffset              = { 0, 0, 0 };
300                 const tcu::ConstPixelBufferAccess       renderedFrame   = m_colorTargetImage->readSurface(m_context.getUniversalQueue(), m_context.getDefaultAllocator(),
301                                                                                                                           vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
302
303                 if (!tcu::fuzzyCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", referenceFrame.getAccess(), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
304                         return tcu::TestStatus::fail("Rendered image is incorrect");
305                 else
306                         return tcu::TestStatus::pass("OK");
307         }
308 }
309
310 #ifndef CTS_USES_VULKANSC
311 void DrawTest::beginSecondaryCmdBuffer(vk::VkRenderingFlagsKHR renderingFlags)
312 {
313         vk::VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo
314         {
315                 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR,    // VkStructureType                                      sType;
316                 DE_NULL,                                                                                                                                // const void*                                          pNext;
317                 renderingFlags,                                                                                                                 // VkRenderingFlagsKHR                          flags;
318                 0u,                                                                                                                                             // uint32_t                                                     viewMask;
319                 1u,                                                                                                                                             // uint32_t                                                     colorAttachmentCount;
320                 &m_colorAttachmentFormat,                                                                                               // const VkFormat*                                      pColorAttachmentFormats;
321                 vk::VK_FORMAT_UNDEFINED,                                                                                                // VkFormat                                                     depthAttachmentFormat;
322                 vk::VK_FORMAT_UNDEFINED,                                                                                                // VkFormat                                                     stencilAttachmentFormat;
323                 vk::VK_SAMPLE_COUNT_1_BIT,                                                                                              // VkSampleCountFlagBits                        rasterizationSamples;
324         };
325         const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo = vk::initVulkanStructure(&inheritanceRenderingInfo);
326
327         vk::VkCommandBufferUsageFlags usageFlags = vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
328         if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
329                 usageFlags |= vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
330
331         const vk::VkCommandBufferBeginInfo commandBufBeginParams
332         {
333                 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,                                                // VkStructureType                                      sType;
334                 DE_NULL,                                                                                                                                // const void*                                          pNext;
335                 usageFlags,                                                                                                                             // VkCommandBufferUsageFlags            flags;
336                 &bufferInheritanceInfo
337         };
338
339         VK_CHECK(m_vk.beginCommandBuffer(*m_secCmdBuffer, &commandBufBeginParams));
340 }
341 #endif // CTS_USES_VULKANSC
342
343 void DrawTest::draw(vk::VkCommandBuffer cmdBuffer)
344 {
345         const vk::VkDeviceSize  vertexBufferOffset      = 0;
346         const vk::VkBuffer              vertexBuffer            = m_vertexBuffer->object();
347
348         m_vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
349         m_vk.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
350
351         if (isIndexed())
352                 m_vk.cmdBindIndexBuffer(cmdBuffer, m_indexBuffer->object(), 0ull, vk::VK_INDEX_TYPE_UINT32);
353
354         const deUint32 numInstances = isInstanced() ? MAX_INSTANCE_COUNT : 1;
355
356         if (isIndirect())
357         {
358                 if (isIndexed())
359                 {
360                         const vk::VkDrawIndexedIndirectCommand commands[]
361                         {
362                                 // indexCount, instanceCount, firstIndex, vertexOffset, firstInstance
363                                 { NUM_VERTICES, numInstances,   NDX_FIRST_INDEX,        OFFSET_FIRST_INDEX,             (isFirstInstance() ? 2u : 0u) },
364                                 { NUM_VERTICES, numInstances,   NDX_SECOND_INDEX,       OFFSET_SECOND_INDEX,    (isFirstInstance() ? 1u : 0u) },
365                                 { NUM_VERTICES, numInstances,   NDX_FIRST_INDEX,        OFFSET_FIRST_INDEX,             (isFirstInstance() ? 3u : 0u) },
366                         };
367                         setIndirectCommand(commands);
368                 }
369                 else
370                 {
371                         const vk::VkDrawIndirectCommand commands[]
372                         {
373                                 // vertexCount, instanceCount, firstVertex, firstInstance
374                                 { NUM_VERTICES, numInstances,   NDX_FIRST_VERTEX,       (isFirstInstance() ? 2u : 0u) },
375                                 { NUM_VERTICES, numInstances,   NDX_SECOND_VERTEX,      (isFirstInstance() ? 1u : 0u) },
376                                 { NUM_VERTICES, numInstances,   NDX_FIRST_VERTEX,       (isFirstInstance() ? 3u : 0u) },
377                         };
378                         setIndirectCommand(commands);
379                 }
380         }
381
382         if (isIndirect())
383         {
384                 const deUint32 numIndirectDraws = isMultiDraw() ? MAX_INDIRECT_DRAW_COUNT : 1;
385
386                 if (isIndexed())
387                         m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), 0ull, numIndirectDraws, sizeof(vk::VkDrawIndexedIndirectCommand));
388                 else
389                         m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), 0ull, numIndirectDraws, sizeof(vk::VkDrawIndirectCommand));
390         }
391         else
392         {
393                 const deUint32 firstInstance = 2;
394
395                 if (isIndexed())
396                         m_vk.cmdDrawIndexed(cmdBuffer, NUM_VERTICES, numInstances, NDX_FIRST_INDEX, OFFSET_FIRST_INDEX, firstInstance);
397                 else
398                         m_vk.cmdDraw(cmdBuffer, NUM_VERTICES, numInstances, NDX_FIRST_VERTEX, firstInstance);
399         }
400 }
401
402 void checkSupport (Context& context, DrawTest::TestSpec testSpec)
403 {
404         context.requireDeviceFunctionality("VK_KHR_shader_draw_parameters");
405
406         // Shader draw parameters is part of Vulkan 1.1 but is optional
407         if (context.contextSupports(vk::ApiVersion(0, 1, 1, 0)) )
408         {
409                 // Check if shader draw parameters is supported on the physical device.
410                 vk::VkPhysicalDeviceShaderDrawParametersFeatures        drawParameters  =
411                 {
412                         vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES,  // sType
413                         DE_NULL,                                                                                                                                // pNext
414                         VK_FALSE                                                                                                                                // shaderDrawParameters
415                 };
416
417                 vk::VkPhysicalDeviceFeatures                                            features;
418                 deMemset(&features, 0, sizeof(vk::VkPhysicalDeviceFeatures));
419
420                 vk::VkPhysicalDeviceFeatures2                                           featuresExt             =
421                 {
422                         vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,                                       // sType
423                         &drawParameters,                                                                                                        // pNext
424                         features
425                 };
426
427                 context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &featuresExt);
428
429                 if (drawParameters.shaderDrawParameters == VK_FALSE)
430                         TCU_THROW(NotSupportedError, "shaderDrawParameters feature not supported by the device");
431         }
432
433         if (testSpec.groupParams->useDynamicRendering)
434                 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
435
436         if (testSpec.flags & TEST_FLAG_MULTIDRAW)
437                 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_DRAW_INDIRECT);
438
439         if (testSpec.flags & TEST_FLAG_FIRST_INSTANCE)
440                 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_DRAW_INDIRECT_FIRST_INSTANCE);
441 }
442
443 void addDrawCase (tcu::TestCaseGroup* group, DrawTest::TestSpec testSpec, const TestFlags flags)
444 {
445         std::ostringstream name;
446         name << "draw";
447
448         if (flags & TEST_FLAG_INDEXED)                  name << "_indexed";
449         if (flags & TEST_FLAG_INDIRECT)                 name << "_indirect";
450         if (flags & TEST_FLAG_INSTANCED)                name << "_instanced";
451         if (flags & TEST_FLAG_FIRST_INSTANCE)   name << "_first_instance";
452
453         testSpec.flags |= flags;
454
455         group->addChild(new InstanceFactory<DrawTest, FunctionSupport1<DrawTest::TestSpec>>(group->getTestContext(), name.str(), "", testSpec, FunctionSupport1<DrawTest::TestSpec>::Args(checkSupport, testSpec)));
456 }
457
458 }       // anonymous
459
460 ShaderDrawParametersTests::ShaderDrawParametersTests (tcu::TestContext &testCtx, const SharedGroupParams groupParams)
461         : TestCaseGroup                 (testCtx, "shader_draw_parameters", "VK_KHR_shader_draw_parameters")
462         , m_groupParams                 (groupParams)
463 {
464 }
465
466 void ShaderDrawParametersTests::init (void)
467 {
468         {
469                 DrawTest::TestSpec testSpec(m_groupParams);
470                 testSpec.shaders[glu::SHADERTYPE_VERTEX]        = "vulkan/draw/VertexFetchShaderDrawParameters.vert";
471                 testSpec.shaders[glu::SHADERTYPE_FRAGMENT]      = "vulkan/draw/VertexFetch.frag";
472                 testSpec.topology                                                       = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
473                 testSpec.flags                                                          = 0;
474
475                 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "base_vertex", ""));
476                 addDrawCase(group.get(), testSpec, 0);
477                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
478                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT);
479                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INDIRECT);
480                 addChild(group.release());
481         }
482         {
483                 DrawTest::TestSpec testSpec(m_groupParams);
484                 testSpec.shaders[glu::SHADERTYPE_VERTEX]        = "vulkan/draw/VertexFetchShaderDrawParameters.vert";
485                 testSpec.shaders[glu::SHADERTYPE_FRAGMENT]      = "vulkan/draw/VertexFetch.frag";
486                 testSpec.topology                                                       = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
487                 testSpec.flags                                                          = TEST_FLAG_INSTANCED;
488
489                 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "base_instance", ""));
490                 addDrawCase(group.get(), testSpec, 0);
491                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
492                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT);
493                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT | TEST_FLAG_FIRST_INSTANCE);
494                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED  | TEST_FLAG_INDIRECT);
495                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED  | TEST_FLAG_INDIRECT | TEST_FLAG_FIRST_INSTANCE);
496                 addChild(group.release());
497         }
498         {
499                 DrawTest::TestSpec testSpec(m_groupParams);
500                 testSpec.shaders[glu::SHADERTYPE_VERTEX]        = "vulkan/draw/VertexFetchShaderDrawParametersDrawIndex.vert";
501                 testSpec.shaders[glu::SHADERTYPE_FRAGMENT]      = "vulkan/draw/VertexFetch.frag";
502                 testSpec.topology                                                       = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
503                 testSpec.flags                                                          = TEST_FLAG_INDIRECT | TEST_FLAG_MULTIDRAW;
504
505                 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "draw_index", ""));
506                 addDrawCase(group.get(), testSpec, 0);
507                 addDrawCase(group.get(), testSpec, TEST_FLAG_INSTANCED);
508                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
509                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INSTANCED);
510                 addChild(group.release());
511         }
512 }
513
514 }       // DrawTests
515 }       // vkt