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
59 enum Constants
60 {
61 // \note Data layout in buffers (junk data and good data is intertwined).
62 // Values are largely arbitrary, but we try to avoid "nice" numbers to make sure the test doesn't pass by accident.
63 NUM_VERTICES = 4, //!< number of consecutive good vertices
64 NDX_FIRST_VERTEX = 2, //!< index of first good vertex data
65 NDX_SECOND_VERTEX = 9, //!< index of second good vertex data
66 NDX_FIRST_INDEX = 11, //!< index of a first good index (in index data)
67 NDX_SECOND_INDEX = 17, //!< index of a second good index
68 OFFSET_FIRST_INDEX = 1, //!< offset added to the first index
69 OFFSET_SECOND_INDEX = 4, //!< offset added to the second index
70 MAX_INSTANCE_COUNT = 3, //!< max number of draw instances
71 MAX_INDIRECT_DRAW_COUNT = 3, //!< max drawCount of indirect calls
72 };
73
74 class DrawTest : public DrawTestsBaseClass
75 {
76 public:
77 typedef FlagsTestSpec TestSpec;
78 DrawTest (Context &context, TestSpec testSpec);
79 tcu::TestStatus iterate (void);
80
81 private:
82 template<typename T, std::size_t N>
83 void setIndirectCommand (const T (&pCmdData)[N]);
84
85 void drawReferenceImage (const tcu::PixelBufferAccess& refImage) const;
86
isInstanced(void) const87 bool isInstanced (void) const { return (m_flags & TEST_FLAG_INSTANCED) != 0; }
isIndexed(void) const88 bool isIndexed (void) const { return (m_flags & TEST_FLAG_INDEXED) != 0; }
isIndirect(void) const89 bool isIndirect (void) const { return (m_flags & TEST_FLAG_INDIRECT) != 0; }
isMultiDraw(void) const90 bool isMultiDraw (void) const { return (m_flags & TEST_FLAG_MULTIDRAW) != 0; }
isFirstInstance(void) const91 bool isFirstInstance (void) const { return (m_flags & TEST_FLAG_FIRST_INSTANCE) != 0; }
92
93 const TestFlags m_flags;
94 de::SharedPtr<Buffer> m_indexBuffer;
95 de::SharedPtr<Buffer> m_indirectBuffer;
96 };
97
DrawTest(Context & context,TestSpec testSpec)98 DrawTest::DrawTest (Context &context, TestSpec testSpec)
99 : DrawTestsBaseClass(context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], testSpec.useDynamicRendering, testSpec.topology)
100 , m_flags (testSpec.flags)
101 {
102 DE_ASSERT(m_topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
103 DE_ASSERT(!isMultiDraw() || isIndirect());
104 DE_ASSERT(!isFirstInstance() || (isIndirect() && isInstanced()));
105
106 // Vertex data
107 {
108 int refIndex = NDX_FIRST_VERTEX - OFFSET_FIRST_INDEX;
109
110 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
111 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
112
113 if (!isIndexed())
114 refIndex = 0;
115
116 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
117 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
118 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
119 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
120
121 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
122 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
123 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
124
125 if (!isIndexed())
126 refIndex = 0;
127
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 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
131 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.3f, 1.0f, 1.0f), tcu::Vec4(1.0f), refIndex++));
132
133 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
134 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f), -1));
135
136 // Make sure constants are up to date
137 DE_ASSERT(m_data.size() == NDX_SECOND_VERTEX + NUM_VERTICES + 2);
138 DE_ASSERT(NDX_SECOND_VERTEX - NDX_FIRST_VERTEX - NUM_VERTICES == 3);
139 }
140
141 if (isIndirect())
142 {
143 const std::size_t indirectBufferSize = MAX_INDIRECT_DRAW_COUNT * 32; // space for COUNT commands plus some gratuitous padding
144 m_indirectBuffer = Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(indirectBufferSize, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
145 m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
146
147 deMemset(m_indirectBuffer->getBoundMemory().getHostPtr(), 0, indirectBufferSize);
148 vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory().getMemory(), m_indirectBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
149 }
150
151 if (isIndexed())
152 {
153 DE_ASSERT(NDX_FIRST_INDEX + NUM_VERTICES <= NDX_SECOND_INDEX);
154 const std::size_t indexBufferSize = sizeof(deUint32) * (NDX_SECOND_INDEX + NUM_VERTICES);
155 m_indexBuffer = Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(indexBufferSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
156 m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
157 deUint32* indices = static_cast<deUint32*>(m_indexBuffer->getBoundMemory().getHostPtr());
158
159 deMemset(indices, 0, indexBufferSize);
160
161 for (int i = 0; i < NUM_VERTICES; i++)
162 {
163 indices[NDX_FIRST_INDEX + i] = static_cast<deUint32>(NDX_FIRST_VERTEX + i) - OFFSET_FIRST_INDEX;
164 indices[NDX_SECOND_INDEX + i] = static_cast<deUint32>(NDX_SECOND_VERTEX + i) - OFFSET_SECOND_INDEX;
165 }
166
167 vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory().getMemory(), m_indexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
168 }
169
170 initialize();
171 }
172
173 template<typename T, std::size_t N>
setIndirectCommand(const T (& pCmdData)[N])174 void DrawTest::setIndirectCommand (const T (&pCmdData)[N])
175 {
176 DE_ASSERT(N != 0 && N <= MAX_INDIRECT_DRAW_COUNT);
177
178 const std::size_t dataSize = N * sizeof(T);
179
180 deMemcpy(m_indirectBuffer->getBoundMemory().getHostPtr(), pCmdData, dataSize);
181 vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory().getMemory(), m_indirectBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
182 }
183
184 //! This function must be kept in sync with the shader.
drawReferenceImage(const tcu::PixelBufferAccess & refImage) const185 void DrawTest::drawReferenceImage (const tcu::PixelBufferAccess& refImage) const
186 {
187 using tcu::Vec2;
188 using tcu::Vec4;
189 using tcu::IVec4;
190
191 const Vec2 perInstanceOffset[] = { Vec2(0.0f, 0.0f), Vec2(-0.3f, 0.0f), Vec2(0.0f, 0.3f) };
192 const Vec2 perDrawOffset[] = { Vec2(0.0f, 0.0f), Vec2(-0.3f, -0.3f), Vec2(0.3f, 0.3f) };
193 const Vec4 allColors[] = { Vec4(1.0f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), Vec4(0.0f, 1.0f, 0.0f, 1.0f) };
194 const int numInstances = isInstanced() ? MAX_INSTANCE_COUNT : 1;
195 const int numIndirectDraws = isMultiDraw() ? MAX_INDIRECT_DRAW_COUNT : 1;
196 const int rectWidth = static_cast<int>(static_cast<float>(WIDTH) * 0.6f / 2.0f);
197 const int rectHeight = static_cast<int>(static_cast<float>(HEIGHT) * 0.6f / 2.0f);
198
199 DE_ASSERT(DE_LENGTH_OF_ARRAY(perInstanceOffset) >= numInstances);
200 DE_ASSERT(DE_LENGTH_OF_ARRAY(allColors) >= numInstances && DE_LENGTH_OF_ARRAY(allColors) >= numIndirectDraws);
201 DE_ASSERT(DE_LENGTH_OF_ARRAY(perDrawOffset) >= numIndirectDraws);
202
203 tcu::clear(refImage, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
204
205 for (int drawNdx = 0; drawNdx < numIndirectDraws; ++drawNdx)
206 for (int instanceNdx = 0; instanceNdx < numInstances; ++instanceNdx)
207 {
208 const Vec2 offset = perInstanceOffset[instanceNdx] + perDrawOffset[drawNdx];
209 const Vec4& color = allColors[isMultiDraw() ? drawNdx : instanceNdx];
210 int x = static_cast<int>(static_cast<float>(WIDTH) * (1.0f - 0.3f + offset.x()) / 2.0f);
211 int y = static_cast<int>(static_cast<float>(HEIGHT) * (1.0f - 0.3f + offset.y()) / 2.0f);
212
213 tcu::clear(tcu::getSubregion(refImage, x, y, rectWidth, rectHeight), color);
214 }
215 }
216
iterate(void)217 tcu::TestStatus DrawTest::iterate (void)
218 {
219 // Draw
220 {
221 beginRender();
222
223 const vk::VkDeviceSize vertexBufferOffset = 0;
224 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
225
226 m_vk.cmdBindVertexBuffers (*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
227 m_vk.cmdBindPipeline (*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
228
229 if (isIndexed())
230 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, m_indexBuffer->object(), 0ull, vk::VK_INDEX_TYPE_UINT32);
231
232 const deUint32 numInstances = isInstanced() ? MAX_INSTANCE_COUNT : 1;
233
234 if (isIndirect())
235 {
236 if (isIndexed())
237 {
238 const vk::VkDrawIndexedIndirectCommand commands[] =
239 {
240 // indexCount, instanceCount, firstIndex, vertexOffset, firstInstance
241 { NUM_VERTICES, numInstances, NDX_FIRST_INDEX, OFFSET_FIRST_INDEX, (isFirstInstance() ? 2u : 0u) },
242 { NUM_VERTICES, numInstances, NDX_SECOND_INDEX, OFFSET_SECOND_INDEX, (isFirstInstance() ? 1u : 0u) },
243 { NUM_VERTICES, numInstances, NDX_FIRST_INDEX, OFFSET_FIRST_INDEX, (isFirstInstance() ? 3u : 0u) },
244 };
245 setIndirectCommand(commands);
246 }
247 else
248 {
249 const vk::VkDrawIndirectCommand commands[] =
250 {
251 // vertexCount, instanceCount, firstVertex, firstInstance
252 { NUM_VERTICES, numInstances, NDX_FIRST_VERTEX, (isFirstInstance() ? 2u : 0u) },
253 { NUM_VERTICES, numInstances, NDX_SECOND_VERTEX, (isFirstInstance() ? 1u : 0u) },
254 { NUM_VERTICES, numInstances, NDX_FIRST_VERTEX, (isFirstInstance() ? 3u : 0u) },
255 };
256 setIndirectCommand(commands);
257 }
258 }
259
260 if (isIndirect())
261 {
262 const deUint32 numIndirectDraws = isMultiDraw() ? MAX_INDIRECT_DRAW_COUNT : 1;
263
264 if (isIndexed())
265 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), 0ull, numIndirectDraws, sizeof(vk::VkDrawIndexedIndirectCommand));
266 else
267 m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), 0ull, numIndirectDraws, sizeof(vk::VkDrawIndirectCommand));
268 }
269 else
270 {
271 const deUint32 firstInstance = 2;
272
273 if (isIndexed())
274 m_vk.cmdDrawIndexed(*m_cmdBuffer, NUM_VERTICES, numInstances, NDX_FIRST_INDEX, OFFSET_FIRST_INDEX, firstInstance);
275 else
276 m_vk.cmdDraw(*m_cmdBuffer, NUM_VERTICES, numInstances, NDX_FIRST_VERTEX, firstInstance);
277 }
278
279 endRender();
280 endCommandBuffer(m_vk, *m_cmdBuffer);
281 }
282
283 // Submit
284 {
285 const vk::VkQueue queue = m_context.getUniversalQueue();
286 const vk::VkDevice device = m_context.getDevice();
287
288 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
289 }
290
291 // Validate
292 {
293 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)));
294
295 drawReferenceImage(referenceFrame.getAccess());
296
297 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
298 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(m_context.getUniversalQueue(), m_context.getDefaultAllocator(),
299 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
300
301 if (!tcu::fuzzyCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", referenceFrame.getAccess(), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
302 return tcu::TestStatus::fail("Rendered image is incorrect");
303 else
304 return tcu::TestStatus::pass("OK");
305 }
306 }
307
checkSupport(Context & context,DrawTest::TestSpec testSpec)308 void checkSupport (Context& context, DrawTest::TestSpec testSpec)
309 {
310 context.requireDeviceFunctionality("VK_KHR_shader_draw_parameters");
311
312 // Shader draw parameters is part of Vulkan 1.1 but is optional
313 if (context.contextSupports(vk::ApiVersion(1, 1, 0)) )
314 {
315 // Check if shader draw parameters is supported on the physical device.
316 vk::VkPhysicalDeviceShaderDrawParametersFeatures drawParameters =
317 {
318 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, // sType
319 DE_NULL, // pNext
320 VK_FALSE // shaderDrawParameters
321 };
322
323 vk::VkPhysicalDeviceFeatures features;
324 deMemset(&features, 0, sizeof(vk::VkPhysicalDeviceFeatures));
325
326 vk::VkPhysicalDeviceFeatures2 featuresExt =
327 {
328 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, // sType
329 &drawParameters, // pNext
330 features
331 };
332
333 context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &featuresExt);
334
335 if (drawParameters.shaderDrawParameters == VK_FALSE)
336 TCU_THROW(NotSupportedError, "shaderDrawParameters feature not supported by the device");
337 }
338
339 if (testSpec.useDynamicRendering)
340 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
341
342 if (testSpec.flags & TEST_FLAG_MULTIDRAW)
343 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_DRAW_INDIRECT);
344
345 if (testSpec.flags & TEST_FLAG_FIRST_INSTANCE)
346 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_DRAW_INDIRECT_FIRST_INSTANCE);
347 }
348
addDrawCase(tcu::TestCaseGroup * group,DrawTest::TestSpec testSpec,const TestFlags flags)349 void addDrawCase (tcu::TestCaseGroup* group, DrawTest::TestSpec testSpec, const TestFlags flags)
350 {
351 std::ostringstream name;
352 name << "draw";
353
354 if (flags & TEST_FLAG_INDEXED) name << "_indexed";
355 if (flags & TEST_FLAG_INDIRECT) name << "_indirect";
356 if (flags & TEST_FLAG_INSTANCED) name << "_instanced";
357 if (flags & TEST_FLAG_FIRST_INSTANCE) name << "_first_instance";
358
359 testSpec.flags |= flags;
360
361 group->addChild(new InstanceFactory<DrawTest, FunctionSupport1<DrawTest::TestSpec>>(group->getTestContext(), name.str(), "", testSpec, FunctionSupport1<DrawTest::TestSpec>::Args(checkSupport, testSpec)));
362 }
363
364 } // anonymous
365
ShaderDrawParametersTests(tcu::TestContext & testCtx,bool useDynamicRendering)366 ShaderDrawParametersTests::ShaderDrawParametersTests (tcu::TestContext &testCtx, bool useDynamicRendering)
367 : TestCaseGroup (testCtx, "shader_draw_parameters", "VK_KHR_shader_draw_parameters")
368 , m_useDynamicRendering (useDynamicRendering)
369 {
370 }
371
init(void)372 void ShaderDrawParametersTests::init (void)
373 {
374 {
375 DrawTest::TestSpec testSpec;
376 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchShaderDrawParameters.vert";
377 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
378 testSpec.useDynamicRendering = m_useDynamicRendering;
379 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
380 testSpec.flags = 0;
381
382 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "base_vertex", ""));
383 addDrawCase(group.get(), testSpec, 0);
384 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
385 addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT);
386 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INDIRECT);
387 addChild(group.release());
388 }
389 {
390 DrawTest::TestSpec testSpec;
391 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchShaderDrawParameters.vert";
392 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
393 testSpec.useDynamicRendering = m_useDynamicRendering;
394 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
395 testSpec.flags = TEST_FLAG_INSTANCED;
396
397 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "base_instance", ""));
398 addDrawCase(group.get(), testSpec, 0);
399 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
400 addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT);
401 addDrawCase(group.get(), testSpec, TEST_FLAG_INDIRECT | TEST_FLAG_FIRST_INSTANCE);
402 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INDIRECT);
403 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INDIRECT | TEST_FLAG_FIRST_INSTANCE);
404 addChild(group.release());
405 }
406 {
407 DrawTest::TestSpec testSpec;
408 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchShaderDrawParametersDrawIndex.vert";
409 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
410 testSpec.useDynamicRendering = m_useDynamicRendering;
411 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
412 testSpec.flags = TEST_FLAG_INDIRECT | TEST_FLAG_MULTIDRAW;
413
414 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(getTestContext(), "draw_index", ""));
415 addDrawCase(group.get(), testSpec, 0);
416 addDrawCase(group.get(), testSpec, TEST_FLAG_INSTANCED);
417 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED);
418 addDrawCase(group.get(), testSpec, TEST_FLAG_INDEXED | TEST_FLAG_INSTANCED);
419 addChild(group.release());
420 }
421 }
422
423 } // DrawTests
424 } // vkt
425