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