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