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