Merge vk-gl-cts/vulkan-cts-1.0.2 into vk-gl-cts/master
[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
32 #include "tcuTestLog.hpp"
33 #include "tcuImageCompare.hpp"
34 #include "tcuTextureUtil.hpp"
35
36 namespace vkt
37 {
38 namespace Draw
39 {
40 namespace
41 {
42
43 enum TestFlagBits
44 {
45         TEST_FLAG_INSTANCED                     = 1u << 0,
46         TEST_FLAG_INDEXED                       = 1u << 1,
47         TEST_FLAG_INDIRECT                      = 1u << 2,
48         TEST_FLAG_MULTIDRAW                     = 1u << 3,      //!< multiDrawIndirect
49         TEST_FLAG_FIRST_INSTANCE        = 1u << 4,      //!< drawIndirectFirstInstance
50 };
51 typedef deUint32 TestFlags;
52
53 struct FlagsTestSpec : public TestSpecBase
54 {
55         TestFlags       flags;
56 };
57
58 inline FlagsTestSpec addFlags (FlagsTestSpec spec, const TestFlags flags)
59 {
60         spec.flags |= flags;
61         return spec;
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
98         const TestFlags                 m_flags;
99         de::SharedPtr<Buffer>   m_indexBuffer;
100         de::SharedPtr<Buffer>   m_indirectBuffer;
101 };
102
103 DrawTest::DrawTest (Context &context, TestSpec testSpec)
104         : DrawTestsBaseClass(context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], testSpec.topology)
105         , m_flags                       (testSpec.flags)
106 {
107         DE_ASSERT(m_topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
108         DE_ASSERT(!isMultiDraw()     || isIndirect());
109         DE_ASSERT(!isFirstInstance() || (isIndirect() && isInstanced()));
110
111         // Requirements
112         {
113                 if (!de::contains(m_context.getDeviceExtensions().begin(), m_context.getDeviceExtensions().end(), std::string("VK_KHR_shader_draw_parameters")))
114                         TCU_THROW(NotSupportedError, "Missing extension: VK_KHR_shader_draw_parameters");
115
116                 if (isMultiDraw() && !m_context.getDeviceFeatures().multiDrawIndirect)
117                         TCU_THROW(NotSupportedError, "Missing feature: multiDrawIndirect");
118
119                 if (isFirstInstance() && !m_context.getDeviceFeatures().drawIndirectFirstInstance)
120                         TCU_THROW(NotSupportedError, "Missing feature: drawIndirectFirstInstance");
121         }
122
123         // Vertex data
124         {
125                 int refIndex = NDX_FIRST_VERTEX - OFFSET_FIRST_INDEX;
126
127                 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
128                 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
129
130                 if (!isIndexed())
131                         refIndex = 0;
132
133                 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
134                 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
135                 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
136                 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
137
138                 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
139                 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
140                 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
141
142                 if (!isIndexed())
143                         refIndex = 0;
144
145                 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
146                 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
147                 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
148                 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
149
150                 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
151                 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
152
153                 // Make sure constants are up to date
154                 DE_ASSERT(m_data.size() == NDX_SECOND_VERTEX + NUM_VERTICES + 2);
155                 DE_ASSERT(NDX_SECOND_VERTEX - NDX_FIRST_VERTEX - NUM_VERTICES == 3);
156         }
157
158         if (isIndirect())
159         {
160                 const std::size_t       indirectBufferSize      = MAX_INDIRECT_DRAW_COUNT * 32; // space for COUNT commands plus some gratuitous padding
161                                                         m_indirectBuffer        = Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(indirectBufferSize, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
162                                                                                                   m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
163
164                 deMemset(m_indirectBuffer->getBoundMemory().getHostPtr(), 0, indirectBufferSize);
165                 vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory().getMemory(), m_indirectBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
166         }
167
168         if (isIndexed())
169         {
170                 DE_ASSERT(NDX_FIRST_INDEX + NUM_VERTICES <= NDX_SECOND_INDEX);
171                 const std::size_t       indexBufferSize = sizeof(deUint32) * (NDX_SECOND_INDEX + NUM_VERTICES);
172                                                         m_indexBuffer   = Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(indexBufferSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
173                                                                                                                                          m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
174                 deUint32*                       indices                 = static_cast<deUint32*>(m_indexBuffer->getBoundMemory().getHostPtr());
175
176                 deMemset(indices, 0, indexBufferSize);
177
178                 for (int i = 0; i < NUM_VERTICES; i++)
179                 {
180                         indices[NDX_FIRST_INDEX  + i] = static_cast<deUint32>(NDX_FIRST_VERTEX  + i) - OFFSET_FIRST_INDEX;
181                         indices[NDX_SECOND_INDEX + i] = static_cast<deUint32>(NDX_SECOND_VERTEX + i) - OFFSET_SECOND_INDEX;
182                 }
183
184                 vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory().getMemory(), m_indexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
185         }
186
187         initialize();
188 }
189
190 template<typename T, std::size_t N>
191 void DrawTest::setIndirectCommand (const T (&pCmdData)[N])
192 {
193         DE_ASSERT(N != 0 && N <= MAX_INDIRECT_DRAW_COUNT);
194
195         const std::size_t dataSize = N * sizeof(T);
196
197         deMemcpy(m_indirectBuffer->getBoundMemory().getHostPtr(), pCmdData, dataSize);
198         vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory().getMemory(), m_indirectBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
199 }
200
201 //! This function must be kept in sync with the shader.
202 void DrawTest::drawReferenceImage (const tcu::PixelBufferAccess& refImage) const
203 {
204         using tcu::Vec2;
205         using tcu::Vec4;
206         using tcu::IVec4;
207
208         const Vec2      perInstanceOffset[]     = { Vec2(0.0f, 0.0f), Vec2(-0.3f,  0.0f), Vec2(0.0f, 0.3f) };
209         const Vec2      perDrawOffset[]         = { Vec2(0.0f, 0.0f), Vec2(-0.3f, -0.3f), Vec2(0.3f, 0.3f) };
210         const Vec4      allColors[]                     = { Vec4(1.0f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), Vec4(0.0f, 1.0f, 0.0f, 1.0f) };
211         const int       numInstances            = isInstanced() ? MAX_INSTANCE_COUNT            : 1;
212         const int       numIndirectDraws        = isMultiDraw() ? MAX_INDIRECT_DRAW_COUNT       : 1;
213         const int       rectWidth                       = static_cast<int>(WIDTH  * 0.6f / 2.0f);
214         const int       rectHeight                      = static_cast<int>(HEIGHT * 0.6f / 2.0f);
215
216         DE_ASSERT(DE_LENGTH_OF_ARRAY(perInstanceOffset) >= numInstances);
217         DE_ASSERT(DE_LENGTH_OF_ARRAY(allColors) >= numInstances && DE_LENGTH_OF_ARRAY(allColors) >= numIndirectDraws);
218         DE_ASSERT(DE_LENGTH_OF_ARRAY(perDrawOffset) >= numIndirectDraws);
219
220         tcu::clear(refImage, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
221
222         for (int drawNdx     = 0; drawNdx     < numIndirectDraws; ++drawNdx)
223         for (int instanceNdx = 0; instanceNdx < numInstances;     ++instanceNdx)
224         {
225                 const Vec2      offset  = perInstanceOffset[instanceNdx] + perDrawOffset[drawNdx];
226                 const Vec4&     color   = allColors[isMultiDraw() ? drawNdx : instanceNdx];
227                 int                     x               = static_cast<int>(WIDTH  * (1.0f - 0.3f + offset.x()) / 2.0f);
228                 int                     y               = static_cast<int>(HEIGHT * (1.0f - 0.3f + offset.y()) / 2.0f);
229
230                 tcu::clear(tcu::getSubregion(refImage, x, y, rectWidth, rectHeight), color);
231         }
232 }
233
234 tcu::TestStatus DrawTest::iterate (void)
235 {
236         // Draw
237         {
238                 beginRenderPass();
239
240                 const vk::VkDeviceSize  vertexBufferOffset      = 0;
241                 const vk::VkBuffer              vertexBuffer            = m_vertexBuffer->object();
242
243                 m_vk.cmdBindVertexBuffers       (*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
244                 m_vk.cmdBindPipeline            (*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
245
246                 if (isIndexed())
247                         m_vk.cmdBindIndexBuffer(*m_cmdBuffer, m_indexBuffer->object(), 0ull, vk::VK_INDEX_TYPE_UINT32);
248
249                 const deUint32                  numInstances            = isInstanced() ? MAX_INSTANCE_COUNT : 1;
250
251                 if (isIndirect())
252                 {
253                         if (isIndexed())
254                         {
255                                 const vk::VkDrawIndexedIndirectCommand commands[] =
256                                 {
257                                         // indexCount, instanceCount, firstIndex, vertexOffset, firstInstance
258                                         { NUM_VERTICES, numInstances,   NDX_FIRST_INDEX,        OFFSET_FIRST_INDEX,             (isFirstInstance() ? 2u : 0u) },
259                                         { NUM_VERTICES, numInstances,   NDX_SECOND_INDEX,       OFFSET_SECOND_INDEX,    (isFirstInstance() ? 1u : 0u) },
260                                         { NUM_VERTICES, numInstances,   NDX_FIRST_INDEX,        OFFSET_FIRST_INDEX,             (isFirstInstance() ? 3u : 0u) },
261                                 };
262                                 setIndirectCommand(commands);
263                         }
264                         else
265                         {
266                                 const vk::VkDrawIndirectCommand commands[] =
267                                 {
268                                         // vertexCount, instanceCount, firstVertex, firstInstance
269                                         { NUM_VERTICES, numInstances,   NDX_FIRST_VERTEX,       (isFirstInstance() ? 2u : 0u) },
270                                         { NUM_VERTICES, numInstances,   NDX_SECOND_VERTEX,      (isFirstInstance() ? 1u : 0u) },
271                                         { NUM_VERTICES, numInstances,   NDX_FIRST_VERTEX,       (isFirstInstance() ? 3u : 0u) },
272                                 };
273                                 setIndirectCommand(commands);
274                         }
275                 }
276
277                 if (isIndirect())
278                 {
279                         const deUint32 numIndirectDraws = isMultiDraw() ? MAX_INDIRECT_DRAW_COUNT : 1;
280
281                         if (isIndexed())
282                                 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), 0ull, numIndirectDraws, sizeof(vk::VkDrawIndexedIndirectCommand));
283                         else
284                                 m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), 0ull, numIndirectDraws, sizeof(vk::VkDrawIndirectCommand));
285                 }
286                 else
287                 {
288                         const deUint32 firstInstance = 2;
289
290                         if (isIndexed())
291                                 m_vk.cmdDrawIndexed(*m_cmdBuffer, NUM_VERTICES, numInstances, NDX_FIRST_INDEX, OFFSET_FIRST_INDEX, firstInstance);
292                         else
293                                 m_vk.cmdDraw(*m_cmdBuffer, NUM_VERTICES, numInstances, NDX_FIRST_VERTEX, firstInstance);
294                 }
295
296                 m_vk.cmdEndRenderPass(*m_cmdBuffer);
297                 m_vk.endCommandBuffer(*m_cmdBuffer);
298         }
299
300         // Submit
301         {
302                 const vk::VkQueue               queue           = m_context.getUniversalQueue();
303                 const vk::VkSubmitInfo  submitInfo      =
304                 {
305                         vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,                      // VkStructureType                      sType;
306                         DE_NULL,                                                                        // const void*                          pNext;
307                         0,                                                                                      // deUint32                                     waitSemaphoreCount;
308                         DE_NULL,                                                                        // const VkSemaphore*           pWaitSemaphores;
309                         (const vk::VkPipelineStageFlags*)DE_NULL,
310                         1,                                                                                      // deUint32                                     commandBufferCount;
311                         &m_cmdBuffer.get(),                                                     // const VkCommandBuffer*       pCommandBuffers;
312                         0,                                                                                      // deUint32                                     signalSemaphoreCount;
313                         DE_NULL                                                                         // const VkSemaphore*           pSignalSemaphores;
314                 };
315                 VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
316                 VK_CHECK(m_vk.queueWaitIdle(queue));
317         }
318
319         // Validate
320         {
321                 tcu::TextureLevel referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), static_cast<int>(0.5f + WIDTH), static_cast<int>(0.5f + HEIGHT));
322
323                 drawReferenceImage(referenceFrame.getAccess());
324
325                 const vk::VkOffset3D                            zeroOffset              = { 0, 0, 0 };
326                 const tcu::ConstPixelBufferAccess       renderedFrame   = m_colorTargetImage->readSurface(m_context.getUniversalQueue(), m_context.getDefaultAllocator(),
327                                                                                                                           vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
328
329                 if (!tcu::fuzzyCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", 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 void addDrawCase (tcu::TestCaseGroup* group, const DrawTest::TestSpec testSpec, const TestFlags flags)
337 {
338         std::ostringstream name;
339         name << "draw";
340
341         if (flags & TEST_FLAG_INDEXED)                  name << "_indexed";
342         if (flags & TEST_FLAG_INDIRECT)                 name << "_indirect";
343         if (flags & TEST_FLAG_INSTANCED)                name << "_instanced";
344         if (flags & TEST_FLAG_FIRST_INSTANCE)   name << "_first_instance";
345
346         group->addChild(new InstanceFactory<DrawTest>(group->getTestContext(), name.str(), "", addFlags(testSpec, flags)));
347 }
348
349 }       // anonymous
350
351 ShaderDrawParametersTests::ShaderDrawParametersTests (tcu::TestContext &testCtx)
352         : TestCaseGroup (testCtx, "shader_draw_parameters", "VK_KHR_shader_draw_parameters")
353 {
354 }
355
356 void ShaderDrawParametersTests::init (void)
357 {
358         {
359                 DrawTest::TestSpec testSpec;
360                 testSpec.shaders[glu::SHADERTYPE_VERTEX]        = "vulkan/draw/VertexFetchShaderDrawParameters.vert";
361                 testSpec.shaders[glu::SHADERTYPE_FRAGMENT]      = "vulkan/draw/VertexFetch.frag";
362                 testSpec.topology                                                       = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
363                 testSpec.flags                                                          = 0;
364
365                 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "base_vertex", ""));
366                 addDrawCase(group.get(), testSpec, 0);
367                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
368                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT);
369                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INDIRECT);
370                 addChild(group.release());
371         }
372         {
373                 DrawTest::TestSpec testSpec;
374                 testSpec.shaders[glu::SHADERTYPE_VERTEX]        = "vulkan/draw/VertexFetchShaderDrawParameters.vert";
375                 testSpec.shaders[glu::SHADERTYPE_FRAGMENT]      = "vulkan/draw/VertexFetch.frag";
376                 testSpec.topology                                                       = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
377                 testSpec.flags                                                          = TEST_FLAG_INSTANCED;
378
379                 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "base_instance", ""));
380                 addDrawCase(group.get(), testSpec, 0);
381                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
382                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT);
383                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT | TEST_FLAG_FIRST_INSTANCE);
384                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED  | TEST_FLAG_INDIRECT);
385                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED  | TEST_FLAG_INDIRECT | TEST_FLAG_FIRST_INSTANCE);
386                 addChild(group.release());
387         }
388         {
389                 DrawTest::TestSpec testSpec;
390                 testSpec.shaders[glu::SHADERTYPE_VERTEX]        = "vulkan/draw/VertexFetchShaderDrawParametersDrawIndex.vert";
391                 testSpec.shaders[glu::SHADERTYPE_FRAGMENT]      = "vulkan/draw/VertexFetch.frag";
392                 testSpec.topology                                                       = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
393                 testSpec.flags                                                          = TEST_FLAG_INDIRECT | TEST_FLAG_MULTIDRAW;
394
395                 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "draw_index", ""));
396                 addDrawCase(group.get(), testSpec, 0);
397                 addDrawCase(group.get(), testSpec, TEST_FLAG_INSTANCED);
398                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
399                 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INSTANCED);
400                 addChild(group.release());
401         }
402 }
403
404 }       // DrawTests
405 }       // vkt