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