1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2018 The Khronos Group Inc.
6 * Copyright (c) 2018 The Android Open Source Project
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Use of gl_ViewportIndex in Vertex and Tessellation Shaders
23 * (part of VK_EXT_ShaderViewportIndexLayer)
24 *//*--------------------------------------------------------------------*/
26 #include "vktDrawShaderViewportIndexTests.hpp"
28 #include "vktDrawBaseClass.hpp"
29 #include "vktTestCaseUtil.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkPrograms.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkBuilderUtil.hpp"
42 #include "vkBufferWithMemory.hpp"
44 #include "tcuTestLog.hpp"
45 #include "tcuVector.hpp"
46 #include "tcuImageCompare.hpp"
47 #include "tcuTextureUtil.hpp"
49 #include "deUniquePtr.hpp"
73 MIN_MAX_VIEWPORTS = 16, //!< Minimum number of viewports for an implementation supporting multiViewport.
80 const SharedGroupParams groupParams;
81 bool useTessellationShader;
85 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
87 return vec.size() * sizeof(vec[0]);
90 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const UVec2& size, VkImageUsageFlags usage)
92 const VkImageCreateInfo imageParams =
94 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
95 DE_NULL, // const void* pNext;
96 (VkImageCreateFlags)0, // VkImageCreateFlags flags;
97 VK_IMAGE_TYPE_2D, // VkImageType imageType;
98 format, // VkFormat format;
99 makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
100 1u, // deUint32 mipLevels;
101 1u, // deUint32 arrayLayers;
102 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
103 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
104 usage, // VkImageUsageFlags usage;
105 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
106 0u, // deUint32 queueFamilyIndexCount;
107 DE_NULL, // const deUint32* pQueueFamilyIndices;
108 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
113 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface& vk,
114 const VkDevice device,
115 const VkPipelineLayout pipelineLayout,
116 const VkRenderPass renderPass,
117 const VkShaderModule vertexModule,
118 const VkShaderModule tessellationControlModule,
119 const VkShaderModule tessellationEvaluationModule,
120 const VkShaderModule fragmentModule,
121 const UVec2 renderSize,
122 const int numViewports,
123 const std::vector<UVec4> cells)
125 const VkVertexInputBindingDescription vertexInputBindingDescription =
127 0u, // uint32_t binding;
128 sizeof(PositionColorVertex), // uint32_t stride;
129 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
132 const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
135 0u, // uint32_t location;
136 0u, // uint32_t binding;
137 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
138 0u, // uint32_t offset;
141 1u, // uint32_t location;
142 0u, // uint32_t binding;
143 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
144 sizeof(Vec4), // uint32_t offset;
148 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
150 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
151 DE_NULL, // const void* pNext;
152 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
153 1u, // uint32_t vertexBindingDescriptionCount;
154 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
155 DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions), // uint32_t vertexAttributeDescriptionCount;
156 vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
159 const bool useTessellationShaders = (tessellationControlModule != DE_NULL) && (tessellationEvaluationModule != DE_NULL);
161 const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
163 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
164 DE_NULL, // const void* pNext;
165 (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags;
166 useTessellationShaders ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology;
167 VK_FALSE, // VkBool32 primitiveRestartEnable;
170 DE_ASSERT(numViewports == static_cast<int>(cells.size()));
172 std::vector<VkViewport> viewports;
173 viewports.reserve(numViewports);
175 std::vector<VkRect2D> rectScissors;
176 rectScissors.reserve(numViewports);
178 for (std::vector<UVec4>::const_iterator it = cells.begin(); it != cells.end(); ++it) {
179 const VkViewport viewport = makeViewport(float(it->x()), float(it->y()), float(it->z()), float(it->w()), 0.0f, 1.0f);
180 viewports.push_back(viewport);
181 const VkRect2D rect = makeRect2D(renderSize);
182 rectScissors.push_back(rect);
185 const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
187 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
188 DE_NULL, // const void* pNext;
189 (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags;
190 static_cast<deUint32>(numViewports), // uint32_t viewportCount;
191 &viewports[0], // const VkViewport* pViewports;
192 static_cast<deUint32>(numViewports), // uint32_t scissorCount;
193 &rectScissors[0], // const VkRect2D* pScissors;
196 const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
198 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
199 DE_NULL, // const void* pNext;
200 (VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStateCreateFlags flags;
201 VK_FALSE, // VkBool32 depthClampEnable;
202 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
203 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
204 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
205 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
206 VK_FALSE, // VkBool32 depthBiasEnable;
207 0.0f, // float depthBiasConstantFactor;
208 0.0f, // float depthBiasClamp;
209 0.0f, // float depthBiasSlopeFactor;
210 1.0f, // float lineWidth;
213 const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
215 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
216 DE_NULL, // const void* pNext;
217 (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags;
218 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
219 VK_FALSE, // VkBool32 sampleShadingEnable;
220 0.0f, // float minSampleShading;
221 DE_NULL, // const VkSampleMask* pSampleMask;
222 VK_FALSE, // VkBool32 alphaToCoverageEnable;
223 VK_FALSE // VkBool32 alphaToOneEnable;
226 const VkStencilOpState stencilOpState = makeStencilOpState(
227 VK_STENCIL_OP_KEEP, // stencil fail
228 VK_STENCIL_OP_KEEP, // depth & stencil pass
229 VK_STENCIL_OP_KEEP, // depth only fail
230 VK_COMPARE_OP_ALWAYS, // compare op
235 VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
237 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
238 DE_NULL, // const void* pNext;
239 (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags;
240 VK_FALSE, // VkBool32 depthTestEnable;
241 VK_FALSE, // VkBool32 depthWriteEnable;
242 VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
243 VK_FALSE, // VkBool32 depthBoundsTestEnable;
244 VK_FALSE, // VkBool32 stencilTestEnable;
245 stencilOpState, // VkStencilOpState front;
246 stencilOpState, // VkStencilOpState back;
247 0.0f, // float minDepthBounds;
248 1.0f, // float maxDepthBounds;
251 const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
252 const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState =
254 VK_FALSE, // VkBool32 blendEnable;
255 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
256 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
257 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
258 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
259 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
260 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
261 colorComponentsAll, // VkColorComponentFlags colorWriteMask;
264 const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
266 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
267 DE_NULL, // const void* pNext;
268 (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags;
269 VK_FALSE, // VkBool32 logicOpEnable;
270 VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
271 1u, // deUint32 attachmentCount;
272 &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
273 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
276 const VkPipelineShaderStageCreateInfo pShaderStages[] =
279 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
280 DE_NULL, // const void* pNext;
281 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
282 VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
283 vertexModule, // VkShaderModule module;
284 "main", // const char* pName;
285 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
288 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
289 DE_NULL, // const void* pNext;
290 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
291 VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
292 fragmentModule, // VkShaderModule module;
293 "main", // const char* pName;
294 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
297 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
298 DE_NULL, // const void* pNext;
299 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
300 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, // VkShaderStageFlagBits stage;
301 tessellationControlModule, // VkShaderModule module;
302 "main", // const char* pName;
303 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
306 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
307 DE_NULL, // const void* pNext;
308 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
309 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, // VkShaderStageFlagBits stage;
310 tessellationEvaluationModule, // VkShaderModule module;
311 "main", // const char* pName;
312 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
316 const VkPipelineTessellationStateCreateInfo pipelineTessellationStateInfo =
318 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType;
319 DE_NULL, // const void* pNext;
320 (VkPipelineTessellationStateCreateFlags)0, // VkPipelineTessellationStateCreateFlags flags;
321 3, // uint32_t patchControlPoints;
324 VkGraphicsPipelineCreateInfo graphicsPipelineInfo
326 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
327 DE_NULL, // const void* pNext;
328 (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags;
329 useTessellationShaders ? deUint32(4) : deUint32(2), // deUint32 stageCount;
330 pShaderStages, // const VkPipelineShaderStageCreateInfo* pStages;
331 &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
332 &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
333 useTessellationShaders ? &pipelineTessellationStateInfo : DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
334 &pipelineViewportStateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState;
335 &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
336 &pipelineMultisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
337 &pipelineDepthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
338 &pipelineColorBlendStateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
339 DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
340 pipelineLayout, // VkPipelineLayout layout;
341 renderPass, // VkRenderPass renderPass;
342 0u, // deUint32 subpass;
343 DE_NULL, // VkPipeline basePipelineHandle;
344 0, // deInt32 basePipelineIndex;
347 #ifndef CTS_USES_VULKANSC
348 VkFormat colorAttachmentFormat = VK_FORMAT_R8G8B8A8_UNORM;
349 VkPipelineRenderingCreateInfoKHR renderingCreateInfo
351 VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
355 &colorAttachmentFormat,
360 // when pipeline is created without render pass we are using dynamic rendering
361 if (renderPass == DE_NULL)
362 graphicsPipelineInfo.pNext = &renderingCreateInfo;
363 #endif // CTS_USES_VULKANSC
365 return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
368 std::vector<UVec4> generateGrid (const int numCells, const UVec2& renderSize)
370 const int numCols = deCeilFloatToInt32(deFloatSqrt(static_cast<float>(numCells)));
371 const int numRows = deCeilFloatToInt32(static_cast<float>(numCells) / static_cast<float>(numCols));
372 const int rectWidth = renderSize.x() / numCols;
373 const int rectHeight = renderSize.y() / numRows;
375 std::vector<UVec4> cells;
376 cells.reserve(numCells);
381 for (int cellNdx = 0; cellNdx < numCells; ++cellNdx)
383 const bool nextRow = (cellNdx != 0) && (cellNdx % numCols == 0);
390 cells.push_back(UVec4(x, y, rectWidth, rectHeight));
398 std::vector<Vec4> generateColors (const int numColors)
400 const Vec4 colors[] =
402 Vec4(0.18f, 0.42f, 0.17f, 1.0f),
403 Vec4(0.29f, 0.62f, 0.28f, 1.0f),
404 Vec4(0.59f, 0.84f, 0.44f, 1.0f),
405 Vec4(0.96f, 0.95f, 0.72f, 1.0f),
406 Vec4(0.94f, 0.55f, 0.39f, 1.0f),
407 Vec4(0.82f, 0.19f, 0.12f, 1.0f),
408 Vec4(0.46f, 0.15f, 0.26f, 1.0f),
409 Vec4(0.24f, 0.14f, 0.24f, 1.0f),
410 Vec4(0.49f, 0.31f, 0.26f, 1.0f),
411 Vec4(0.78f, 0.52f, 0.33f, 1.0f),
412 Vec4(0.94f, 0.82f, 0.31f, 1.0f),
413 Vec4(0.98f, 0.65f, 0.30f, 1.0f),
414 Vec4(0.22f, 0.65f, 0.53f, 1.0f),
415 Vec4(0.67f, 0.81f, 0.91f, 1.0f),
416 Vec4(0.43f, 0.44f, 0.75f, 1.0f),
417 Vec4(0.26f, 0.24f, 0.48f, 1.0f),
420 DE_ASSERT(numColors <= DE_LENGTH_OF_ARRAY(colors));
422 return std::vector<Vec4>(colors, colors + numColors);
425 //! Renders a colorful grid of rectangles.
426 tcu::TextureLevel generateReferenceImage (const tcu::TextureFormat format,
427 const UVec2& renderSize,
428 const Vec4& clearColor,
429 const std::vector<UVec4>& cells,
430 const std::vector<Vec4>& cellColors)
432 DE_ASSERT(cells.size() == cellColors.size());
434 tcu::TextureLevel image(format, renderSize.x(), renderSize.y());
435 tcu::clear(image.getAccess(), clearColor);
437 for (std::size_t i = 0; i < cells.size(); ++i)
439 const UVec4& cell = cells[i];
441 tcu::getSubregion(image.getAccess(), cell.x(), cell.y(), cell.z(), cell.w()),
448 void initVertexTestPrograms (SourceCollections& programCollection, const TestParams)
452 std::ostringstream src;
453 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
454 << "#extension GL_ARB_shader_viewport_layer_array : require\n"
456 << "layout(location = 0) in vec4 in_position;\n"
457 << "layout(location = 1) in vec4 in_color;\n"
458 << "layout(location = 0) out vec4 out_color;\n"
460 << "void main(void)\n"
462 << " gl_ViewportIndex = gl_VertexIndex / 6;\n"
463 << " gl_Position = in_position;\n"
464 << " out_color = in_color;\n"
467 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
472 std::ostringstream src;
473 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
475 << "layout(location = 0) in vec4 in_color;\n"
476 << "layout(location = 0) out vec4 out_color;\n"
478 << "void main(void)\n"
480 << " out_color = in_color;\n"
483 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
487 void initFragmentTestPrograms (SourceCollections& programCollection, const TestParams testParams)
491 std::ostringstream src;
492 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
493 << "#extension GL_ARB_shader_viewport_layer_array : require\n"
495 << "layout(location = 0) in vec4 in_position;\n"
496 << "layout(location = 1) in vec4 in_color;\n"
497 << "layout(location = 0) out vec4 out_color;\n"
499 << "void main(void)\n"
501 << (testParams.writeFromVertex ? " gl_ViewportIndex = gl_VertexIndex / 6;\n" : "")
502 << " gl_Position = in_position;\n"
503 << " out_color = in_color;\n"
506 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
511 // Ignore input color and choose one using the viewport index.
512 std::ostringstream src;
513 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
515 << "layout(location = 0) in vec4 in_color;\n"
516 << "layout(location = 0) out vec4 out_color;\n"
517 << "layout(set=0, binding=0) uniform Colors {\n"
518 << " vec4 color[" << testParams.numViewports << "];\n"
521 << "void main(void)\n"
523 << " out_color = color[gl_ViewportIndex];\n"
526 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
530 void initTessellationTestPrograms (SourceCollections& programCollection, const TestParams)
534 std::ostringstream src;
535 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
537 << "layout(location = 0) in vec4 in_position;\n"
538 << "layout(location = 1) in vec4 in_color;\n"
539 << "layout(location = 0) out vec4 out_color;\n"
541 << "void main(void)\n"
543 << " gl_Position = in_position;\n"
544 << " out_color = in_color;\n"
547 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
550 // Tessellation control shader
552 std::ostringstream src;
553 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
555 << "layout(vertices = 3) out;\n"
557 << "layout(location = 0) in vec4 in_color[];\n"
558 << "layout(location = 0) out vec4 out_color[];\n"
560 << "void main(void)\n"
562 << " if (gl_InvocationID == 0) {\n"
563 << " gl_TessLevelInner[0] = 1.0;\n"
564 << " gl_TessLevelInner[1] = 1.0;\n"
565 << " gl_TessLevelOuter[0] = 1.0;\n"
566 << " gl_TessLevelOuter[1] = 1.0;\n"
567 << " gl_TessLevelOuter[2] = 1.0;\n"
568 << " gl_TessLevelOuter[3] = 1.0;\n"
570 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
571 << " out_color[gl_InvocationID] = in_color[gl_InvocationID];\n"
574 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
577 // Tessellation evaluation shader
579 std::ostringstream src;
580 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
581 << "#extension GL_ARB_shader_viewport_layer_array : require\n"
583 << "layout(triangles, equal_spacing, cw) in;\n"
585 << "layout(location = 0) in vec4 in_color[];\n"
586 << "layout(location = 0) out vec4 out_color;\n"
588 << "void main(void)\n"
590 << " gl_ViewportIndex = gl_PrimitiveID / 2;\n"
591 << " gl_Position = gl_in[0].gl_Position * gl_TessCoord.x +\n"
592 << " gl_in[1].gl_Position * gl_TessCoord.y +\n"
593 << " gl_in[2].gl_Position * gl_TessCoord.z;\n"
595 << " out_color = in_color[0] * gl_TessCoord.x +\n"
596 << " in_color[1] * gl_TessCoord.y +\n"
597 << " in_color[2] * gl_TessCoord.z;\n"
600 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
605 std::ostringstream src;
606 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
608 << "layout(location = 0) in vec4 in_color;\n"
609 << "layout(location = 0) out vec4 out_color;\n"
611 << "void main(void)\n"
613 << " out_color = in_color;\n"
616 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
620 std::vector<PositionColorVertex> generateVertices (const std::vector<Vec4>& colors)
622 // Two triangles for each color (viewport).
623 std::size_t total = colors.size() * 6;
625 std::vector<PositionColorVertex> result;
626 result.reserve(total);
628 for (std::size_t i = 0; i < total; ++i)
635 case 0: pos.xy() = Vec2(-1.0, 1.0); break;
636 case 1: pos.xy() = Vec2( 1.0, 1.0); break;
637 case 2: pos.xy() = Vec2(-1.0, -1.0); break;
638 case 3: pos.xy() = Vec2( 1.0, -1.0); break;
639 case 4: pos.xy() = Vec2( 1.0, 1.0); break;
640 case 5: pos.xy() = Vec2(-1.0, -1.0); break;
643 result.push_back(PositionColorVertex(pos, colors[i/6]));
649 // Renderer generates two triangles per viewport, each pair using a different color. The
650 // numViewports are positioned to form a grid.
660 Renderer (Context& context,
661 const UVec2& renderSize,
662 const TestParams& testParams,
663 const std::vector<UVec4>& cells,
664 const VkFormat colorFormat,
665 const Vec4& clearColor,
666 const std::vector<Vec4>& colors,
668 : m_groupParams (testParams.groupParams)
669 , m_renderSize (renderSize)
670 , m_colorFormat (colorFormat)
671 , m_colorSubresourceRange (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
672 , m_clearValue (makeClearValueColor(clearColor))
673 , m_numViewports (testParams.numViewports)
675 , m_vertices (generateVertices(colors))
678 const DeviceInterface& vk = context.getDeviceInterface();
679 const VkDevice device = context.getDevice();
680 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
681 Allocator& allocator = context.getDefaultAllocator();
682 const VkDeviceSize vertexBufferSize = sizeInBytes(m_vertices);
684 m_colorImage = makeImage (vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
685 m_colorImageAlloc = bindImage (vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
686 m_colorAttachment = makeImageView (vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
688 m_vertexBuffer = Buffer::createAndAlloc (vk, device, makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), allocator, MemoryRequirement::HostVisible);
691 deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), &m_vertices[0], static_cast<std::size_t>(vertexBufferSize));
692 flushAlloc(vk, device, m_vertexBuffer->getBoundMemory());
695 if (shader == TESSELLATION)
697 m_tessellationControlModule = createShaderModule (vk, device, context.getBinaryCollection().get("tesc"), 0u);
698 m_tessellationEvaluationModule = createShaderModule (vk, device, context.getBinaryCollection().get("tese"), 0u);
701 m_vertexModule = createShaderModule (vk, device, context.getBinaryCollection().get("vert"), 0u);
702 m_fragmentModule = createShaderModule (vk, device, context.getBinaryCollection().get("frag"), 0u);
704 if (!m_groupParams->useDynamicRendering)
706 m_renderPass = makeRenderPass (vk, device, m_colorFormat);
708 m_framebuffer = makeFramebuffer (vk, device, *m_renderPass, m_colorAttachment.get(),
709 static_cast<deUint32>(m_renderSize.x()), static_cast<deUint32>(m_renderSize.y()));
712 if (shader == FRAGMENT)
714 vk::DescriptorSetLayoutBuilder builder;
715 builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
716 m_descriptorSetLayout = builder.build(vk, device);
719 m_pipelineLayout = makePipelineLayout (vk, device, (shader == FRAGMENT ? m_descriptorSetLayout.get() : DE_NULL));
720 m_pipeline = makeGraphicsPipeline (vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_tessellationControlModule,
721 *m_tessellationEvaluationModule, *m_fragmentModule, m_renderSize, m_numViewports, cells);
722 m_cmdPool = createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
723 m_cmdBuffer = allocateCommandBuffer (vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
724 m_secCmdBuffer = allocateCommandBuffer (vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
727 void draw (Context& context, const VkBuffer colorBuffer)
729 const DeviceInterface& vk = context.getDeviceInterface();
730 const VkDevice device = context.getDevice();
731 const VkQueue queue = context.getUniversalQueue();
732 const VkRect2D renderArea
735 makeExtent2D(m_renderSize.x(), m_renderSize.y()),
738 #ifndef CTS_USES_VULKANSC
739 if (m_groupParams->useSecondaryCmdBuffer)
741 // record secondary command buffer
742 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
744 beginSecondaryCmdBuffer(context, *m_secCmdBuffer, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
745 beginRendering(vk, *m_secCmdBuffer, *m_colorAttachment, renderArea, m_clearValue,
746 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR);
749 beginSecondaryCmdBuffer(context, *m_secCmdBuffer);
751 drawCommands(context, *m_secCmdBuffer);
753 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
754 endRendering(vk, *m_secCmdBuffer);
756 endCommandBuffer(vk, *m_secCmdBuffer);
758 // record primary command buffer
759 beginCommandBuffer(vk, *m_cmdBuffer, 0u);
761 preRenderCommands(context, *m_cmdBuffer);
763 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
764 beginRendering(vk, *m_cmdBuffer, *m_colorAttachment, renderArea, m_clearValue,
765 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR);
767 vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
769 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
770 endRendering(vk, *m_cmdBuffer);
772 postRenderCommands(context, colorBuffer);
773 endCommandBuffer(vk, *m_cmdBuffer);
775 else if (m_groupParams->useDynamicRendering)
777 beginCommandBuffer(vk, *m_cmdBuffer);
779 preRenderCommands(context, *m_cmdBuffer);
780 beginRendering(vk, *m_cmdBuffer, *m_colorAttachment, renderArea, m_clearValue,
781 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR);
782 drawCommands(context, *m_cmdBuffer);
783 endRendering(vk, *m_cmdBuffer);
784 postRenderCommands(context, colorBuffer);
786 endCommandBuffer(vk, *m_cmdBuffer);
788 #endif // CTS_USES_VULKANSC
790 if (!m_groupParams->useDynamicRendering)
792 beginCommandBuffer(vk, *m_cmdBuffer);
794 preRenderCommands(context, *m_cmdBuffer);
795 beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, m_clearValue);
796 drawCommands(context, *m_cmdBuffer);
797 endRenderPass(vk, *m_cmdBuffer);
798 postRenderCommands(context, colorBuffer);
800 endCommandBuffer(vk, *m_cmdBuffer);
803 submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
808 #ifndef CTS_USES_VULKANSC
809 void beginSecondaryCmdBuffer(Context& context, VkCommandBuffer cmdBuffer, VkRenderingFlagsKHR renderingFlags = 0u) const
811 VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo
813 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
814 DE_NULL, // const void* pNext;
815 renderingFlags, // VkRenderingFlagsKHR flags;
816 0u, // uint32_t viewMask;
817 1u, // uint32_t colorAttachmentCount;
818 &m_colorFormat, // const VkFormat* pColorAttachmentFormats;
819 VK_FORMAT_UNDEFINED, // VkFormat depthAttachmentFormat;
820 VK_FORMAT_UNDEFINED, // VkFormat stencilAttachmentFormat;
821 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
823 const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo);
825 VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
826 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
827 usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
829 const VkCommandBufferBeginInfo commandBufBeginParams
831 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
832 DE_NULL, // const void* pNext;
833 usageFlags, // VkCommandBufferUsageFlags flags;
834 &bufferInheritanceInfo
837 const DeviceInterface& vk = context.getDeviceInterface();
838 VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
840 #endif // CTS_USES_VULKANSC
842 void preRenderCommands(Context& context, VkCommandBuffer cmdBuffer) const
844 if (m_groupParams->useDynamicRendering)
846 const DeviceInterface& vk = context.getDeviceInterface();
847 initialTransitionColor2DImage(vk, cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
848 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
852 void postRenderCommands(Context& context, VkBuffer colorBuffer) const
854 const DeviceInterface& vk = context.getDeviceInterface();
855 copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, colorBuffer, tcu::IVec2(m_renderSize.x(), m_renderSize.y()));
858 void drawCommands(Context& context, VkCommandBuffer cmdBuffer)
860 const DeviceInterface& vk = context.getDeviceInterface();
861 const VkDevice device = context.getDevice();
862 Allocator& allocator = context.getDefaultAllocator();
863 const VkBuffer vertexBuffer = m_vertexBuffer->object();
864 const VkDeviceSize vertexBufferOffset = 0ull;
866 vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
867 vk.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
869 // Prepare colors buffer if needed.
870 if (m_shader == FRAGMENT)
873 const auto colorsBufferSize = m_colors.size() * sizeof(decltype(m_colors)::value_type);
874 const auto colorsBufferCreateInfo = vk::makeBufferCreateInfo(static_cast<VkDeviceSize>(colorsBufferSize), vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
875 m_colorsBuffer = SharedPtr<BufferWithMemory>(new vk::BufferWithMemory{ vk, device, allocator, colorsBufferCreateInfo, MemoryRequirement::HostVisible });
877 // Copy colors and flush allocation.
878 auto& colorsBufferAlloc = m_colorsBuffer->getAllocation();
879 deMemcpy(colorsBufferAlloc.getHostPtr(), m_colors.data(), colorsBufferSize);
880 vk::flushAlloc(vk, device, colorsBufferAlloc);
883 DescriptorPoolBuilder poolBuilder;
884 poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u);
885 m_descriptorPool = poolBuilder.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
888 m_descriptorSet = vk::makeDescriptorSet(vk, device, m_descriptorPool.get(), m_descriptorSetLayout.get());
890 // Update and bind descriptor set.
891 const auto colorsBufferDescriptorInfo = vk::makeDescriptorBufferInfo(m_colorsBuffer->get(), 0ull, VK_WHOLE_SIZE);
892 vk::DescriptorSetUpdateBuilder updateBuilder;
893 updateBuilder.writeSingle(m_descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &colorsBufferDescriptorInfo);
894 updateBuilder.update(vk, device);
896 vk.cmdBindDescriptorSets(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout.get(), 0u, 1u, &m_descriptorSet.get(), 0u, nullptr);
899 vk.cmdDraw(cmdBuffer, static_cast<deUint32>(m_numViewports * 6), 1u, 0u, 0u); // two triangles per viewport
903 const SharedGroupParams m_groupParams;
904 const UVec2 m_renderSize;
905 const VkFormat m_colorFormat;
906 const VkImageSubresourceRange m_colorSubresourceRange;
907 const VkClearValue m_clearValue;
908 const int m_numViewports;
909 const std::vector<Vec4> m_colors;
910 const std::vector<PositionColorVertex> m_vertices;
911 const Shader m_shader;
913 Move<VkImage> m_colorImage;
914 MovePtr<Allocation> m_colorImageAlloc;
915 Move<VkImageView> m_colorAttachment;
916 SharedPtr<BufferWithMemory> m_colorsBuffer;
917 SharedPtr<Buffer> m_vertexBuffer;
918 Move<VkShaderModule> m_vertexModule;
919 Move<VkShaderModule> m_tessellationControlModule;
920 Move<VkShaderModule> m_tessellationEvaluationModule;
921 Move<VkShaderModule> m_fragmentModule;
922 Move<VkRenderPass> m_renderPass;
923 Move<VkFramebuffer> m_framebuffer;
924 Move<VkDescriptorPool> m_descriptorPool;
925 Move<VkDescriptorSet> m_descriptorSet;
926 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
927 Move<VkPipelineLayout> m_pipelineLayout;
928 Move<VkPipeline> m_pipeline;
929 Move<VkCommandPool> m_cmdPool;
930 Move<VkCommandBuffer> m_cmdBuffer;
931 Move<VkCommandBuffer> m_secCmdBuffer;
934 Renderer (const Renderer&);
935 Renderer& operator= (const Renderer&);
938 tcu::TestStatus testVertexFragmentShader (Context& context, const TestParams& testParams, Renderer::Shader shader)
940 const DeviceInterface& vk = context.getDeviceInterface();
941 const VkDevice device = context.getDevice();
942 Allocator& allocator = context.getDefaultAllocator();
944 const UVec2 renderSize (128, 128);
945 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
946 const Vec4 clearColor (0.5f, 0.5f, 0.5f, 1.0f);
947 const std::vector<Vec4> colors = generateColors(testParams.numViewports);
948 const std::vector<UVec4> cells = generateGrid(testParams.numViewports, renderSize);
950 const VkDeviceSize colorBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
952 const SharedPtr<Buffer> colorBuffer = Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), allocator, MemoryRequirement::HostVisible);
956 const Allocation alloc = colorBuffer->getBoundMemory();
957 deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
958 flushAlloc(vk, device, alloc);
962 context.getTestContext().getLog()
963 << tcu::TestLog::Message << "Rendering a colorful grid of " << testParams.numViewports << " rectangle(s)." << tcu::TestLog::EndMessage
964 << tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage;
969 Renderer renderer (context, renderSize, testParams, cells, colorFormat, clearColor, colors, shader);
970 renderer.draw(context, colorBuffer->object());
975 const Allocation alloc = colorBuffer->getBoundMemory();
976 invalidateAlloc(vk, device, alloc);
978 const tcu::ConstPixelBufferAccess resultImage (mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, alloc.getHostPtr());
979 const tcu::TextureLevel referenceImage = generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, cells, colors);
981 // Images should now match.
982 if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
983 TCU_FAIL("Rendered image is not correct");
986 return tcu::TestStatus::pass("OK");
989 tcu::TestStatus testVertexShader (Context& context, const TestParams testParams)
991 return testVertexFragmentShader(context, testParams, Renderer::VERTEX);
994 tcu::TestStatus testFragmentShader (Context& context, const TestParams testParams)
996 return testVertexFragmentShader(context, testParams, Renderer::FRAGMENT);
999 tcu::TestStatus testTessellationShader (Context& context, const TestParams testParams)
1001 const DeviceInterface& vk = context.getDeviceInterface();
1002 const VkDevice device = context.getDevice();
1003 Allocator& allocator = context.getDefaultAllocator();
1005 const UVec2 renderSize (128, 128);
1006 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
1007 const Vec4 clearColor (0.5f, 0.5f, 0.5f, 1.0f);
1008 const std::vector<Vec4> colors = generateColors(testParams.numViewports);
1009 const std::vector<UVec4> cells = generateGrid(testParams.numViewports, renderSize);
1011 const VkDeviceSize colorBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
1013 const SharedPtr<Buffer> colorBuffer = Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), allocator, MemoryRequirement::HostVisible);
1017 const Allocation alloc = colorBuffer->getBoundMemory();
1018 deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
1019 flushAlloc(vk, device, alloc);
1023 context.getTestContext().getLog()
1024 << tcu::TestLog::Message << "Rendering a colorful grid of " << testParams.numViewports << " rectangle(s)." << tcu::TestLog::EndMessage
1025 << tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage;
1030 Renderer renderer (context, renderSize, testParams, cells, colorFormat, clearColor, colors, Renderer::TESSELLATION);
1031 renderer.draw(context, colorBuffer->object());
1036 const Allocation alloc = colorBuffer->getBoundMemory();
1037 invalidateAlloc(vk, device, alloc);
1039 const tcu::ConstPixelBufferAccess resultImage (mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, alloc.getHostPtr());
1040 const tcu::TextureLevel referenceImage = generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, cells, colors);
1042 // Images should now match.
1043 if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
1044 TCU_FAIL("Rendered image is not correct");
1047 return tcu::TestStatus::pass("OK");
1050 void checkSupport (Context& context, TestParams params)
1052 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
1053 context.requireDeviceFunctionality("VK_EXT_shader_viewport_index_layer");
1055 if (context.getDeviceProperties().limits.maxViewports < MIN_MAX_VIEWPORTS)
1056 TCU_FAIL("multiViewport supported but maxViewports is less than the minimum required");
1058 if (params.useTessellationShader)
1059 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
1061 if (params.groupParams->useDynamicRendering)
1062 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
1067 tcu::TestCaseGroup* createShaderViewportIndexTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
1069 MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "shader_viewport_index", ""));
1071 TestParams testParams
1073 1, // int numViewports;
1074 false, // bool writeFromVertex;
1075 groupParams, // SharedGroupParams groupParams;
1076 false // bool useTessellationShader;
1079 for (testParams.numViewports = 1; testParams.numViewports <= MIN_MAX_VIEWPORTS; ++testParams.numViewports)
1080 addFunctionCaseWithPrograms(group.get(), "vertex_shader_" + de::toString(testParams.numViewports), "", checkSupport, initVertexTestPrograms, testVertexShader, testParams);
1082 testParams.numViewports = 1;
1083 addFunctionCaseWithPrograms(group.get(), "fragment_shader_implicit", "", checkSupport, initFragmentTestPrograms, testFragmentShader, testParams);
1084 testParams.writeFromVertex = true;
1085 for (testParams.numViewports = 1; testParams.numViewports <= MIN_MAX_VIEWPORTS; ++testParams.numViewports)
1086 addFunctionCaseWithPrograms(group.get(), "fragment_shader_" + de::toString(testParams.numViewports), "", checkSupport, initFragmentTestPrograms, testFragmentShader, testParams);
1087 testParams.writeFromVertex = false;
1089 testParams.useTessellationShader = true;
1090 for (testParams.numViewports = 1; testParams.numViewports <= MIN_MAX_VIEWPORTS; ++testParams.numViewports)
1091 addFunctionCaseWithPrograms(group.get(), "tessellation_shader_" + de::toString(testParams.numViewports), "", checkSupport, initTessellationTestPrograms, testTessellationShader, testParams);
1093 return group.release();