• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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