• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Intel Corporation
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Dynamic State Viewport Tests
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktDynamicStateVPTests.hpp"
28 
29 #include "vktDynamicStateBaseClass.hpp"
30 #include "vktDynamicStateTestCaseUtil.hpp"
31 
32 #include "vkImageUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 
35 #include "tcuTextureUtil.hpp"
36 #include "tcuImageCompare.hpp"
37 #include "tcuRGBA.hpp"
38 
39 namespace vkt
40 {
41 namespace DynamicState
42 {
43 
44 using namespace Draw;
45 
46 namespace
47 {
48 
49 class ViewportStateBaseCase : public DynamicStateBaseClass
50 {
51 public:
ViewportStateBaseCase(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName,const char * meshShaderName)52 	ViewportStateBaseCase (Context& context, vk::PipelineConstructionType pipelineConstructionType, const char* vertexShaderName, const char* fragmentShaderName, const char* meshShaderName)
53 		: DynamicStateBaseClass	(context, pipelineConstructionType, vertexShaderName, fragmentShaderName, meshShaderName)
54 	{}
55 
initialize(void)56 	void initialize(void)
57 	{
58 		m_data.push_back(PositionColorVertex(tcu::Vec4(-0.5f, 0.5f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
59 		m_data.push_back(PositionColorVertex(tcu::Vec4(0.5f, 0.5f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
60 		m_data.push_back(PositionColorVertex(tcu::Vec4(-0.5f, -0.5f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
61 		m_data.push_back(PositionColorVertex(tcu::Vec4(0.5f, -0.5f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
62 
63 		DynamicStateBaseClass::initialize();
64 	}
65 
buildReferenceFrame(void)66 	virtual tcu::Texture2D buildReferenceFrame (void)
67 	{
68 		DE_ASSERT(false);
69 		return tcu::Texture2D(tcu::TextureFormat(), 0, 0);
70 	}
71 
setDynamicStates(void)72 	virtual void setDynamicStates (void)
73 	{
74 		DE_ASSERT(false);
75 	}
76 
iterate(void)77 	virtual tcu::TestStatus iterate (void)
78 	{
79 		tcu::TestLog&		log		= m_context.getTestContext().getLog();
80 		const vk::VkQueue	queue	= m_context.getUniversalQueue();
81 		const vk::VkDevice	device	= m_context.getDevice();
82 
83 		beginRenderPass();
84 
85 		// set states here
86 		setDynamicStates();
87 
88 		m_pipeline.bind(*m_cmdBuffer);
89 
90 #ifndef CTS_USES_VULKANSC
91 		if (m_isMesh)
92 		{
93 			const auto numVert = static_cast<uint32_t>(m_data.size());
94 			DE_ASSERT(numVert >= 2u);
95 
96 			m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout.get(), 0u, 1u, &m_descriptorSet.get(), 0u, nullptr);
97 			pushVertexOffset(0u, *m_pipelineLayout);
98 			m_vk.cmdDrawMeshTasksEXT(*m_cmdBuffer, numVert - 2u, 1u, 1u);
99 		}
100 		else
101 #endif // CTS_USES_VULKANSC
102 		{
103 			const vk::VkDeviceSize vertexBufferOffset = 0;
104 			const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
105 			m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
106 
107 			m_vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_data.size()), 1, 0, 0);
108 		}
109 
110 		m_renderPass.end(m_vk, *m_cmdBuffer);
111 		endCommandBuffer(m_vk, *m_cmdBuffer);
112 
113 		submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
114 
115 		// validation
116 		{
117 			tcu::Texture2D referenceFrame = buildReferenceFrame();
118 
119 			const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
120 			const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
121 				vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
122 
123 			if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
124 				referenceFrame.getLevel(0), renderedFrame, 0.05f,
125 				tcu::COMPARE_LOG_RESULT))
126 			{
127 				return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
128 			}
129 
130 			return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
131 		}
132 	}
133 };
134 
135 class ViewportParamTestInstance : public ViewportStateBaseCase
136 {
137 public:
ViewportParamTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const ShaderMap & shaders)138 	ViewportParamTestInstance (Context& context, vk::PipelineConstructionType pipelineConstructionType, const ShaderMap& shaders)
139 		: ViewportStateBaseCase (context, pipelineConstructionType, shaders.at(glu::SHADERTYPE_VERTEX), shaders.at(glu::SHADERTYPE_FRAGMENT), shaders.at(glu::SHADERTYPE_MESH))
140 	{
141 		ViewportStateBaseCase::initialize();
142 	}
143 
setDynamicStates(void)144 	virtual void setDynamicStates(void)
145 	{
146 		const vk::VkViewport viewport	= { 0.0f, 0.0f, static_cast<float>(WIDTH) * 2.0f, static_cast<float>(HEIGHT) * 2.0f, 0.0f, 0.0f };
147 		const vk::VkRect2D scissor		= { { 0, 0 }, { WIDTH, HEIGHT } };
148 
149 		setDynamicViewportState(1, &viewport, &scissor);
150 		setDynamicRasterizationState();
151 		setDynamicBlendState();
152 		setDynamicDepthStencilState();
153 	}
154 
buildReferenceFrame(void)155 	virtual tcu::Texture2D buildReferenceFrame (void)
156 	{
157 		tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
158 		referenceFrame.allocLevel(0);
159 
160 		const deInt32 frameWidth	= referenceFrame.getWidth();
161 		const deInt32 frameHeight	= referenceFrame.getHeight();
162 
163 		tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
164 
165 		for (int y = 0; y < frameHeight; y++)
166 		{
167 			const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
168 
169 			for (int x = 0; x < frameWidth; x++)
170 			{
171 				const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
172 
173 				if (xCoord >= 0.0f && xCoord <= 1.0f && yCoord >= 0.0f && yCoord <= 1.0f)
174 					referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
175 			}
176 		}
177 
178 		return referenceFrame;
179 	}
180 };
181 
182 class ScissorParamTestInstance : public ViewportStateBaseCase
183 {
184 public:
ScissorParamTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const ShaderMap & shaders)185 	ScissorParamTestInstance (Context& context, vk::PipelineConstructionType pipelineConstructionType, const ShaderMap& shaders)
186 		: ViewportStateBaseCase (context, pipelineConstructionType, shaders.at(glu::SHADERTYPE_VERTEX), shaders.at(glu::SHADERTYPE_FRAGMENT), shaders.at(glu::SHADERTYPE_MESH))
187 	{
188 		ViewportStateBaseCase::initialize();
189 	}
190 
setDynamicStates(void)191 	virtual void setDynamicStates (void)
192 	{
193 		const vk::VkViewport viewport	= { 0.0f, 0.0f, (float)WIDTH, (float)HEIGHT, 0.0f, 0.0f };
194 		const vk::VkRect2D scissor		= { { 0, 0 }, { WIDTH / 2, HEIGHT / 2 } };
195 
196 		setDynamicViewportState(1, &viewport, &scissor);
197 		setDynamicRasterizationState();
198 		setDynamicBlendState();
199 		setDynamicDepthStencilState();
200 	}
201 
buildReferenceFrame(void)202 	virtual tcu::Texture2D buildReferenceFrame (void)
203 	{
204 		tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
205 		referenceFrame.allocLevel(0);
206 
207 		const deInt32 frameWidth	= referenceFrame.getWidth();
208 		const deInt32 frameHeight	= referenceFrame.getHeight();
209 
210 		tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
211 
212 		for (int y = 0; y < frameHeight; y++)
213 		{
214 			const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
215 
216 			for (int x = 0; x < frameWidth; x++)
217 			{
218 				const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
219 
220 				if (xCoord >= -0.5f && xCoord <= 0.0f && yCoord >= -0.5f && yCoord <= 0.0f)
221 					referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
222 			}
223 		}
224 
225 		return referenceFrame;
226 	}
227 };
228 
229 class ViewportArrayTestInstance : public DynamicStateBaseClass
230 {
231 protected:
232 	std::string m_geometryShaderName;
233 
234 public:
235 
236 	static constexpr uint32_t kNumViewports = 4u;
237 
ViewportArrayTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const ShaderMap & shaders)238 	ViewportArrayTestInstance (Context& context, vk::PipelineConstructionType pipelineConstructionType, const ShaderMap& shaders)
239 		: DynamicStateBaseClass	(context, pipelineConstructionType, shaders.at(glu::SHADERTYPE_VERTEX), shaders.at(glu::SHADERTYPE_FRAGMENT), shaders.at(glu::SHADERTYPE_MESH))
240 		, m_geometryShaderName	(shaders.at(glu::SHADERTYPE_GEOMETRY) ? shaders.at(glu::SHADERTYPE_GEOMETRY) : "")
241 	{
242 		if (m_isMesh)
243 			DE_ASSERT(m_geometryShaderName.empty());
244 		else
245 			DE_ASSERT(!m_geometryShaderName.empty());
246 
247 		for (uint32_t i = 0u; i < kNumViewports; i++)
248 		{
249 			m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, (float)i / 3.0f, 1.0f), tcu::RGBA::green().toVec()));
250 			m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, (float)i / 3.0f, 1.0f), tcu::RGBA::green().toVec()));
251 			m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, (float)i / 3.0f, 1.0f), tcu::RGBA::green().toVec()));
252 			m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, (float)i / 3.0f, 1.0f), tcu::RGBA::green().toVec()));
253 		}
254 
255 		DynamicStateBaseClass::initialize();
256 	}
257 
initPipeline(const vk::VkDevice device)258 	virtual void initPipeline (const vk::VkDevice device)
259 	{
260 		const auto&							binaries	= m_context.getBinaryCollection();
261 		const vk::ShaderWrapper				vs			(m_isMesh ? vk::ShaderWrapper() : vk::ShaderWrapper(m_vk, device, binaries.get(m_vertexShaderName), 0));
262 		const vk::ShaderWrapper				gs			(m_isMesh ? vk::ShaderWrapper() : vk::ShaderWrapper(m_vk, device, binaries.get(m_geometryShaderName), 0));
263 		const vk::ShaderWrapper				ms			(m_isMesh ? vk::ShaderWrapper(m_vk, device, binaries.get(m_meshShaderName)) : vk::ShaderWrapper());
264 		const vk::ShaderWrapper				fs			(vk::ShaderWrapper(m_vk, device, binaries.get(m_fragmentShaderName), 0));
265 		std::vector<vk::VkViewport>			viewports	(4u, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f });
266 		std::vector<vk::VkRect2D>			scissors	(4u, { { 0u, 0u }, { 0u, 0u } });
267 
268 		const PipelineCreateInfo::ColorBlendState::Attachment	attachmentState;
269 		const PipelineCreateInfo::ColorBlendState				colorBlendState(1u, static_cast<const vk::VkPipelineColorBlendAttachmentState*>(&attachmentState));
270 		const PipelineCreateInfo::RasterizerState				rasterizerState;
271 		const PipelineCreateInfo::DepthStencilState				depthStencilState;
272 		PipelineCreateInfo::DynamicState						dynamicState;
273 
274 		m_pipeline.setDefaultTopology(m_topology)
275 				  .setDynamicState(static_cast<const vk::VkPipelineDynamicStateCreateInfo*>(&dynamicState))
276 				  .setDefaultMultisampleState();
277 
278 #ifndef CTS_USES_VULKANSC
279 		if (m_isMesh)
280 		{
281 			m_pipeline
282 				  .setupPreRasterizationMeshShaderState(viewports,
283 														scissors,
284 														m_pipelineLayout,
285 														*m_renderPass,
286 														0u,
287 														vk::ShaderWrapper(),
288 														ms,
289 														static_cast<const vk::VkPipelineRasterizationStateCreateInfo*>(&rasterizerState));
290 		}
291 		else
292 #endif // CTS_USES_VULKANSC
293 		{
294 			m_pipeline
295 				  .setupVertexInputState(&m_vertexInputState)
296 				  .setupPreRasterizationShaderState(viewports,
297 													scissors,
298 													m_pipelineLayout,
299 													*m_renderPass,
300 													0u,
301 													vs,
302 													static_cast<const vk::VkPipelineRasterizationStateCreateInfo*>(&rasterizerState),
303 													vk::ShaderWrapper(),
304 													vk::ShaderWrapper(),
305 													gs);
306 		}
307 
308 		m_pipeline.setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, fs, static_cast<const vk::VkPipelineDepthStencilStateCreateInfo*>(&depthStencilState))
309 				  .setupFragmentOutputState(*m_renderPass, 0u, static_cast<const vk::VkPipelineColorBlendStateCreateInfo*>(&colorBlendState))
310 				  .setMonolithicPipelineLayout(m_pipelineLayout)
311 				  .buildPipeline();
312 	}
313 
iterate(void)314 	virtual tcu::TestStatus iterate (void)
315 	{
316 		tcu::TestLog&		log		= m_context.getTestContext().getLog();
317 		const vk::VkQueue	queue	= m_context.getUniversalQueue();
318 		const vk::VkDevice	device	= m_context.getDevice();
319 
320 		beginRenderPass();
321 
322 		// set states here
323 		const float halfWidth		= (float)WIDTH / 2;
324 		const float halfHeight		= (float)HEIGHT / 2;
325 		const deInt32 quarterWidth	= WIDTH / 4;
326 		const deInt32 quarterHeight = HEIGHT / 4;
327 
328 		const vk::VkViewport viewports[kNumViewports] =
329 		{
330 			{ 0.0f, 0.0f, (float)halfWidth, (float)halfHeight, 0.0f, 0.0f },
331 			{ halfWidth, 0.0f, (float)halfWidth, (float)halfHeight, 0.0f, 0.0f },
332 			{ halfWidth, halfHeight, (float)halfWidth, (float)halfHeight, 0.0f, 0.0f },
333 			{ 0.0f, halfHeight, (float)halfWidth, (float)halfHeight, 0.0f, 0.0f }
334 		};
335 
336 		const vk::VkRect2D scissors[kNumViewports] =
337 		{
338 			{ { quarterWidth, quarterHeight }, { quarterWidth, quarterHeight } },
339 			{ { (deInt32)halfWidth, quarterHeight }, { quarterWidth, quarterHeight } },
340 			{ { (deInt32)halfWidth, (deInt32)halfHeight }, { quarterWidth, quarterHeight } },
341 			{ { quarterWidth, (deInt32)halfHeight }, { quarterWidth, quarterHeight } },
342 		};
343 
344 		setDynamicViewportState(kNumViewports, viewports, scissors);
345 		setDynamicRasterizationState();
346 		setDynamicBlendState();
347 		setDynamicDepthStencilState();
348 
349 		m_pipeline.bind(*m_cmdBuffer);
350 
351 		DE_ASSERT(m_data.size() % kNumViewports == 0u);
352 		const uint32_t vertsPerViewport = static_cast<uint32_t>(m_data.size() / kNumViewports);
353 
354 		if (!m_isMesh)
355 		{
356 			const vk::VkDeviceSize vertexBufferOffset = 0;
357 			const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
358 			m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
359 
360 			for (uint32_t i = 0u; i < kNumViewports; ++i)
361 			{
362 				const uint32_t firstVertex = i * vertsPerViewport;
363 				m_vk.cmdDraw(*m_cmdBuffer, vertsPerViewport, 1, firstVertex, 0);
364 			}
365 		}
366 #ifndef CTS_USES_VULKANSC
367 		else
368 		{
369 			DE_ASSERT(vertsPerViewport >= 2u);
370 
371 			m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout.get(), 0u, 1u, &m_descriptorSet.get(), 0u, nullptr);
372 
373 			for (uint32_t i = 0u; i < kNumViewports; ++i)
374 			{
375 				const uint32_t firstVertex = i * vertsPerViewport;
376 				pushVertexOffset(firstVertex, *m_pipelineLayout);
377 				m_vk.cmdDrawMeshTasksEXT(*m_cmdBuffer, vertsPerViewport - 2u, 1u, 1u);
378 			}
379 		}
380 #endif // CTS_USES_VULKANSC
381 
382 		m_renderPass.end(m_vk, *m_cmdBuffer);
383 		endCommandBuffer(m_vk, *m_cmdBuffer);
384 
385 		submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
386 
387 		// validation
388 		{
389 			tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
390 			referenceFrame.allocLevel(0);
391 
392 			const deInt32 frameWidth = referenceFrame.getWidth();
393 			const deInt32 frameHeight = referenceFrame.getHeight();
394 
395 			tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
396 
397 			for (int y = 0; y < frameHeight; y++)
398 			{
399 				const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
400 
401 				for (int x = 0; x < frameWidth; x++)
402 				{
403 					const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
404 
405 					if (xCoord >= -0.5f && xCoord <= 0.5f && yCoord >= -0.5f && yCoord <= 0.5f)
406 						referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
407 				}
408 			}
409 
410 			const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
411 			const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
412 				vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
413 
414 			if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
415 				referenceFrame.getLevel(0), renderedFrame, 0.05f,
416 				tcu::COMPARE_LOG_RESULT))
417 			{
418 				return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
419 			}
420 
421 			return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
422 		}
423 	}
424 };
425 
checkGeometryAndMultiViewportSupport(Context & context)426 void checkGeometryAndMultiViewportSupport (Context& context)
427 {
428 	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
429 	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
430 }
431 
checkMeshShaderSupport(Context & context)432 void checkMeshShaderSupport (Context& context)
433 {
434 	context.requireDeviceFunctionality("VK_EXT_mesh_shader");
435 }
436 
checkMeshAndMultiViewportSupport(Context & context)437 void checkMeshAndMultiViewportSupport (Context& context)
438 {
439 	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
440 	checkMeshShaderSupport(context);
441 }
442 
checkNothing(Context &)443 void checkNothing (Context&)
444 {
445 }
446 
447 } //anonymous
448 
DynamicStateVPTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)449 DynamicStateVPTests::DynamicStateVPTests (tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType)
450 	: TestCaseGroup					(testCtx, "vp_state")
451 	, m_pipelineConstructionType	(pipelineConstructionType)
452 {
453 	/* Left blank on purpose */
454 }
455 
~DynamicStateVPTests()456 DynamicStateVPTests::~DynamicStateVPTests ()
457 {
458 }
459 
init(void)460 void DynamicStateVPTests::init (void)
461 {
462 	ShaderMap basePaths;
463 	basePaths[glu::SHADERTYPE_FRAGMENT]	= "vulkan/dynamic_state/VertexFetch.frag";
464 	basePaths[glu::SHADERTYPE_GEOMETRY]	= nullptr;
465 	basePaths[glu::SHADERTYPE_VERTEX]	= nullptr;
466 	basePaths[glu::SHADERTYPE_MESH]		= nullptr;
467 
468 	for (int i = 0; i < 2; ++i)
469 	{
470 		const bool					isMesh					= (i > 0);
471 		ShaderMap					shaderPaths(basePaths);
472 		std::string					nameSuffix;
473 		FunctionSupport0::Function	checkSupportFunc;
474 
475 		if (isMesh)
476 		{
477 #ifndef CTS_USES_VULKANSC
478 			shaderPaths[glu::SHADERTYPE_MESH] = "vulkan/dynamic_state/VertexFetch.mesh";
479 			nameSuffix = "_mesh";
480 			checkSupportFunc = checkMeshShaderSupport;
481 #else
482 			continue;
483 #endif // CTS_USES_VULKANSC
484 		}
485 		else
486 		{
487 			shaderPaths[glu::SHADERTYPE_VERTEX] = "vulkan/dynamic_state/VertexFetch.vert";
488 			checkSupportFunc = checkNothing;
489 		}
490 
491 		addChild(new InstanceFactory<ViewportParamTestInstance, FunctionSupport0>(m_testCtx, "viewport" + nameSuffix, m_pipelineConstructionType, shaderPaths, checkSupportFunc));
492 		addChild(new InstanceFactory<ScissorParamTestInstance, FunctionSupport0>(m_testCtx, "scissor" + nameSuffix, m_pipelineConstructionType, shaderPaths, checkSupportFunc));
493 
494 		if (isMesh)
495 		{
496 			shaderPaths[glu::SHADERTYPE_MESH] = "vulkan/dynamic_state/VertexFetchViewportArray.mesh";
497 			checkSupportFunc = checkMeshAndMultiViewportSupport;
498 		}
499 		else
500 		{
501 			shaderPaths[glu::SHADERTYPE_GEOMETRY] = "vulkan/dynamic_state/ViewportArray.geom";
502 			checkSupportFunc = checkGeometryAndMultiViewportSupport;
503 		}
504 		// Multiple viewports and scissors
505 		addChild(new InstanceFactory<ViewportArrayTestInstance, FunctionSupport0>(m_testCtx, "viewport_array" + nameSuffix, m_pipelineConstructionType, shaderPaths, checkSupportFunc));
506 	}
507 }
508 
509 } // DynamicState
510 } // vkt
511