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
addFlags(FlagsTestSpec spec,const TestFlags flags)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
isInstanced(void) const92 bool isInstanced (void) const { return (m_flags & TEST_FLAG_INSTANCED) != 0; }
isIndexed(void) const93 bool isIndexed (void) const { return (m_flags & TEST_FLAG_INDEXED) != 0; }
isIndirect(void) const94 bool isIndirect (void) const { return (m_flags & TEST_FLAG_INDIRECT) != 0; }
isMultiDraw(void) const95 bool isMultiDraw (void) const { return (m_flags & TEST_FLAG_MULTIDRAW) != 0; }
isFirstInstance(void) const96 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
DrawTest(Context & context,TestSpec testSpec)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 (!vk::isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), "VK_KHR_shader_draw_parameters"))
114 TCU_THROW(NotSupportedError, "Missing extension: VK_KHR_shader_draw_parameters");
115
116 // Shader draw parameters is part of Vulkan 1.1 but is optional
117 if ( context.contextSupports(vk::ApiVersion(1, 1, 0)) )
118 {
119 // Check if shader draw parameters is supported on the physical device.
120 vk::VkPhysicalDeviceShaderDrawParameterFeatures drawParameters =
121 {
122 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES, // sType
123 DE_NULL, // pNext
124 VK_FALSE // shaderDrawParameters
125 };
126 vk::VkPhysicalDeviceFeatures features;
127 deMemset(&features, 0, sizeof(vk::VkPhysicalDeviceFeatures));
128
129 vk::VkPhysicalDeviceFeatures2 featuresExt =
130 {
131 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, // sType
132 &drawParameters, // pNext
133 features
134 };
135
136 context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &featuresExt);
137
138 if (drawParameters.shaderDrawParameters == VK_FALSE)
139 TCU_THROW(NotSupportedError, "shaderDrawParameters feature not supported by the device");
140 }
141
142 if (isMultiDraw() && !m_context.getDeviceFeatures().multiDrawIndirect)
143 TCU_THROW(NotSupportedError, "Missing feature: multiDrawIndirect");
144
145 if (isFirstInstance() && !m_context.getDeviceFeatures().drawIndirectFirstInstance)
146 TCU_THROW(NotSupportedError, "Missing feature: drawIndirectFirstInstance");
147 }
148
149 // Vertex data
150 {
151 int refIndex = NDX_FIRST_VERTEX - OFFSET_FIRST_INDEX;
152
153 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
154 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
155
156 if (!isIndexed())
157 refIndex = 0;
158
159 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
160 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
161 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
162 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
163
164 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
165 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
166 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
167
168 if (!isIndexed())
169 refIndex = 0;
170
171 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
172 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
173 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
174 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
175
176 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
177 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
178
179 // Make sure constants are up to date
180 DE_ASSERT(m_data.size() == NDX_SECOND_VERTEX + NUM_VERTICES + 2);
181 DE_ASSERT(NDX_SECOND_VERTEX - NDX_FIRST_VERTEX - NUM_VERTICES == 3);
182 }
183
184 if (isIndirect())
185 {
186 const std::size_t indirectBufferSize = MAX_INDIRECT_DRAW_COUNT * 32; // space for COUNT commands plus some gratuitous padding
187 m_indirectBuffer = Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(indirectBufferSize, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
188 m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
189
190 deMemset(m_indirectBuffer->getBoundMemory().getHostPtr(), 0, indirectBufferSize);
191 vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory().getMemory(), m_indirectBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
192 }
193
194 if (isIndexed())
195 {
196 DE_ASSERT(NDX_FIRST_INDEX + NUM_VERTICES <= NDX_SECOND_INDEX);
197 const std::size_t indexBufferSize = sizeof(deUint32) * (NDX_SECOND_INDEX + NUM_VERTICES);
198 m_indexBuffer = Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(indexBufferSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
199 m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
200 deUint32* indices = static_cast<deUint32*>(m_indexBuffer->getBoundMemory().getHostPtr());
201
202 deMemset(indices, 0, indexBufferSize);
203
204 for (int i = 0; i < NUM_VERTICES; i++)
205 {
206 indices[NDX_FIRST_INDEX + i] = static_cast<deUint32>(NDX_FIRST_VERTEX + i) - OFFSET_FIRST_INDEX;
207 indices[NDX_SECOND_INDEX + i] = static_cast<deUint32>(NDX_SECOND_VERTEX + i) - OFFSET_SECOND_INDEX;
208 }
209
210 vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory().getMemory(), m_indexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
211 }
212
213 initialize();
214 }
215
216 template<typename T, std::size_t N>
setIndirectCommand(const T (& pCmdData)[N])217 void DrawTest::setIndirectCommand (const T (&pCmdData)[N])
218 {
219 DE_ASSERT(N != 0 && N <= MAX_INDIRECT_DRAW_COUNT);
220
221 const std::size_t dataSize = N * sizeof(T);
222
223 deMemcpy(m_indirectBuffer->getBoundMemory().getHostPtr(), pCmdData, dataSize);
224 vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory().getMemory(), m_indirectBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
225 }
226
227 //! This function must be kept in sync with the shader.
drawReferenceImage(const tcu::PixelBufferAccess & refImage) const228 void DrawTest::drawReferenceImage (const tcu::PixelBufferAccess& refImage) const
229 {
230 using tcu::Vec2;
231 using tcu::Vec4;
232 using tcu::IVec4;
233
234 const Vec2 perInstanceOffset[] = { Vec2(0.0f, 0.0f), Vec2(-0.3f, 0.0f), Vec2(0.0f, 0.3f) };
235 const Vec2 perDrawOffset[] = { Vec2(0.0f, 0.0f), Vec2(-0.3f, -0.3f), Vec2(0.3f, 0.3f) };
236 const Vec4 allColors[] = { Vec4(1.0f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), Vec4(0.0f, 1.0f, 0.0f, 1.0f) };
237 const int numInstances = isInstanced() ? MAX_INSTANCE_COUNT : 1;
238 const int numIndirectDraws = isMultiDraw() ? MAX_INDIRECT_DRAW_COUNT : 1;
239 const int rectWidth = static_cast<int>(WIDTH * 0.6f / 2.0f);
240 const int rectHeight = static_cast<int>(HEIGHT * 0.6f / 2.0f);
241
242 DE_ASSERT(DE_LENGTH_OF_ARRAY(perInstanceOffset) >= numInstances);
243 DE_ASSERT(DE_LENGTH_OF_ARRAY(allColors) >= numInstances && DE_LENGTH_OF_ARRAY(allColors) >= numIndirectDraws);
244 DE_ASSERT(DE_LENGTH_OF_ARRAY(perDrawOffset) >= numIndirectDraws);
245
246 tcu::clear(refImage, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
247
248 for (int drawNdx = 0; drawNdx < numIndirectDraws; ++drawNdx)
249 for (int instanceNdx = 0; instanceNdx < numInstances; ++instanceNdx)
250 {
251 const Vec2 offset = perInstanceOffset[instanceNdx] + perDrawOffset[drawNdx];
252 const Vec4& color = allColors[isMultiDraw() ? drawNdx : instanceNdx];
253 int x = static_cast<int>(WIDTH * (1.0f - 0.3f + offset.x()) / 2.0f);
254 int y = static_cast<int>(HEIGHT * (1.0f - 0.3f + offset.y()) / 2.0f);
255
256 tcu::clear(tcu::getSubregion(refImage, x, y, rectWidth, rectHeight), color);
257 }
258 }
259
iterate(void)260 tcu::TestStatus DrawTest::iterate (void)
261 {
262 // Draw
263 {
264 beginRenderPass();
265
266 const vk::VkDeviceSize vertexBufferOffset = 0;
267 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
268
269 m_vk.cmdBindVertexBuffers (*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
270 m_vk.cmdBindPipeline (*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
271
272 if (isIndexed())
273 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, m_indexBuffer->object(), 0ull, vk::VK_INDEX_TYPE_UINT32);
274
275 const deUint32 numInstances = isInstanced() ? MAX_INSTANCE_COUNT : 1;
276
277 if (isIndirect())
278 {
279 if (isIndexed())
280 {
281 const vk::VkDrawIndexedIndirectCommand commands[] =
282 {
283 // indexCount, instanceCount, firstIndex, vertexOffset, firstInstance
284 { NUM_VERTICES, numInstances, NDX_FIRST_INDEX, OFFSET_FIRST_INDEX, (isFirstInstance() ? 2u : 0u) },
285 { NUM_VERTICES, numInstances, NDX_SECOND_INDEX, OFFSET_SECOND_INDEX, (isFirstInstance() ? 1u : 0u) },
286 { NUM_VERTICES, numInstances, NDX_FIRST_INDEX, OFFSET_FIRST_INDEX, (isFirstInstance() ? 3u : 0u) },
287 };
288 setIndirectCommand(commands);
289 }
290 else
291 {
292 const vk::VkDrawIndirectCommand commands[] =
293 {
294 // vertexCount, instanceCount, firstVertex, firstInstance
295 { NUM_VERTICES, numInstances, NDX_FIRST_VERTEX, (isFirstInstance() ? 2u : 0u) },
296 { NUM_VERTICES, numInstances, NDX_SECOND_VERTEX, (isFirstInstance() ? 1u : 0u) },
297 { NUM_VERTICES, numInstances, NDX_FIRST_VERTEX, (isFirstInstance() ? 3u : 0u) },
298 };
299 setIndirectCommand(commands);
300 }
301 }
302
303 if (isIndirect())
304 {
305 const deUint32 numIndirectDraws = isMultiDraw() ? MAX_INDIRECT_DRAW_COUNT : 1;
306
307 if (isIndexed())
308 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), 0ull, numIndirectDraws, sizeof(vk::VkDrawIndexedIndirectCommand));
309 else
310 m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), 0ull, numIndirectDraws, sizeof(vk::VkDrawIndirectCommand));
311 }
312 else
313 {
314 const deUint32 firstInstance = 2;
315
316 if (isIndexed())
317 m_vk.cmdDrawIndexed(*m_cmdBuffer, NUM_VERTICES, numInstances, NDX_FIRST_INDEX, OFFSET_FIRST_INDEX, firstInstance);
318 else
319 m_vk.cmdDraw(*m_cmdBuffer, NUM_VERTICES, numInstances, NDX_FIRST_VERTEX, firstInstance);
320 }
321
322 m_vk.cmdEndRenderPass(*m_cmdBuffer);
323 m_vk.endCommandBuffer(*m_cmdBuffer);
324 }
325
326 // Submit
327 {
328 const vk::VkQueue queue = m_context.getUniversalQueue();
329 const vk::VkSubmitInfo submitInfo =
330 {
331 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
332 DE_NULL, // const void* pNext;
333 0, // deUint32 waitSemaphoreCount;
334 DE_NULL, // const VkSemaphore* pWaitSemaphores;
335 (const vk::VkPipelineStageFlags*)DE_NULL,
336 1, // deUint32 commandBufferCount;
337 &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
338 0, // deUint32 signalSemaphoreCount;
339 DE_NULL // const VkSemaphore* pSignalSemaphores;
340 };
341 VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
342 VK_CHECK(m_vk.queueWaitIdle(queue));
343 }
344
345 // Validate
346 {
347 tcu::TextureLevel referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), static_cast<int>(0.5f + WIDTH), static_cast<int>(0.5f + HEIGHT));
348
349 drawReferenceImage(referenceFrame.getAccess());
350
351 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
352 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(m_context.getUniversalQueue(), m_context.getDefaultAllocator(),
353 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
354
355 if (!tcu::fuzzyCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", referenceFrame.getAccess(), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
356 return tcu::TestStatus::fail("Rendered image is incorrect");
357 else
358 return tcu::TestStatus::pass("OK");
359 }
360 }
361
addDrawCase(tcu::TestCaseGroup * group,const DrawTest::TestSpec testSpec,const TestFlags flags)362 void addDrawCase (tcu::TestCaseGroup* group, const DrawTest::TestSpec testSpec, const TestFlags flags)
363 {
364 std::ostringstream name;
365 name << "draw";
366
367 if (flags & TEST_FLAG_INDEXED) name << "_indexed";
368 if (flags & TEST_FLAG_INDIRECT) name << "_indirect";
369 if (flags & TEST_FLAG_INSTANCED) name << "_instanced";
370 if (flags & TEST_FLAG_FIRST_INSTANCE) name << "_first_instance";
371
372 group->addChild(new InstanceFactory<DrawTest>(group->getTestContext(), name.str(), "", addFlags(testSpec, flags)));
373 }
374
375 } // anonymous
376
ShaderDrawParametersTests(tcu::TestContext & testCtx)377 ShaderDrawParametersTests::ShaderDrawParametersTests (tcu::TestContext &testCtx)
378 : TestCaseGroup (testCtx, "shader_draw_parameters", "VK_KHR_shader_draw_parameters")
379 {
380 }
381
init(void)382 void ShaderDrawParametersTests::init (void)
383 {
384 {
385 DrawTest::TestSpec testSpec;
386 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchShaderDrawParameters.vert";
387 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
388 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
389 testSpec.flags = 0;
390
391 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "base_vertex", ""));
392 addDrawCase(group.get(), testSpec, 0);
393 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
394 addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT);
395 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INDIRECT);
396 addChild(group.release());
397 }
398 {
399 DrawTest::TestSpec testSpec;
400 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchShaderDrawParameters.vert";
401 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
402 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
403 testSpec.flags = TEST_FLAG_INSTANCED;
404
405 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "base_instance", ""));
406 addDrawCase(group.get(), testSpec, 0);
407 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
408 addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT);
409 addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT | TEST_FLAG_FIRST_INSTANCE);
410 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INDIRECT);
411 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INDIRECT | TEST_FLAG_FIRST_INSTANCE);
412 addChild(group.release());
413 }
414 {
415 DrawTest::TestSpec testSpec;
416 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchShaderDrawParametersDrawIndex.vert";
417 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
418 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
419 testSpec.flags = TEST_FLAG_INDIRECT | TEST_FLAG_MULTIDRAW;
420
421 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "draw_index", ""));
422 addDrawCase(group.get(), testSpec, 0);
423 addDrawCase(group.get(), testSpec, TEST_FLAG_INSTANCED);
424 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
425 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INSTANCED);
426 addChild(group.release());
427 }
428 }
429
430 } // DrawTests
431 } // vkt
432