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