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
FlagsTestSpecvkt::Draw::__anonbf3f0d290111::FlagsTestSpec58 FlagsTestSpec(const SharedGroupParams groupParams_)
59 : TestSpecBase{ {}, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, groupParams_ }
60 {
61 }
62 };
63
64 enum Constants
65 {
66 // \note Data layout in buffers (junk data and good data is intertwined).
67 // Values are largely arbitrary, but we try to avoid "nice" numbers to make sure the test doesn't pass by accident.
68 NUM_VERTICES = 4, //!< number of consecutive good vertices
69 NDX_FIRST_VERTEX = 2, //!< index of first good vertex data
70 NDX_SECOND_VERTEX = 9, //!< index of second good vertex data
71 NDX_FIRST_INDEX = 11, //!< index of a first good index (in index data)
72 NDX_SECOND_INDEX = 17, //!< index of a second good index
73 OFFSET_FIRST_INDEX = 1, //!< offset added to the first index
74 OFFSET_SECOND_INDEX = 4, //!< offset added to the second index
75 MAX_INSTANCE_COUNT = 3, //!< max number of draw instances
76 MAX_INDIRECT_DRAW_COUNT = 3, //!< max drawCount of indirect calls
77 };
78
79 class DrawTest : public DrawTestsBaseClass
80 {
81 public:
82 typedef FlagsTestSpec TestSpec;
83 DrawTest (Context &context, TestSpec testSpec);
84 tcu::TestStatus iterate (void);
85
86 private:
87 template<typename T, std::size_t N>
88 void setIndirectCommand (const T (&pCmdData)[N]);
89
90 void drawReferenceImage (const tcu::PixelBufferAccess& refImage) const;
91
isInstanced(void) const92 bool isInstanced (void) const { 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 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
DrawTest(Context & context,TestSpec testSpec)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>
setIndirectCommand(const T (& pCmdData)[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.
drawReferenceImage(const tcu::PixelBufferAccess & refImage) const195 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
iterate(void)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
beginSecondaryCmdBuffer(vk::VkRenderingFlagsKHR renderingFlags)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
draw(vk::VkCommandBuffer cmdBuffer)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
checkSupport(Context & context,DrawTest::TestSpec testSpec)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
addDrawCase(tcu::TestCaseGroup * group,DrawTest::TestSpec testSpec,const TestFlags flags)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
ShaderDrawParametersTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)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
init(void)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
516