• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 The Khronos Group Inc.
6  * Copyright (c) 2018 The Android Open Source Project
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Use of gl_Layer in Vertex and Tessellation Shaders
23  *        (part of VK_EXT_ShaderViewportIndexLayer)
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktDrawShaderLayerTests.hpp"
27 
28 #include "vktDrawBaseClass.hpp"
29 #include "vktTestCaseUtil.hpp"
30 
31 #include "vkDefs.hpp"
32 #include "vkRef.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 
42 #include "tcuTestLog.hpp"
43 #include "tcuVector.hpp"
44 #include "tcuImageCompare.hpp"
45 #include "tcuTextureUtil.hpp"
46 
47 #include "deUniquePtr.hpp"
48 #include "deMath.h"
49 
50 #include <vector>
51 
52 namespace vkt
53 {
54 namespace Draw
55 {
56 using namespace vk;
57 using de::UniquePtr;
58 using de::MovePtr;
59 using de::SharedPtr;
60 using tcu::Vec4;
61 using tcu::Vec2;
62 using tcu::UVec2;
63 using tcu::UVec4;
64 
65 namespace
66 {
67 
68 enum Constants
69 {
70 	MIN_MAX_FRAMEBUFFER_LAYERS = 256,	//!< Minimum number of framebuffer layers.
71 	MIN_MAX_VIEWPORTS = 16,				//!< Minimum number of viewports for an implementation supporting multiViewport.
72 };
73 
74 struct TestParams
75 {
76 	int		numLayers;
77 	bool	useDynamicRendering;
78 };
79 
80 template<typename T>
sizeInBytes(const std::vector<T> & vec)81 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
82 {
83 	return vec.size() * sizeof(vec[0]);
84 }
85 
makeImageCreateInfo(const VkFormat format,const UVec2 & size,const deUint32 numLayers,VkImageUsageFlags usage)86 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const UVec2& size, const deUint32 numLayers, VkImageUsageFlags usage)
87 {
88 	const VkImageCreateInfo imageParams =
89 	{
90 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
91 		DE_NULL,										// const void*				pNext;
92 		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
93 		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
94 		format,											// VkFormat					format;
95 		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
96 		1u,												// deUint32					mipLevels;
97 		numLayers,										// deUint32					arrayLayers;
98 		VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
99 		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
100 		usage,											// VkImageUsageFlags		usage;
101 		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
102 		0u,												// deUint32					queueFamilyIndexCount;
103 		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
104 		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
105 	};
106 	return imageParams;
107 }
108 
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule tessellationControlModule,const VkShaderModule tessellationEvaluationModule,const VkShaderModule fragmentModule,const UVec2 renderSize)109 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&		vk,
110 									   const VkDevice				device,
111 									   const VkPipelineLayout		pipelineLayout,
112 									   const VkRenderPass			renderPass,
113 									   const VkShaderModule			vertexModule,
114 									   const VkShaderModule			tessellationControlModule,
115 									   const VkShaderModule			tessellationEvaluationModule,
116 									   const VkShaderModule			fragmentModule,
117 									   const UVec2					renderSize)
118 {
119 	const VkVertexInputBindingDescription vertexInputBindingDescription =
120 	{
121 		0u,								// uint32_t				binding;
122 		sizeof(PositionColorVertex),	// uint32_t				stride;
123 		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
124 	};
125 
126 	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
127 	{
128 		{
129 			0u,									// uint32_t			location;
130 			0u,									// uint32_t			binding;
131 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
132 			0u,									// uint32_t			offset;
133 		},
134 		{
135 			1u,									// uint32_t			location;
136 			0u,									// uint32_t			binding;
137 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
138 			sizeof(Vec4),						// uint32_t			offset;
139 		},
140 	};
141 
142 	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
143 	{
144 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
145 		DE_NULL,														// const void*                                 pNext;
146 		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
147 		1u,																// uint32_t                                    vertexBindingDescriptionCount;
148 		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
149 		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),			// uint32_t                                    vertexAttributeDescriptionCount;
150 		vertexInputAttributeDescriptions,								// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
151 	};
152 
153 	const bool useTessellationShaders = (tessellationControlModule != DE_NULL) && (tessellationEvaluationModule != DE_NULL);
154 
155 	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
156 	{
157 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,										// VkStructureType                             sType;
158 		DE_NULL,																							// const void*                                 pNext;
159 		(VkPipelineInputAssemblyStateCreateFlags)0,															// VkPipelineInputAssemblyStateCreateFlags     flags;
160 		useTessellationShaders ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	// VkPrimitiveTopology                         topology;
161 		VK_FALSE,																							// VkBool32                                    primitiveRestartEnable;
162 	};
163 
164 
165 	VkViewport viewport = makeViewport(0.0f, 0.0f, static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()), 0.0f, 1.0f);
166 	VkRect2D rectScissor = { { 0, 0 }, { renderSize.x(), renderSize.y() } };
167 
168 	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
169 	{
170 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType                             sType;
171 		DE_NULL,														// const void*                                 pNext;
172 		(VkPipelineViewportStateCreateFlags)0,							// VkPipelineViewportStateCreateFlags          flags;
173 		1u,																// uint32_t                                    viewportCount;
174 		&viewport,														// const VkViewport*                           pViewports;
175 		1u,																// uint32_t                                    scissorCount;
176 		&rectScissor,													// const VkRect2D*                             pScissors;
177 	};
178 
179 	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
180 	{
181 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
182 		DE_NULL,														// const void*                              pNext;
183 		(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
184 		VK_FALSE,														// VkBool32                                 depthClampEnable;
185 		VK_FALSE,														// VkBool32                                 rasterizerDiscardEnable;
186 		VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
187 		VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
188 		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
189 		VK_FALSE,														// VkBool32									depthBiasEnable;
190 		0.0f,															// float									depthBiasConstantFactor;
191 		0.0f,															// float									depthBiasClamp;
192 		0.0f,															// float									depthBiasSlopeFactor;
193 		1.0f,															// float									lineWidth;
194 	};
195 
196 	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
197 	{
198 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
199 		DE_NULL,														// const void*								pNext;
200 		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags	flags;
201 		VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits					rasterizationSamples;
202 		VK_FALSE,														// VkBool32									sampleShadingEnable;
203 		0.0f,															// float									minSampleShading;
204 		DE_NULL,														// const VkSampleMask*						pSampleMask;
205 		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
206 		VK_FALSE														// VkBool32									alphaToOneEnable;
207 	};
208 
209 	const VkStencilOpState stencilOpState = makeStencilOpState(
210 		VK_STENCIL_OP_KEEP,				// stencil fail
211 		VK_STENCIL_OP_KEEP,				// depth & stencil pass
212 		VK_STENCIL_OP_KEEP,				// depth only fail
213 		VK_COMPARE_OP_ALWAYS,			// compare op
214 		0u,								// compare mask
215 		0u,								// write mask
216 		0u);							// reference
217 
218 	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
219 	{
220 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		// VkStructureType							sType;
221 		DE_NULL,														// const void*								pNext;
222 		(VkPipelineDepthStencilStateCreateFlags)0,						// VkPipelineDepthStencilStateCreateFlags	flags;
223 		VK_FALSE,														// VkBool32									depthTestEnable;
224 		VK_FALSE,														// VkBool32									depthWriteEnable;
225 		VK_COMPARE_OP_LESS,												// VkCompareOp								depthCompareOp;
226 		VK_FALSE,														// VkBool32									depthBoundsTestEnable;
227 		VK_FALSE,														// VkBool32									stencilTestEnable;
228 		stencilOpState,													// VkStencilOpState							front;
229 		stencilOpState,													// VkStencilOpState							back;
230 		0.0f,															// float									minDepthBounds;
231 		1.0f,															// float									maxDepthBounds;
232 	};
233 
234 	const VkColorComponentFlags					colorComponentsAll					= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
235 	const VkPipelineColorBlendAttachmentState	pipelineColorBlendAttachmentState	=
236 	{
237 		VK_FALSE,						// VkBool32					blendEnable;
238 		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcColorBlendFactor;
239 		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstColorBlendFactor;
240 		VK_BLEND_OP_ADD,				// VkBlendOp				colorBlendOp;
241 		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcAlphaBlendFactor;
242 		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstAlphaBlendFactor;
243 		VK_BLEND_OP_ADD,				// VkBlendOp				alphaBlendOp;
244 		colorComponentsAll,				// VkColorComponentFlags	colorWriteMask;
245 	};
246 
247 	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
248 	{
249 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
250 		DE_NULL,														// const void*									pNext;
251 		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
252 		VK_FALSE,														// VkBool32										logicOpEnable;
253 		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
254 		1u,																// deUint32										attachmentCount;
255 		&pipelineColorBlendAttachmentState,								// const VkPipelineColorBlendAttachmentState*	pAttachments;
256 		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
257 	};
258 
259 	const VkPipelineShaderStageCreateInfo pShaderStages[] =
260 	{
261 		{
262 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
263 			DE_NULL,													// const void*							pNext;
264 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
265 			VK_SHADER_STAGE_VERTEX_BIT,									// VkShaderStageFlagBits				stage;
266 			vertexModule,												// VkShaderModule						module;
267 			"main",														// const char*							pName;
268 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
269 		},
270 		{
271 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
272 			DE_NULL,													// const void*							pNext;
273 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
274 			VK_SHADER_STAGE_FRAGMENT_BIT,								// VkShaderStageFlagBits				stage;
275 			fragmentModule,												// VkShaderModule						module;
276 			"main",														// const char*							pName;
277 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
278 		},
279 		{
280 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
281 			DE_NULL,													// const void*							pNext;
282 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
283 			VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,					// VkShaderStageFlagBits				stage;
284 			tessellationControlModule,									// VkShaderModule						module;
285 			"main",														// const char*							pName;
286 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
287 		},
288 		{
289 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
290 			DE_NULL,													// const void*							pNext;
291 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
292 			VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,				// VkShaderStageFlagBits				stage;
293 			tessellationEvaluationModule,								// VkShaderModule						module;
294 			"main",														// const char*							pName;
295 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
296 		},
297 	};
298 
299 	const VkPipelineTessellationStateCreateInfo pipelineTessellationStateInfo =
300 	{
301 		VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,		// VkStructureType							sType;
302 		DE_NULL,														// const void*								pNext;
303 		(VkPipelineTessellationStateCreateFlags)0,						// VkPipelineTessellationStateCreateFlags	flags;
304 		3,																// uint32_t									patchControlPoints;
305 	};
306 
307 	VkGraphicsPipelineCreateInfo graphicsPipelineInfo
308 	{
309 		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,					// VkStructureType									sType;
310 		DE_NULL,															// const void*										pNext;
311 		(VkPipelineCreateFlags)0,											// VkPipelineCreateFlags							flags;
312 		useTessellationShaders ? deUint32(4) : deUint32(2),					// deUint32											stageCount;
313 		pShaderStages,														// const VkPipelineShaderStageCreateInfo*			pStages;
314 		&vertexInputStateInfo,												// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
315 		&pipelineInputAssemblyStateInfo,									// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
316 		useTessellationShaders ? &pipelineTessellationStateInfo : DE_NULL,	// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
317 		&pipelineViewportStateInfo,											// const VkPipelineViewportStateCreateInfo*			pViewportState;
318 		&pipelineRasterizationStateInfo,									// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
319 		&pipelineMultisampleStateInfo,										// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
320 		&pipelineDepthStencilStateInfo,										// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
321 		&pipelineColorBlendStateInfo,										// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
322 		DE_NULL,															// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
323 		pipelineLayout,														// VkPipelineLayout									layout;
324 		renderPass,															// VkRenderPass										renderPass;
325 		0u,																	// deUint32											subpass;
326 		DE_NULL,															// VkPipeline										basePipelineHandle;
327 		0,																	// deInt32											basePipelineIndex;
328 	};
329 
330 	VkFormat colorAttachmentFormat = VK_FORMAT_R8G8B8A8_UNORM;
331 	VkPipelineRenderingCreateInfoKHR renderingCreateInfo
332 	{
333 		VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
334 		DE_NULL,
335 		0u,
336 		1u,
337 		&colorAttachmentFormat,
338 		VK_FORMAT_UNDEFINED,
339 		VK_FORMAT_UNDEFINED
340 	};
341 
342 	// when pipeline is created without render pass we are using dynamic rendering
343 	if (renderPass == DE_NULL)
344 		graphicsPipelineInfo.pNext = &renderingCreateInfo;
345 
346 	return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
347 }
348 
349 //! Renders a colorful grid of rectangles.
generateReferenceImage(const tcu::TextureFormat format,const UVec2 & renderSize,const Vec4 & clearColor,const UVec4 & cell,const Vec4 & cellColor)350 tcu::TextureLevel generateReferenceImage (const tcu::TextureFormat	format,
351 										  const UVec2&				renderSize,
352 										  const Vec4&				clearColor,
353 										  const UVec4&				cell,
354 										  const Vec4&				cellColor)
355 {
356 	tcu::TextureLevel image(format, renderSize.x(), renderSize.y());
357 	tcu::clear(image.getAccess(), clearColor);
358 
359 	tcu::clear(tcu::getSubregion(image.getAccess(), cell.x(), cell.y(), cell.z(), cell.w()),
360 			   cellColor);
361 
362 	return image;
363 }
364 
initVertexTestPrograms(SourceCollections & programCollection,const TestParams params)365 void initVertexTestPrograms (SourceCollections& programCollection, const TestParams params)
366 {
367 	DE_UNREF(params.numLayers);
368 
369 	// Vertex shader
370 	{
371 		std::ostringstream src;
372 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
373 			<< "#extension GL_ARB_shader_viewport_layer_array : require\n"
374 			<< "\n"
375 			<< "layout(location = 0) in  vec4 in_position;\n"
376 			<< "layout(location = 1) in  vec4 in_color;\n"
377 			<< "layout(location = 0) out vec4 out_color;\n"
378 			<< "\n"
379 			<< "void main(void)\n"
380 			<< "{\n"
381 			<< "    gl_Layer = gl_VertexIndex / 6;\n"
382 			<< "    gl_Position = in_position;\n"
383 			<< "    out_color = in_color;\n"
384 			<< "}\n";
385 
386 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
387 	}
388 
389 	// Fragment shader
390 	{
391 		std::ostringstream src;
392 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
393 			<< "\n"
394 			<< "layout(location = 0) in  vec4 in_color;\n"
395 			<< "layout(location = 0) out vec4 out_color;\n"
396 			<< "\n"
397 			<< "void main(void)\n"
398 			<< "{\n"
399 			<< "    out_color = in_color;\n"
400 			<< "}\n";
401 
402 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
403 	}
404 }
405 
initTessellationTestPrograms(SourceCollections & programCollection,const TestParams params)406 void initTessellationTestPrograms (SourceCollections& programCollection, const TestParams params)
407 {
408 	DE_UNREF(params.numLayers);
409 
410 	// Vertex shader
411 	{
412 		std::ostringstream src;
413 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
414 			<< "\n"
415 			<< "layout(location = 0) in  vec4 in_position;\n"
416 			<< "layout(location = 1) in  vec4 in_color;\n"
417 			<< "layout(location = 0) out vec4 out_color;\n"
418 			<< "\n"
419 			<< "void main(void)\n"
420 			<< "{\n"
421 			<< "    gl_Position = in_position;\n"
422 			<< "    out_color = in_color;\n"
423 			<< "}\n";
424 
425 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
426 	}
427 
428 	// Tessellation control shader
429 	{
430 		std::ostringstream src;
431 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
432 			<< "\n"
433 			<< "layout(vertices = 3) out;\n"
434 			<< "\n"
435 			<< "layout(location = 0) in  vec4 in_color[];\n"
436 			<< "layout(location = 0) out vec4 out_color[];\n"
437 			<< "\n"
438 			<< "void main(void)\n"
439 			<< "{\n"
440 			<< "    if (gl_InvocationID == 0) {\n"
441 			<< "        gl_TessLevelInner[0] = 1.0;\n"
442 			<< "        gl_TessLevelInner[1] = 1.0;\n"
443 			<< "        gl_TessLevelOuter[0] = 1.0;\n"
444 			<< "        gl_TessLevelOuter[1] = 1.0;\n"
445 			<< "        gl_TessLevelOuter[2] = 1.0;\n"
446 			<< "        gl_TessLevelOuter[3] = 1.0;\n"
447 			<< "    }\n"
448 			<< "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
449 			<< "    out_color[gl_InvocationID] = in_color[gl_InvocationID];\n"
450 			<< "}\n";
451 
452 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
453 	}
454 
455 	// Tessellation evaluation shader
456 	{
457 		std::ostringstream src;
458 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
459 			<< "#extension GL_ARB_shader_viewport_layer_array : require\n"
460 			<< "\n"
461 			<< "layout(triangles, equal_spacing, cw) in;\n"
462 			<< "\n"
463 			<< "layout(location = 0) in  vec4 in_color[];\n"
464 			<< "layout(location = 0) out vec4 out_color;\n"
465 			<< "\n"
466 			<< "void main(void)\n"
467 			<< "{\n"
468 			<< "    gl_Layer = gl_PrimitiveID / 2;\n"
469 			<< "    gl_Position = gl_in[0].gl_Position * gl_TessCoord.x +\n"
470 			<< "                  gl_in[1].gl_Position * gl_TessCoord.y +\n"
471 			<< "                  gl_in[2].gl_Position * gl_TessCoord.z;\n"
472 			<< "\n"
473 			<< "    out_color = in_color[0] * gl_TessCoord.x +\n"
474 			<< "                in_color[1] * gl_TessCoord.y +\n"
475 			<< "                in_color[2] * gl_TessCoord.z;\n"
476 			<< "}\n";
477 
478 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
479 	}
480 
481 	// Fragment shader
482 	{
483 		std::ostringstream src;
484 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
485 			<< "\n"
486 			<< "layout(location = 0) in  vec4 in_color;\n"
487 			<< "layout(location = 0) out vec4 out_color;\n"
488 			<< "\n"
489 			<< "void main(void)\n"
490 			<< "{\n"
491 			<< "    out_color = in_color;\n"
492 			<< "}\n";
493 
494 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
495 	}
496 }
497 
generateGrid(const int numCells,const UVec2 & renderSize)498 std::vector<UVec4> generateGrid (const int numCells, const UVec2& renderSize)
499 {
500 	const int numCols		= deCeilFloatToInt32(deFloatSqrt(static_cast<float>(numCells)));
501 	const int numRows		= deCeilFloatToInt32(static_cast<float>(numCells) / static_cast<float>(numCols));
502 	const int rectWidth		= renderSize.x() / numCols;
503 	const int rectHeight	= renderSize.y() / numRows;
504 
505 	std::vector<UVec4> cells;
506 	cells.reserve(numCells);
507 
508 	int x = 0;
509 	int y = 0;
510 
511 	for (int cellNdx = 0; cellNdx < numCells; ++cellNdx)
512 	{
513 		const bool nextRow = (cellNdx != 0) && (cellNdx % numCols == 0);
514 		if (nextRow)
515 		{
516 			x  = 0;
517 			y += rectHeight;
518 		}
519 
520 		cells.push_back(UVec4(x, y, rectWidth, rectHeight));
521 
522 		x += rectWidth;
523 	}
524 
525 	return cells;
526 }
527 
generateColors(int numColors)528 std::vector<Vec4> generateColors (int numColors)
529 {
530 	const Vec4 colors[] =
531 	{
532 		Vec4(0.18f, 0.42f, 0.17f, 1.0f),
533 		Vec4(0.29f, 0.62f, 0.28f, 1.0f),
534 		Vec4(0.59f, 0.84f, 0.44f, 1.0f),
535 		Vec4(0.96f, 0.95f, 0.72f, 1.0f),
536 		Vec4(0.94f, 0.55f, 0.39f, 1.0f),
537 		Vec4(0.82f, 0.19f, 0.12f, 1.0f),
538 		Vec4(0.46f, 0.15f, 0.26f, 1.0f),
539 		Vec4(0.24f, 0.14f, 0.24f, 1.0f),
540 		Vec4(0.49f, 0.31f, 0.26f, 1.0f),
541 		Vec4(0.78f, 0.52f, 0.33f, 1.0f),
542 		Vec4(0.94f, 0.82f, 0.31f, 1.0f),
543 		Vec4(0.98f, 0.65f, 0.30f, 1.0f),
544 		Vec4(0.22f, 0.65f, 0.53f, 1.0f),
545 		Vec4(0.67f, 0.81f, 0.91f, 1.0f),
546 		Vec4(0.43f, 0.44f, 0.75f, 1.0f),
547 		Vec4(0.26f, 0.24f, 0.48f, 1.0f),
548 	};
549 
550 	std::vector<Vec4> result;
551 	result.reserve(numColors);
552 
553 	for (int i = 0; i < numColors; ++i)
554 	{
555 		result.push_back(colors[i % DE_LENGTH_OF_ARRAY(colors)]);
556 	}
557 
558 	return result;
559 }
560 
generateVertices(const std::vector<UVec4> & grid,const std::vector<Vec4> & colors,const UVec2 & renderSize)561 std::vector<PositionColorVertex> generateVertices (const std::vector<UVec4>& grid, const std::vector<Vec4>& colors, const UVec2& renderSize)
562 {
563 	DE_ASSERT(colors.size() == grid.size());
564 
565 	// Two triangles for each cell. Each cell correspond to a layer.
566 	std::size_t total = grid.size() * 6;
567 
568 	std::vector<PositionColorVertex> result;
569 	result.reserve(total);
570 
571 	for (std::size_t i = 0; i < total; ++i)
572 	{
573 		Vec4 pos;
574 		pos.z() = 0.0;
575 		pos.w() = 1.0;
576 
577 		Vec4 cell = grid[i/6].asFloat() * 2.0f;
578 		float x			= cell.x() / float(renderSize.x()) - 1.0f;
579 		float y			= cell.y() / float(renderSize.y()) - 1.0f;
580 		float width		= cell.z() / float(renderSize.x());
581 		float height	= cell.w() / float(renderSize.y());
582 
583 		switch (i % 6)
584 		{
585 		case 0: pos.xy() = Vec2(x,			y + height);	break;
586 		case 1: pos.xy() = Vec2(x + width,	y + height);	break;
587 		case 2: pos.xy() = Vec2(x,			y);				break;
588 		case 3: pos.xy() = Vec2(x + width,	y);				break;
589 		case 4: pos.xy() = Vec2(x + width,	y + height);	break;
590 		case 5: pos.xy() = Vec2(x,			y);				break;
591 		}
592 
593 		result.push_back(PositionColorVertex(pos, colors[i/6]));
594 	}
595 
596 	return result;
597 }
598 
599 // Renderer generates two triangles per layer, each pair using a different
600 // color and a different position.
601 class Renderer
602 {
603 public:
604 	enum Shader
605 	{
606 		VERTEX,
607 		TESSELLATION,
608 	};
609 
Renderer(Context & context,const bool useDynamicRendering,const UVec2 & renderSize,const int numLayers,const VkFormat colorFormat,const Vec4 & clearColor,const std::vector<PositionColorVertex> & vertices,const Shader shader)610 	Renderer (Context&									context,
611 			  const bool								useDynamicRendering,
612 			  const UVec2&								renderSize,
613 			  const int									numLayers,
614 			  const VkFormat							colorFormat,
615 			  const Vec4&								clearColor,
616 			  const std::vector<PositionColorVertex>&	vertices,
617 			  const Shader								shader)
618 		: m_useDynamicRendering		(useDynamicRendering)
619 		, m_renderSize				(renderSize)
620 		, m_colorFormat				(colorFormat)
621 		, m_colorSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, numLayers))
622 		, m_clearColor				(clearColor)
623 		, m_numLayers				(numLayers)
624 		, m_vertices				(vertices)
625 	{
626 		const DeviceInterface&		vk					= context.getDeviceInterface();
627 		const VkDevice				device				= context.getDevice();
628 		const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
629 		Allocator&					allocator			= context.getDefaultAllocator();
630 		const VkDeviceSize			vertexBufferSize    = sizeInBytes(m_vertices);
631 
632 		m_colorImage		= makeImage					(vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, m_numLayers, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
633 		m_colorImageAlloc	= bindImage					(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
634 		m_colorAttachment	= makeImageView				(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D_ARRAY, m_colorFormat, m_colorSubresourceRange);
635 
636 		m_vertexBuffer		= Buffer::createAndAlloc	(vk, device, makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), allocator, MemoryRequirement::HostVisible);
637 
638 		deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), &m_vertices[0], static_cast<std::size_t>(vertexBufferSize));
639 		flushAlloc(vk, device, m_vertexBuffer->getBoundMemory());
640 
641 		if (shader == TESSELLATION)
642 		{
643 			m_tessellationControlModule		= createShaderModule	(vk, device, context.getBinaryCollection().get("tesc"), 0u);
644 			m_tessellationEvaluationModule	= createShaderModule	(vk, device, context.getBinaryCollection().get("tese"), 0u);
645 		}
646 
647 		m_vertexModule		= createShaderModule	(vk, device, context.getBinaryCollection().get("vert"), 0u);
648 		m_fragmentModule	= createShaderModule	(vk, device, context.getBinaryCollection().get("frag"), 0u);
649 
650 		if (!m_useDynamicRendering)
651 		{
652 			m_renderPass	= makeRenderPass		(vk, device, m_colorFormat);
653 
654 			m_framebuffer	= makeFramebuffer		(vk, device, *m_renderPass, m_colorAttachment.get(),
655 													 static_cast<deUint32>(m_renderSize.x()),
656 													 static_cast<deUint32>(m_renderSize.y()),
657 													 numLayers);
658 		}
659 
660 		m_pipelineLayout	= makePipelineLayout	(vk, device);
661 		m_pipeline			= makeGraphicsPipeline	(vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_tessellationControlModule,
662 													 *m_tessellationEvaluationModule, *m_fragmentModule, m_renderSize);
663 		m_cmdPool			= createCommandPool		(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
664 		m_cmdBuffer			= allocateCommandBuffer	(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
665 	}
666 
draw(Context & context,const VkBuffer colorBuffer) const667 	void draw (Context& context, const VkBuffer colorBuffer) const
668 	{
669 		const DeviceInterface&		vk			= context.getDeviceInterface();
670 		const VkDevice				device		= context.getDevice();
671 		const VkQueue				queue		= context.getUniversalQueue();
672 
673 		beginCommandBuffer(vk, *m_cmdBuffer);
674 
675 		const VkClearValue			clearValue	= makeClearValueColor(m_clearColor);
676 		const VkRect2D				renderArea	=
677 		{
678 			makeOffset2D(0, 0),
679 			makeExtent2D(m_renderSize.x(), m_renderSize.y()),
680 		};
681 
682 		if (m_useDynamicRendering)
683 		{
684 			initialTransitionColor2DImage(vk, *m_cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
685 										  VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
686 			beginRendering(vk, *m_cmdBuffer, *m_colorAttachment, renderArea, clearValue, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR, 0, m_numLayers);
687 		}
688 		else
689 		{
690 			const VkRenderPassBeginInfo renderPassBeginInfo =
691 			{
692 				VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
693 				DE_NULL,										// const void*             pNext;
694 				*m_renderPass,									// VkRenderPass            renderPass;
695 				*m_framebuffer,									// VkFramebuffer           framebuffer;
696 				renderArea,										// VkRect2D                renderArea;
697 				1u,												// uint32_t                clearValueCount;
698 				&clearValue,									// const VkClearValue*     pClearValues;
699 			};
700 			vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
701 		}
702 
703 		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
704 		{
705 			const VkBuffer vertexBuffer = m_vertexBuffer->object();
706 			const VkDeviceSize vertexBufferOffset = 0ull;
707 			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
708 		}
709 		vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_numLayers * 6), 1u, 0u, 0u);	// two triangles per layer
710 
711 		if (m_useDynamicRendering)
712 			endRendering(vk, *m_cmdBuffer);
713 		else
714 			vk.cmdEndRenderPass(*m_cmdBuffer);
715 
716 		copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, colorBuffer, tcu::IVec2(m_renderSize.x(), m_renderSize.y()), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, m_colorSubresourceRange.layerCount);
717 
718 		endCommandBuffer(vk, *m_cmdBuffer);
719 		submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
720 	}
721 
722 private:
723 	const bool								m_useDynamicRendering;
724 	const UVec2								m_renderSize;
725 	const VkFormat							m_colorFormat;
726 	const VkImageSubresourceRange			m_colorSubresourceRange;
727 	const Vec4								m_clearColor;
728 	const int								m_numLayers;
729 	const std::vector<PositionColorVertex>	m_vertices;
730 
731 	Move<VkImage>							m_colorImage;
732 	MovePtr<Allocation>						m_colorImageAlloc;
733 	Move<VkImageView>						m_colorAttachment;
734 	SharedPtr<Buffer>						m_vertexBuffer;
735 	Move<VkShaderModule>					m_vertexModule;
736 	Move<VkShaderModule>					m_tessellationControlModule;
737 	Move<VkShaderModule>					m_tessellationEvaluationModule;
738 	Move<VkShaderModule>					m_fragmentModule;
739 	Move<VkRenderPass>						m_renderPass;
740 	Move<VkFramebuffer>						m_framebuffer;
741 	Move<VkPipelineLayout>					m_pipelineLayout;
742 	Move<VkPipeline>						m_pipeline;
743 	Move<VkCommandPool>						m_cmdPool;
744 	Move<VkCommandBuffer>					m_cmdBuffer;
745 
746 	// "deleted"
747 				Renderer	(const Renderer&);
748 	Renderer&	operator=	(const Renderer&);
749 };
750 
checkRequirements(Context & context,const TestParams params)751 void checkRequirements (Context& context, const TestParams params)
752 {
753 	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
754 	context.requireDeviceFunctionality("VK_EXT_shader_viewport_index_layer");
755 
756 	if (params.useDynamicRendering)
757 		context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
758 
759 	const VkPhysicalDeviceLimits	limits	= context.getDeviceProperties().limits;
760 
761 	if (limits.maxFramebufferLayers < MIN_MAX_FRAMEBUFFER_LAYERS)
762 		TCU_FAIL("maxFramebuffersLayers is less than the minimum required");
763 
764 	if (limits.maxViewports < MIN_MAX_VIEWPORTS)
765 		TCU_FAIL("multiViewport supported but maxViewports is less than the minimum required");
766 }
767 
testVertexShader(Context & context,const TestParams params)768 tcu::TestStatus testVertexShader (Context& context, const TestParams params)
769 {
770 	const DeviceInterface&					vk					= context.getDeviceInterface();
771 	const VkDevice							device				= context.getDevice();
772 	Allocator&								allocator			= context.getDefaultAllocator();
773 
774 	const UVec2								renderSize			(256, 256);
775 	const VkFormat							colorFormat			= VK_FORMAT_R8G8B8A8_UNORM;
776 	const Vec4								clearColor			(0.5f, 0.5f, 0.5f, 1.0f);
777 	const std::vector<UVec4>				grid				= generateGrid(params.numLayers, renderSize);
778 	const std::vector<Vec4>					colors				= generateColors(params.numLayers);
779 	const std::vector<PositionColorVertex>	vertices			= generateVertices(grid, colors, renderSize);
780 
781 	const VkDeviceSize						colorBufferSize		= renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat)) * params.numLayers;
782 
783 	const SharedPtr<Buffer>					colorBuffer			= Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), allocator, MemoryRequirement::HostVisible);
784 
785 	// Zero buffer.
786 	{
787 		const Allocation alloc = colorBuffer->getBoundMemory();
788 		deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
789 		flushAlloc(vk, device, alloc);
790 	}
791 
792 	{
793 		context.getTestContext().getLog()
794 			<< tcu::TestLog::Message << "Rendering a rectangle in each of the " << params.numLayers << " layer(s)." << tcu::TestLog::EndMessage
795 			<< tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage;
796 	}
797 
798 	// Draw.
799 	{
800 		const Renderer renderer (context, params.useDynamicRendering, renderSize, params.numLayers, colorFormat, clearColor, vertices, Renderer::VERTEX);
801 		renderer.draw(context, colorBuffer->object());
802 	}
803 
804 	// Verify layers.
805 	{
806 		const Allocation alloc = colorBuffer->getBoundMemory();
807 		invalidateAlloc(vk, device, alloc);
808 
809 		deUint8* resultMem = reinterpret_cast<deUint8*>(alloc.getHostPtr());
810 		for (int i = 0; i < params.numLayers; i++)
811 		{
812 			const tcu::ConstPixelBufferAccess	resultImage		(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, resultMem + ((colorBufferSize / params.numLayers) * i));
813 			const tcu::TextureLevel				referenceImage	= generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, grid[i], colors[i]);
814 			std::string imageSetName = "layer_" + de::toString(i);
815 			std::string imageSetDesc = "Image compare for layer " + de::toString(i);
816 			if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), imageSetName.c_str(), imageSetDesc.c_str(), referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
817 				TCU_FAIL("Rendered image is not correct");
818 		}
819 	}
820 
821 	return tcu::TestStatus::pass("OK");
822 }
823 
testTessellationShader(Context & context,const TestParams params)824 tcu::TestStatus testTessellationShader (Context& context, const TestParams params)
825 {
826 	const VkPhysicalDeviceFeatures&			features			= context.getDeviceFeatures();
827 	if (!features.tessellationShader)
828 		TCU_THROW(NotSupportedError, "Required feature is not supported: tessellationShader");
829 
830 	const DeviceInterface&					vk					= context.getDeviceInterface();
831 	const VkDevice							device				= context.getDevice();
832 	Allocator&								allocator			= context.getDefaultAllocator();
833 
834 	const UVec2								renderSize			(256, 256);
835 	const VkFormat							colorFormat			= VK_FORMAT_R8G8B8A8_UNORM;
836 	const Vec4								clearColor			(0.5f, 0.5f, 0.5f, 1.0f);
837 	const std::vector<UVec4>				grid				= generateGrid(params.numLayers, renderSize);
838 	const std::vector<Vec4>					colors				= generateColors(params.numLayers);
839 	const std::vector<PositionColorVertex>	vertices			= generateVertices(grid, colors, renderSize);
840 
841 	const VkDeviceSize						colorBufferSize		= renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat)) * params.numLayers;
842 
843 	const SharedPtr<Buffer>					colorBuffer			= Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), allocator, MemoryRequirement::HostVisible);
844 
845 	// Zero buffer.
846 	{
847 		const Allocation alloc = colorBuffer->getBoundMemory();
848 		deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
849 		flushAlloc(vk, device, alloc);
850 	}
851 
852 	{
853 		context.getTestContext().getLog()
854 			<< tcu::TestLog::Message << "Rendering a rectangle in each of the " << params.numLayers << " layer(s)." << tcu::TestLog::EndMessage
855 			<< tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage;
856 	}
857 
858 	// Draw.
859 	{
860 		const Renderer renderer (context, params.useDynamicRendering, renderSize, params.numLayers, colorFormat, clearColor, vertices, Renderer::TESSELLATION);
861 		renderer.draw(context, colorBuffer->object());
862 	}
863 
864 	// Verify layers.
865 	{
866 		const Allocation alloc = colorBuffer->getBoundMemory();
867 		invalidateAlloc(vk, device, alloc);
868 
869 		deUint8* resultMem = reinterpret_cast<deUint8*>(alloc.getHostPtr());
870 		for (int i = 0; i < params.numLayers; i++) {
871 			const tcu::ConstPixelBufferAccess	resultImage		(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, resultMem + ((colorBufferSize / params.numLayers) * i));
872 			const tcu::TextureLevel				referenceImage	= generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, grid[i], colors[i]);
873 			std::string imageSetName = "layer_" + de::toString(i);
874 			std::string imageSetDesc = "Image compare for layer " + de::toString(i);
875 			if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), imageSetName.c_str(), imageSetDesc.c_str(), referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
876 				TCU_FAIL("Rendered image is not correct");
877 		}
878 	}
879 
880 	return tcu::TestStatus::pass("OK");
881 }
882 
883 } // anonymous
884 
createShaderLayerTests(tcu::TestContext & testCtx,bool useDynamicRendering)885 tcu::TestCaseGroup* createShaderLayerTests	(tcu::TestContext& testCtx, bool useDynamicRendering)
886 {
887 	MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "shader_layer", ""));
888 
889 	int numLayersToTest[] =
890 	{
891 		1,
892 		2,
893 		3,
894 		4,
895 		5,
896 		6,
897 		7,
898 		8,
899 		MIN_MAX_FRAMEBUFFER_LAYERS,
900 	};
901 
902 	TestParams parmas
903 	{
904 		1,
905 		useDynamicRendering
906 	};
907 
908 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(numLayersToTest); ++i)
909 	{
910 		parmas.numLayers = numLayersToTest[i];
911 		addFunctionCaseWithPrograms<TestParams>(group.get(), "vertex_shader_" + de::toString(parmas.numLayers), "", checkRequirements, initVertexTestPrograms, testVertexShader, parmas);
912 	}
913 
914 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(numLayersToTest); ++i)
915 	{
916 		parmas.numLayers = numLayersToTest[i];
917 		addFunctionCaseWithPrograms<TestParams>(group.get(), "tessellation_shader_" + de::toString(parmas.numLayers), "", checkRequirements, initTessellationTestPrograms, testTessellationShader, parmas);
918 	}
919 
920 	return group.release();
921 }
922 
923 } // Draw
924 } // vkt
925