• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Valve Corporation.
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 Pipeline Cache Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktPipelineCreationFeedbackTests.hpp"
26 #include "vktPipelineVertexUtil.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktTestCaseUtil.hpp"
29 #include "vkMemUtil.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkObjUtil.hpp"
35 #include "tcuTestLog.hpp"
36 
37 #include <sstream>
38 #include <vector>
39 
40 namespace vkt
41 {
42 namespace pipeline
43 {
44 
45 using namespace vk;
46 
47 namespace
48 {
49 enum
50 {
51 	VK_MAX_SHADER_STAGES = 6,
52 };
53 
54 enum
55 {
56 	VK_MAX_PIPELINE_PARTS = 5,			// 4 parts + 1 final
57 };
58 
59 enum
60 {
61 	PIPELINE_CACHE_NDX_NO_CACHE = 0,
62 	PIPELINE_CACHE_NDX_DERIVATIVE = 1,
63 	PIPELINE_CACHE_NDX_CACHED = 2,
64 	PIPELINE_CACHE_NDX_COUNT,
65 };
66 
67 // helper functions
68 
getShaderFlagStr(const VkShaderStageFlags shader,bool isDescription)69 std::string getShaderFlagStr (const VkShaderStageFlags	shader,
70 							  bool						isDescription)
71 {
72 	std::ostringstream desc;
73 	if (shader & VK_SHADER_STAGE_COMPUTE_BIT)
74 	{
75 		desc << ((isDescription) ? "compute stage" : "compute_stage");
76 	}
77 	else
78 	{
79 		desc << ((isDescription) ? "vertex stage" : "vertex_stage");
80 		if (shader & VK_SHADER_STAGE_GEOMETRY_BIT)
81 			desc << ((isDescription) ? " geometry stage" : "_geometry_stage");
82 		if (shader & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
83 			desc << ((isDescription) ? " tessellation control stage" : "_tessellation_control_stage");
84 		if (shader & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
85 			desc << ((isDescription) ? " tessellation evaluation stage" : "_tessellation_evaluation_stage");
86 		desc << ((isDescription) ? " fragment stage" : "_fragment_stage");
87 	}
88 
89 	return desc.str();
90 }
91 
getCaseStr(const deUint32 ndx)92 std::string getCaseStr (const deUint32 ndx)
93 {
94 	switch(ndx)
95 	{
96 		case PIPELINE_CACHE_NDX_NO_CACHE:
97 			return "No cached pipeline";
98 		case PIPELINE_CACHE_NDX_CACHED:
99 			return "Cached pipeline";
100 		case PIPELINE_CACHE_NDX_DERIVATIVE:
101 			return "Pipeline derivative";
102 		default:
103 			DE_FATAL("Unknown case!");
104 	}
105 
106 	return "Unknown case";
107 }
108 
109 // helper classes
110 class CacheTestParam
111 {
112 public:
113 								CacheTestParam				(const PipelineConstructionType	pipelineConstructionType,
114 															 const VkShaderStageFlags		shaders,
115 															 deBool							noCache,
116 															 deBool							delayedDestroy,
117 															 deBool							zeroOutFeedbackCount = VK_FALSE);
118 	virtual						~CacheTestParam				(void) = default;
119 	virtual const std::string	generateTestName			(void)	const;
120 	virtual const std::string	generateTestDescription		(void)	const;
getPipelineConstructionType(void) const121 	PipelineConstructionType	getPipelineConstructionType	(void)	const	{ return m_pipelineConstructionType; }
getShaderFlags(void) const122 	VkShaderStageFlags			getShaderFlags				(void)	const	{ return m_shaders; }
isCacheDisabled(void) const123 	deBool						isCacheDisabled				(void)	const	{ return m_noCache; }
isDelayedDestroy(void) const124 	deBool						isDelayedDestroy			(void)	const	{ return m_delayedDestroy; }
isZeroOutFeedbackCount(void) const125 	deBool						isZeroOutFeedbackCount		(void)	const	{ return m_zeroOutFeedbackCount; }
126 
127 protected:
128 	PipelineConstructionType	m_pipelineConstructionType;
129 	VkShaderStageFlags			m_shaders;
130 	bool						m_noCache;
131 	bool						m_delayedDestroy;
132 	bool						m_zeroOutFeedbackCount;
133 };
134 
CacheTestParam(const PipelineConstructionType pipelineConstructionType,const VkShaderStageFlags shaders,deBool noCache,deBool delayedDestroy,deBool zeroOutFeedbackCount)135 CacheTestParam::CacheTestParam (const PipelineConstructionType pipelineConstructionType, const VkShaderStageFlags shaders, deBool noCache, deBool delayedDestroy, deBool zeroOutFeedbackCount)
136 	: m_pipelineConstructionType	(pipelineConstructionType)
137 	, m_shaders						(shaders)
138 	, m_noCache						(noCache)
139 	, m_delayedDestroy				(delayedDestroy)
140 	, m_zeroOutFeedbackCount		(zeroOutFeedbackCount)
141 {
142 }
143 
generateTestName(void) const144 const std::string CacheTestParam::generateTestName (void) const
145 {
146 	std::string cacheString [] = { "", "_no_cache" };
147 	std::string delayedDestroyString [] = { "", "_delayed_destroy" };
148 	std::string zeroOutFeedbackCoutString [] = { "", "_zero_out_feedback_cout" };
149 
150 	return getShaderFlagStr(m_shaders, false) + cacheString[m_noCache ? 1 : 0] + delayedDestroyString[m_delayedDestroy ? 1 : 0] + zeroOutFeedbackCoutString[m_zeroOutFeedbackCount ? 1 : 0];
151 }
152 
generateTestDescription(void) const153 const std::string CacheTestParam::generateTestDescription (void) const
154 {
155 	std::string result("Get pipeline creation feedback with " + getShaderFlagStr(m_shaders, true));
156 	if (m_noCache)
157 		result += " with no cache";
158 	if (m_delayedDestroy)
159 		result += " with delayed destroy";
160 
161 	return result;
162 }
163 
164 template <class Test>
newTestCase(tcu::TestContext & testContext,const CacheTestParam * testParam)165 vkt::TestCase* newTestCase (tcu::TestContext&		testContext,
166 							const CacheTestParam*	testParam)
167 {
168 	return new Test(testContext,
169 					testParam->generateTestName().c_str(),
170 					testParam->generateTestDescription().c_str(),
171 					testParam);
172 }
173 
174 // Test Classes
175 class CacheTest : public vkt::TestCase
176 {
177 public:
CacheTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,const CacheTestParam * param)178 							CacheTest(tcu::TestContext&		testContext,
179 									  const std::string&		name,
180 									  const std::string&		description,
181 									  const CacheTestParam*	param)
182 								: vkt::TestCase (testContext, name, description)
183 								, m_param (*param)
184 								{ }
~CacheTest(void)185 	virtual				~CacheTest (void) { }
186 protected:
187 	const CacheTestParam	m_param;
188 };
189 
190 class CacheTestInstance : public vkt::TestInstance
191 {
192 public:
193 							CacheTestInstance			(Context&				context,
194 														 const CacheTestParam*	param);
195 	virtual					~CacheTestInstance			(void);
196 	virtual tcu::TestStatus iterate						(void);
197 protected:
198 	virtual tcu::TestStatus verifyTestResult			(void) = 0;
199 protected:
200 	const CacheTestParam*	m_param;
201 
202 	Move<VkPipelineCache>	m_cache;
203 	deBool					m_extensions;
204 };
205 
CacheTestInstance(Context & context,const CacheTestParam * param)206 CacheTestInstance::CacheTestInstance (Context&					context,
207 									  const CacheTestParam*	param)
208 	: TestInstance		(context)
209 	, m_param			(param)
210 	, m_extensions		(m_context.requireDeviceFunctionality("VK_EXT_pipeline_creation_feedback"))
211 {
212 	const DeviceInterface&	vk				= m_context.getDeviceInterface();
213 	const VkDevice			vkDevice		= m_context.getDevice();
214 
215 	if (m_param->isCacheDisabled() == DE_FALSE)
216 	{
217 		const VkPipelineCacheCreateInfo pipelineCacheCreateInfo =
218 		{
219 			VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,			// VkStructureType				sType;
220 			DE_NULL,												// const void*					pNext;
221 			0u,														// VkPipelineCacheCreateFlags	flags;
222 			0u,														// deUintptr					initialDataSize;
223 			DE_NULL,												// const void*					pInitialData;
224 		};
225 
226 		m_cache = createPipelineCache(vk, vkDevice, &pipelineCacheCreateInfo);
227 	}
228 }
229 
~CacheTestInstance(void)230 CacheTestInstance::~CacheTestInstance (void)
231 {
232 }
233 
iterate(void)234 tcu::TestStatus CacheTestInstance::iterate (void)
235 {
236 	return verifyTestResult();
237 }
238 
239 class GraphicsCacheTest : public CacheTest
240 {
241 public:
GraphicsCacheTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,const CacheTestParam * param)242 							GraphicsCacheTest	(tcu::TestContext&		testContext,
243 												 const std::string&		name,
244 												 const std::string&		description,
245 												 const CacheTestParam*	param)
246 								: CacheTest (testContext, name, description, param)
247 								{ }
~GraphicsCacheTest(void)248 	virtual					~GraphicsCacheTest	(void) { }
249 	virtual void			initPrograms		(SourceCollections&	programCollection) const;
250 	virtual void			checkSupport		(Context&			context) const;
251 	virtual TestInstance*	createInstance		(Context&			context) const;
252 };
253 
254 class GraphicsCacheTestInstance : public CacheTestInstance
255 {
256 public:
257 							GraphicsCacheTestInstance	(Context&				context,
258 														 const CacheTestParam*	param);
259 	virtual					~GraphicsCacheTestInstance	(void);
260 protected:
261 	void					preparePipelineWrapper		(GraphicsPipelineWrapper&		gpw,
262 														 VkShaderModule					vertShaderModule,
263 														 VkShaderModule					tescShaderModule,
264 														 VkShaderModule					teseShaderModule,
265 														 VkShaderModule					geomShaderModule,
266 														 VkShaderModule					fragShaderModule,
267 														 VkPipelineCreationFeedbackEXT*	pipelineCreationFeedback,
268 														 bool*							pipelineCreationIsHeavy,
269 														 VkPipelineCreationFeedbackEXT*	pipelineStageCreationFeedbacks,
270 														 VkPipeline						basePipelineHandle,
271 														 VkBool32						zeroOutFeedbackCount);
272 	virtual tcu::TestStatus verifyTestResult			(void);
273 	void					clearFeedbacks				(void);
274 
275 protected:
276 	const tcu::UVec2					m_renderSize;
277 	const VkFormat						m_colorFormat;
278 	const VkFormat						m_depthFormat;
279 	Move<VkPipelineLayout>				m_pipelineLayout;
280 
281 	Move<VkRenderPass>					m_renderPass;
282 
283 	GraphicsPipelineWrapper				m_pipeline[PIPELINE_CACHE_NDX_COUNT];
284 	VkPipelineCreationFeedbackEXT		m_pipelineCreationFeedback[VK_MAX_PIPELINE_PARTS * PIPELINE_CACHE_NDX_COUNT];
285 	bool								m_pipelineCreationIsHeavy[VK_MAX_PIPELINE_PARTS * PIPELINE_CACHE_NDX_COUNT];
286 	VkPipelineCreationFeedbackEXT		m_pipelineStageCreationFeedbacks[PIPELINE_CACHE_NDX_COUNT * VK_MAX_SHADER_STAGES];
287 };
288 
initPrograms(SourceCollections & programCollection) const289 void GraphicsCacheTest::initPrograms (SourceCollections& programCollection) const
290 {
291 	programCollection.glslSources.add("color_vert_1") << glu::VertexSource(
292 				"#version 310 es\n"
293 				"layout(location = 0) in vec4 position;\n"
294 				"layout(location = 1) in vec4 color;\n"
295 				"layout(location = 0) out highp vec4 vtxColor;\n"
296 				"void main (void)\n"
297 				"{\n"
298 				"  gl_Position = position;\n"
299 				"  vtxColor = color;\n"
300 				"}\n");
301 	programCollection.glslSources.add("color_vert_2") << glu::VertexSource(
302 				"#version 310 es\n"
303 				"layout(location = 0) in vec4 position;\n"
304 				"layout(location = 1) in vec4 color;\n"
305 				"layout(location = 0) out highp vec4 vtxColor;\n"
306 				"void main (void)\n"
307 				"{\n"
308 				"  gl_Position = position;\n"
309 				"  gl_PointSize = 1.0f;\n"
310 				"  vtxColor = color + vec4(0.1, 0.2, 0.3, 0.0);\n"
311 				"}\n");
312 	programCollection.glslSources.add("color_frag") << glu::FragmentSource(
313 				"#version 310 es\n"
314 				"layout(location = 0) in highp vec4 vtxColor;\n"
315 				"layout(location = 0) out highp vec4 fragColor;\n"
316 				"void main (void)\n"
317 				"{\n"
318 				"  fragColor = vtxColor;\n"
319 				"}\n");
320 
321 	VkShaderStageFlags shaderFlag = m_param.getShaderFlags();
322 	if (shaderFlag & VK_SHADER_STAGE_GEOMETRY_BIT)
323 	{
324 		programCollection.glslSources.add("unused_geo") << glu::GeometrySource(
325 				"#version 450 \n"
326 				"layout(triangles) in;\n"
327 				"layout(triangle_strip, max_vertices = 3) out;\n"
328 				"layout(location = 0) in highp vec4 in_vtxColor[];\n"
329 				"layout(location = 0) out highp vec4 vtxColor;\n"
330 				"out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
331 				"in gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_in[];\n"
332 				"void main (void)\n"
333 				"{\n"
334 				"  for(int ndx=0; ndx<3; ndx++)\n"
335 				"  {\n"
336 				"    gl_Position = gl_in[ndx].gl_Position;\n"
337 				"    gl_PointSize = gl_in[ndx].gl_PointSize;\n"
338 				"    vtxColor    = in_vtxColor[ndx];\n"
339 				"    EmitVertex();\n"
340 				"  }\n"
341 				"  EndPrimitive();\n"
342 				"}\n");
343 	}
344 
345 	if (shaderFlag & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
346 	{
347 		programCollection.glslSources.add("basic_tcs") << glu::TessellationControlSource(
348 				"#version 450 \n"
349 				"layout(vertices = 3) out;\n"
350 				"layout(location = 0) in highp vec4 color[];\n"
351 				"layout(location = 0) out highp vec4 vtxColor[];\n"
352 				"out gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_out[3];\n"
353 				"in gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_in[gl_MaxPatchVertices];\n"
354 				"void main()\n"
355 				"{\n"
356 				"  gl_TessLevelOuter[0] = 4.0;\n"
357 				"  gl_TessLevelOuter[1] = 4.0;\n"
358 				"  gl_TessLevelOuter[2] = 4.0;\n"
359 				"  gl_TessLevelInner[0] = 4.0;\n"
360 				"  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
361 				"  gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n"
362 				"  vtxColor[gl_InvocationID] = color[gl_InvocationID];\n"
363 				"}\n");
364 	}
365 
366 	if (shaderFlag & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
367 	{
368 		programCollection.glslSources.add("basic_tes") << glu::TessellationEvaluationSource(
369 				"#version 450 \n"
370 				"layout(triangles, fractional_even_spacing, ccw) in;\n"
371 				"layout(location = 0) in highp vec4 colors[];\n"
372 				"layout(location = 0) out highp vec4 vtxColor;\n"
373 				"out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
374 				"in gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_in[gl_MaxPatchVertices];\n"
375 				"void main() \n"
376 				"{\n"
377 				"  float u = gl_TessCoord.x;\n"
378 				"  float v = gl_TessCoord.y;\n"
379 				"  float w = gl_TessCoord.z;\n"
380 				"  vec4 pos = vec4(0);\n"
381 				"  vec4 color = vec4(0);\n"
382 				"  pos.xyz += u * gl_in[0].gl_Position.xyz;\n"
383 				"  color.xyz += u * colors[0].xyz;\n"
384 				"  pos.xyz += v * gl_in[1].gl_Position.xyz;\n"
385 				"  color.xyz += v * colors[1].xyz;\n"
386 				"  pos.xyz += w * gl_in[2].gl_Position.xyz;\n"
387 				"  color.xyz += w * colors[2].xyz;\n"
388 				"  pos.w = 1.0;\n"
389 				"  color.w = 1.0;\n"
390 				"  gl_Position = pos;\n"
391 				"  gl_PointSize = gl_in[0].gl_PointSize;"
392 				"  vtxColor = color;\n"
393 				"}\n");
394 	}
395 }
396 
checkSupport(Context & context) const397 void GraphicsCacheTest::checkSupport (Context& context) const
398 {
399 	if (m_param.getShaderFlags() & VK_SHADER_STAGE_GEOMETRY_BIT)
400 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
401 	if ((m_param.getShaderFlags() & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) ||
402 		(m_param.getShaderFlags() & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))
403 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
404 
405 	checkPipelineLibraryRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_param.getPipelineConstructionType());
406 }
407 
createInstance(Context & context) const408 TestInstance* GraphicsCacheTest::createInstance (Context& context) const
409 {
410 	return new GraphicsCacheTestInstance(context, &m_param);
411 }
412 
GraphicsCacheTestInstance(Context & context,const CacheTestParam * param)413 GraphicsCacheTestInstance::GraphicsCacheTestInstance (Context&				context,
414 													  const CacheTestParam*	param)
415 	: CacheTestInstance		(context, param)
416 	, m_renderSize			(32u, 32u)
417 	, m_colorFormat			(VK_FORMAT_R8G8B8A8_UNORM)
418 	, m_depthFormat			(VK_FORMAT_D16_UNORM)
419 	, m_pipeline
420 	{
421 		{ context.getDeviceInterface(), context.getDevice(), param->getPipelineConstructionType(), VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT },
422 		{ context.getDeviceInterface(), context.getDevice(), param->getPipelineConstructionType(), VK_PIPELINE_CREATE_DERIVATIVE_BIT },
423 		{ context.getDeviceInterface(), context.getDevice(), param->getPipelineConstructionType(), VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT },
424 	}
425 {
426 	const DeviceInterface&	vk				= m_context.getDeviceInterface();
427 	const VkDevice			vkDevice		= m_context.getDevice();
428 
429 	// Create pipeline layout
430 	{
431 		const VkPipelineLayoutCreateInfo pipelineLayoutParams =
432 		{
433 			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType					sType;
434 			DE_NULL,											// const void*						pNext;
435 			0u,													// VkPipelineLayoutCreateFlags		flags;
436 			0u,													// deUint32							setLayoutCount;
437 			DE_NULL,											// const VkDescriptorSetLayout*		pSetLayouts;
438 			0u,													// deUint32							pushConstantRangeCount;
439 			DE_NULL												// const VkPushConstantRange*		pPushConstantRanges;
440 		};
441 
442 		m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
443 	}
444 
445 	// Create render pass
446 	m_renderPass = makeRenderPass(vk, vkDevice, m_colorFormat, m_depthFormat);
447 
448 	// Create shader modules
449 	Move<VkShaderModule> vertShaderModule1	= createShaderModule(vk, vkDevice, context.getBinaryCollection().get("color_vert_1"), 0);
450 	Move<VkShaderModule> vertShaderModule2	= createShaderModule(vk, vkDevice, context.getBinaryCollection().get("color_vert_2"), 0);
451 	Move<VkShaderModule> fragShaderModule	= createShaderModule(vk, vkDevice, context.getBinaryCollection().get("color_frag"), 0);
452 	Move<VkShaderModule> tescShaderModule;
453 	Move<VkShaderModule> teseShaderModule;
454 	Move<VkShaderModule> geomShaderModule;
455 
456 	VkShaderStageFlags shaderFlags = m_param->getShaderFlags();
457 	if (shaderFlags & VK_SHADER_STAGE_GEOMETRY_BIT)
458 		geomShaderModule = createShaderModule(vk, vkDevice, context.getBinaryCollection().get("unused_geo"), 0);
459 	if (shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
460 		tescShaderModule = createShaderModule(vk, vkDevice, context.getBinaryCollection().get("basic_tcs"), 0);
461 	if (shaderFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
462 		teseShaderModule = createShaderModule(vk, vkDevice, context.getBinaryCollection().get("basic_tes"), 0);
463 
464 	for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
465 	{
466 		VkShaderModule vertShaderModule = (ndx == PIPELINE_CACHE_NDX_DERIVATIVE) ? *vertShaderModule2 : *vertShaderModule1;
467 
468 		if (ndx == PIPELINE_CACHE_NDX_CACHED && !param->isDelayedDestroy())
469 		{
470 			// Destroy the NO_CACHE pipeline to check that the cached one really hits cache,
471 			// except for the case where we're testing cache hit of a pipeline still active.
472 			m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE].destroyPipeline();
473 		}
474 
475 		clearFeedbacks();
476 
477 		preparePipelineWrapper(m_pipeline[ndx], vertShaderModule, *tescShaderModule, *teseShaderModule, *geomShaderModule, *fragShaderModule,
478 							   &m_pipelineCreationFeedback[VK_MAX_PIPELINE_PARTS * ndx],
479 							   &m_pipelineCreationIsHeavy[VK_MAX_PIPELINE_PARTS * ndx],
480 							   &m_pipelineStageCreationFeedbacks[VK_MAX_SHADER_STAGES * ndx],
481 							   ndx == PIPELINE_CACHE_NDX_DERIVATIVE ? m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE].getPipeline() : DE_NULL,
482 							   param->isZeroOutFeedbackCount());
483 
484 		if (ndx != PIPELINE_CACHE_NDX_NO_CACHE)
485 		{
486 			// Destroy the pipeline as soon as it is created, except the NO_CACHE because
487 			// it is needed as a base pipeline for the derivative case.
488 			m_pipeline[ndx].destroyPipeline();
489 
490 			if (ndx == PIPELINE_CACHE_NDX_CACHED && param->isDelayedDestroy())
491 			{
492 				// Destroy the pipeline we didn't destroy earlier for the isDelayedDestroy case.
493 				m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE].destroyPipeline();
494 			}
495 		}
496 	}
497 }
498 
~GraphicsCacheTestInstance(void)499 GraphicsCacheTestInstance::~GraphicsCacheTestInstance (void)
500 {
501 }
502 
preparePipelineWrapper(GraphicsPipelineWrapper & gpw,VkShaderModule vertShaderModule,VkShaderModule tescShaderModule,VkShaderModule teseShaderModule,VkShaderModule geomShaderModule,VkShaderModule fragShaderModule,VkPipelineCreationFeedbackEXT * pipelineCreationFeedback,bool * pipelineCreationIsHeavy,VkPipelineCreationFeedbackEXT * pipelineStageCreationFeedbacks,VkPipeline basePipelineHandle,VkBool32 zeroOutFeedbackCount)503 void GraphicsCacheTestInstance::preparePipelineWrapper (GraphicsPipelineWrapper&		gpw,
504 														VkShaderModule					vertShaderModule,
505 														VkShaderModule					tescShaderModule,
506 														VkShaderModule					teseShaderModule,
507 														VkShaderModule					geomShaderModule,
508 														VkShaderModule					fragShaderModule,
509 														VkPipelineCreationFeedbackEXT*	pipelineCreationFeedback,
510 														bool*							pipelineCreationIsHeavy,
511 														VkPipelineCreationFeedbackEXT*	pipelineStageCreationFeedbacks,
512 														VkPipeline						basePipelineHandle,
513 														VkBool32						zeroOutFeedbackCount)
514 {
515 	const VkVertexInputBindingDescription vertexInputBindingDescription
516 	{
517 		0u,										// deUint32				binding;
518 		sizeof(Vertex4RGBA),					// deUint32				strideInBytes;
519 		VK_VERTEX_INPUT_RATE_VERTEX,			// VkVertexInputRate	inputRate;
520 	};
521 
522 	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2]
523 	{
524 		{
525 			0u,									// deUint32				location;
526 			0u,									// deUint32				binding;
527 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat				format;
528 			0u									// deUint32				offsetInBytes;
529 		},
530 		{
531 			1u,									// deUint32				location;
532 			0u,									// deUint32				binding;
533 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat				format;
534 			DE_OFFSET_OF(Vertex4RGBA, color),	// deUint32				offsetInBytes;
535 		}
536 	};
537 
538 	const VkPipelineVertexInputStateCreateInfo vertexInputStateParams
539 	{
540 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType							sType;
541 		DE_NULL,														// const void*								pNext;
542 		0u,																// VkPipelineVertexInputStateCreateFlags	flags;
543 		1u,																// deUint32									vertexBindingDescriptionCount;
544 		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
545 		2u,																// deUint32									vertexAttributeDescriptionCount;
546 		vertexInputAttributeDescriptions,								// const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
547 	};
548 
549 	const std::vector<VkViewport>	viewport	{ makeViewport(m_renderSize) };
550 	const std::vector<VkRect2D>		scissor		{ makeRect2D(m_renderSize) };
551 
552 	const VkPipelineColorBlendAttachmentState colorBlendAttachmentState
553 	{
554 		VK_FALSE,														// VkBool32		blendEnable;
555 		VK_BLEND_FACTOR_ONE,											// VkBlendFactor	srcColorBlendFactor;
556 		VK_BLEND_FACTOR_ZERO,											// VkBlendFactor	dstColorBlendFactor;
557 		VK_BLEND_OP_ADD,												// VkBlendOp		colorBlendOp;
558 		VK_BLEND_FACTOR_ONE,											// VkBlendFactor	srcAlphaBlendFactor;
559 		VK_BLEND_FACTOR_ZERO,											// VkBlendFactor	dstAlphaBlendFactor;
560 		VK_BLEND_OP_ADD,												// VkBlendOp		alphaBlendOp;
561 		VK_COLOR_COMPONENT_R_BIT |
562 		VK_COLOR_COMPONENT_G_BIT |
563 		VK_COLOR_COMPONENT_B_BIT |
564 		VK_COLOR_COMPONENT_A_BIT										// VkColorComponentFlags    colorWriteMask;
565 	};
566 
567 	const VkPipelineColorBlendStateCreateInfo colorBlendStateParams
568 	{
569 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
570 		DE_NULL,													// const void*									pNext;
571 		0u,															// VkPipelineColorBlendStateCreateFlags			flags;
572 		VK_FALSE,													// VkBool32										logicOpEnable;
573 		VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
574 		1u,															// deUint32										attachmentCount;
575 		&colorBlendAttachmentState,									// const VkPipelineColorBlendAttachmentState*	pAttachments;
576 		{ 0.0f, 0.0f, 0.0f, 0.0f },									// float										blendConst[4];
577 	};
578 
579 	VkPipelineDepthStencilStateCreateInfo depthStencilStateParams
580 	{
581 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType							sType;
582 		DE_NULL,													// const void*								pNext;
583 		0u,															// VkPipelineDepthStencilStateCreateFlags	flags;
584 		VK_TRUE,													// VkBool32									depthTestEnable;
585 		VK_TRUE,													// VkBool32									depthWriteEnable;
586 		VK_COMPARE_OP_LESS_OR_EQUAL,								// VkCompareOp								depthCompareOp;
587 		VK_FALSE,													// VkBool32									depthBoundsTestEnable;
588 		VK_FALSE,													// VkBool32									stencilTestEnable;
589 		// VkStencilOpState front;
590 		{
591 			VK_STENCIL_OP_KEEP,		// VkStencilOp	failOp;
592 			VK_STENCIL_OP_KEEP,		// VkStencilOp	passOp;
593 			VK_STENCIL_OP_KEEP,		// VkStencilOp	depthFailOp;
594 			VK_COMPARE_OP_NEVER,	// VkCompareOp	compareOp;
595 			0u,						// deUint32		compareMask;
596 			0u,						// deUint32		writeMask;
597 			0u,						// deUint32		reference;
598 		},
599 		// VkStencilOpState back;
600 		{
601 			VK_STENCIL_OP_KEEP,		// VkStencilOp	failOp;
602 			VK_STENCIL_OP_KEEP,		// VkStencilOp	passOp;
603 			VK_STENCIL_OP_KEEP,		// VkStencilOp	depthFailOp;
604 			VK_COMPARE_OP_NEVER,	// VkCompareOp	compareOp;
605 			0u,						// deUint32		compareMask;
606 			0u,						// deUint32		writeMask;
607 			0u,						// deUint32		reference;
608 		},
609 		0.0f,														// float									minDepthBounds;
610 		1.0f,														// float									maxDepthBounds;
611 	};
612 
613 	VkPipelineCreationFeedbackCreateInfoEXT		pipelineCreationFeedbackCreateInfo[VK_MAX_PIPELINE_PARTS];
614 	PipelineCreationFeedbackCreateInfoWrapper	pipelineCreationFeedbackWrapper[VK_MAX_PIPELINE_PARTS];
615 	for (deUint32 i = 0u ; i < VK_MAX_PIPELINE_PARTS ; ++i)
616 	{
617 		pipelineCreationFeedbackCreateInfo[i] = initVulkanStructure();
618 		pipelineCreationFeedbackCreateInfo[i].pPipelineCreationFeedback = &pipelineCreationFeedback[i];
619 		pipelineCreationFeedbackWrapper[i].ptr = &pipelineCreationFeedbackCreateInfo[i];
620 
621 		pipelineCreationIsHeavy[i] = false;
622 	}
623 
624 	deUint32 geometryStages = 1u + (geomShaderModule != DE_NULL) + (tescShaderModule != DE_NULL) + (teseShaderModule != DE_NULL);
625 	if (m_param->getPipelineConstructionType() == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
626 	{
627 		pipelineCreationFeedbackCreateInfo[4].pipelineStageCreationFeedbackCount	= zeroOutFeedbackCount ? 0u : (1u + geometryStages);
628 		pipelineCreationFeedbackCreateInfo[4].pPipelineStageCreationFeedbacks		= pipelineStageCreationFeedbacks;
629 
630 		pipelineCreationIsHeavy[4] = true;
631 	}
632 	else
633 	{
634 		// setup proper stages count for CreationFeedback structures
635 		// that will be passed to pre-rasterization and fragment shader states
636 		pipelineCreationFeedbackCreateInfo[1].pipelineStageCreationFeedbackCount	= zeroOutFeedbackCount ? 0u : geometryStages;
637 		pipelineCreationFeedbackCreateInfo[1].pPipelineStageCreationFeedbacks		= pipelineStageCreationFeedbacks;
638 		pipelineCreationFeedbackCreateInfo[2].pipelineStageCreationFeedbackCount	= zeroOutFeedbackCount ? 0u : 1u;
639 		pipelineCreationFeedbackCreateInfo[2].pPipelineStageCreationFeedbacks		= pipelineStageCreationFeedbacks + geometryStages;
640 
641 		pipelineCreationIsHeavy[1] = true;
642 		pipelineCreationIsHeavy[2] = true;
643 
644 		if (m_param->getPipelineConstructionType() == PIPELINE_CONSTRUCTION_TYPE_LINK_TIME_OPTIMIZED_LIBRARY)
645 		{
646 			pipelineCreationFeedbackCreateInfo[4].pipelineStageCreationFeedbackCount	= zeroOutFeedbackCount ? 0u : (1u + geometryStages);
647 			pipelineCreationFeedbackCreateInfo[4].pPipelineStageCreationFeedbacks		= pipelineStageCreationFeedbacks;
648 
649 			pipelineCreationIsHeavy[4] = true;
650 		}
651 	}
652 
653 	// pipelineCreationIsHeavy element 0 and 3 intentionally left false,
654 	// because these relate to vertex input and fragment output stages, which may be
655 	// created in nearly zero time.
656 
657 	gpw.setDefaultTopology((tescShaderModule == DE_NULL) ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST : VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)
658 	   .setDefaultRasterizationState()
659 	   .setDefaultMultisampleState()
660 	   .setupVertexInputState(&vertexInputStateParams, DE_NULL, *m_cache, pipelineCreationFeedbackWrapper[0])
661 	   .setupPreRasterizationShaderState(
662 			viewport,
663 			scissor,
664 			*m_pipelineLayout,
665 			*m_renderPass,
666 			0u,
667 			vertShaderModule,
668 			DE_NULL,
669 			tescShaderModule,
670 			teseShaderModule,
671 			geomShaderModule,
672 			DE_NULL,
673 			nullptr,
674 			PipelineRenderingCreateInfoWrapper(),
675 			*m_cache,
676 			pipelineCreationFeedbackWrapper[1])
677 	   .setupFragmentShaderState(
678 			*m_pipelineLayout,
679 			*m_renderPass,
680 			0u,
681 			fragShaderModule,
682 			&depthStencilStateParams,
683 			DE_NULL,
684 			DE_NULL,
685 			*m_cache,
686 			pipelineCreationFeedbackWrapper[2])
687 	   .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams, DE_NULL, *m_cache, pipelineCreationFeedbackWrapper[3])
688 	   .setMonolithicPipelineLayout(*m_pipelineLayout)
689 	   .buildPipeline(*m_cache, basePipelineHandle, basePipelineHandle != DE_NULL ? -1 : 0, pipelineCreationFeedbackWrapper[4]);
690 }
691 
verifyTestResult(void)692 tcu::TestStatus GraphicsCacheTestInstance::verifyTestResult (void)
693 {
694 	tcu::TestLog&	log						= m_context.getTestContext().getLog();
695 	bool			durationZeroWarning		= DE_FALSE;
696 	bool			cachedPipelineWarning	= DE_FALSE;
697 	bool			isMonolithic			= m_param->getPipelineConstructionType() == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC;
698 	bool			isZeroOutFeedbackCout	= m_param->isZeroOutFeedbackCount();
699 	deUint32		finalPipelineIndex		= deUint32(VK_MAX_PIPELINE_PARTS) - 1u;
700 	deUint32		start					= isMonolithic ? finalPipelineIndex : 0u;
701 	deUint32		step					= start + 1u;
702 
703 	// Iterate ofer creation feedback for all pipeline parts - if monolithic pipeline is tested then skip (step over) feedback for parts
704 	for (deUint32 creationFeedbackNdx = start; creationFeedbackNdx < VK_MAX_PIPELINE_PARTS * PIPELINE_CACHE_NDX_COUNT; creationFeedbackNdx += step)
705 	{
706 		deUint32		pipelineCacheNdx		= creationFeedbackNdx / deUint32(VK_MAX_PIPELINE_PARTS);
707 		auto			creationFeedbackFlags	= m_pipelineCreationFeedback[creationFeedbackNdx].flags;
708 		std::string		caseString				= getCaseStr(pipelineCacheNdx);
709 		deUint32		pipelinePartIndex	= creationFeedbackNdx % deUint32(VK_MAX_PIPELINE_PARTS);
710 
711 		std::ostringstream message;
712 		message << caseString;
713 		// Check first that the no cached pipeline was missed in the pipeline cache
714 
715 		// According to the spec:
716 		// "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
717 		//	may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
718 		if (!(creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
719 		{
720 			// According to the spec:
721 			// "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
722 			//	must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
723 			if (m_pipelineCreationFeedback[creationFeedbackNdx].flags)
724 			{
725 				std::ostringstream			errorMsg;
726 				errorMsg << ": Creation feedback is not valid but there are other flags written";
727 				return tcu::TestStatus::fail(errorMsg.str());
728 			}
729 			message << "\t\t Pipeline Creation Feedback data is not valid\n";
730 		}
731 		else
732 		{
733 			if (m_param->isCacheDisabled() && creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
734 			{
735 				message << ": feedback indicates pipeline hit cache when it shouldn't";
736 				return tcu::TestStatus::fail(message.str());
737 			}
738 
739 			if (pipelineCacheNdx == PIPELINE_CACHE_NDX_NO_CACHE && creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
740 			{
741 				message << ": hit the cache when it shouldn't";
742 				return tcu::TestStatus::fail(message.str());
743 			}
744 
745 			if (pipelineCacheNdx != PIPELINE_CACHE_NDX_DERIVATIVE && creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT)
746 			{
747 				message << ": feedback indicates base pipeline acceleration when it shouldn't";
748 				return tcu::TestStatus::fail(message.str());
749 			}
750 
751 			if (pipelineCacheNdx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
752 			{
753 				// For graphics pipeline library cache is only hit for the pre_rasterization and fragment_shader stages
754 				if (isMonolithic || (pipelinePartIndex == 1u) || (pipelinePartIndex == 2u))
755 				{
756 					message << "\nWarning: Cached pipeline case did not hit the cache";
757 					cachedPipelineWarning = DE_TRUE;
758 				}
759 			}
760 
761 			if (m_pipelineCreationFeedback[creationFeedbackNdx].duration == 0)
762 			{
763 				if (m_pipelineCreationIsHeavy[creationFeedbackNdx])
764 				{
765 					// Emit warnings only for pipelines, that are expected to have large creation times.
766 					// Pipelines containing only vertex input or fragment output stages may be created in
767 					// time duration less than the timer precision available on given platform.
768 
769 					message << "\nWarning: Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds\n";
770 					durationZeroWarning = DE_TRUE;
771 				}
772 			}
773 
774 			message << "\n";
775 			message << "\t\t Hit cache ? \t\t\t"				<< (creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT ? "yes" : "no")	<< "\n";
776 			message << "\t\t Base Pipeline Acceleration ? \t"	<< (creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ?	 "yes" : "no")		<< "\n";
777 			message << "\t\t Duration (ns): \t\t"				<< m_pipelineCreationFeedback[creationFeedbackNdx].duration																							<< "\n";
778 		}
779 
780 		// dont repeat checking shader feedback for pipeline parts - just check all shaders when checkin final pipelines
781 		if (pipelinePartIndex == finalPipelineIndex)
782 		{
783 			VkShaderStageFlags	testedShaderFlags	= m_param->getShaderFlags();
784 			deUint32			shaderCount			= 2u + ((testedShaderFlags & VK_SHADER_STAGE_GEOMETRY_BIT) != 0) +
785 														   ((testedShaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) +
786 														   ((testedShaderFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0);
787 			for(deUint32 shader = 0; shader < shaderCount; shader++)
788 			{
789 				const deUint32 index = VK_MAX_SHADER_STAGES * pipelineCacheNdx + shader;
790 				message << "\t" <<(shader + 1) << " shader stage\n";
791 
792 				// According to the spec:
793 				// "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
794 				//      may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
795 				if (m_pipelineStageCreationFeedbacks[index].flags & isZeroOutFeedbackCout)
796 				{
797 					std::ostringstream			errorMsg;
798 					errorMsg << caseString << ": feedback indicates pipeline " << (shader + 1) << " shader stage feedback was generated despite setting feedback count to zero";
799 					return tcu::TestStatus::fail(errorMsg.str());
800 				}
801 
802 				if (!(m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
803 				{
804 					// According to the spec:
805 					// "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
806 					//      must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
807 					if (m_pipelineStageCreationFeedbacks[index].flags)
808 					{
809 						std::ostringstream			errorMsg;
810 						errorMsg << caseString << ": Creation feedback is not valid for " << (shader + 1) << " shader stage but there are other flags written";
811 						return tcu::TestStatus::fail(errorMsg.str());
812 					}
813 					message << "\t\t Pipeline Creation Feedback data is not valid\n";
814 					continue;
815 				}
816 				if (m_param->isCacheDisabled() && m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
817 				{
818 					std::ostringstream			errorMsg;
819 					errorMsg << caseString << ": feedback indicates pipeline " << (shader + 1) << " shader stage hit cache when it shouldn't";
820 					return tcu::TestStatus::fail(errorMsg.str());
821 				}
822 
823 				if (pipelineCacheNdx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
824 				{
825 					message << "Warning: pipeline stage did not hit the cache\n";
826 					cachedPipelineWarning = DE_TRUE;
827 				}
828 				if (cachedPipelineWarning && m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
829 				{
830 					// We only set the warning when the pipeline nor the pipeline stages hit the cache. If any of them did, them disable the warning.
831 					cachedPipelineWarning = DE_FALSE;
832 				}
833 
834 				message << "\t\t Hit cache ? \t\t\t"				<< (m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT ? "yes" : "no")	<< "\n";
835 				message << "\t\t Base Pipeline Acceleration ? \t"	<< (m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ?	 "yes" : "no")		<< "\n";
836 				message << "\t\t Duration (ns): \t\t"				<< m_pipelineStageCreationFeedbacks[index].duration																							<< "\n";
837 			}
838 		}
839 
840 		log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
841 	}
842 
843 	if (cachedPipelineWarning)
844 	{
845 		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Cached pipeline or stage did not hit the cache");
846 	}
847 	if (durationZeroWarning)
848 	{
849 		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds");
850 	}
851 	return tcu::TestStatus::pass("Pass");
852 }
853 
clearFeedbacks(void)854 void GraphicsCacheTestInstance::clearFeedbacks(void)
855 {
856 	deMemset(m_pipelineCreationFeedback, 0, sizeof(VkPipelineCreationFeedbackEXT) * VK_MAX_PIPELINE_PARTS * PIPELINE_CACHE_NDX_COUNT);
857 	deMemset(m_pipelineStageCreationFeedbacks, 0, sizeof(VkPipelineCreationFeedbackEXT) * PIPELINE_CACHE_NDX_COUNT * VK_MAX_SHADER_STAGES);
858 }
859 
860 class ComputeCacheTest : public CacheTest
861 {
862 public:
ComputeCacheTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,const CacheTestParam * param)863 							ComputeCacheTest		(tcu::TestContext&		testContext,
864 													 const std::string&		name,
865 													 const std::string&		description,
866 													 const CacheTestParam*	param)
867 								: CacheTest		(testContext, name, description, param)
868 								{ }
~ComputeCacheTest(void)869 	virtual					~ComputeCacheTest	(void) { }
870 	virtual void			initPrograms			(SourceCollections&	programCollection) const;
871 	virtual TestInstance*	createInstance			(Context&				context) const;
872 };
873 
874 class ComputeCacheTestInstance : public CacheTestInstance
875 {
876 public:
877 							ComputeCacheTestInstance		(Context&				context,
878 															 const CacheTestParam*	param);
879 	virtual					~ComputeCacheTestInstance	(void);
880 protected:
881 	virtual tcu::TestStatus verifyTestResult				(void);
882 			void			buildDescriptorSets				(deUint32 ndx);
883 			void			buildShader						(deUint32 ndx);
884 			void			buildPipeline					(const CacheTestParam*	param, deUint32 ndx);
885 protected:
886 	Move<VkBuffer>					m_inputBuf;
887 	de::MovePtr<Allocation>			m_inputBufferAlloc;
888 	Move<VkShaderModule>			m_computeShaderModule[PIPELINE_CACHE_NDX_COUNT];
889 
890 	Move<VkBuffer>					m_outputBuf[PIPELINE_CACHE_NDX_COUNT];
891 	de::MovePtr<Allocation>			m_outputBufferAlloc[PIPELINE_CACHE_NDX_COUNT];
892 
893 	Move<VkDescriptorPool>			m_descriptorPool[PIPELINE_CACHE_NDX_COUNT];
894 	Move<VkDescriptorSetLayout>		m_descriptorSetLayout[PIPELINE_CACHE_NDX_COUNT];
895 	Move<VkDescriptorSet>			m_descriptorSet[PIPELINE_CACHE_NDX_COUNT];
896 
897 	Move<VkPipelineLayout>			m_pipelineLayout[PIPELINE_CACHE_NDX_COUNT];
898 	VkPipeline						m_pipeline[PIPELINE_CACHE_NDX_COUNT];
899 	VkPipelineCreationFeedbackEXT	m_pipelineCreationFeedback[PIPELINE_CACHE_NDX_COUNT];
900 	VkPipelineCreationFeedbackEXT	m_pipelineStageCreationFeedback[PIPELINE_CACHE_NDX_COUNT];
901 };
902 
initPrograms(SourceCollections & programCollection) const903 void ComputeCacheTest::initPrograms (SourceCollections& programCollection) const
904 {
905 	programCollection.glslSources.add("basic_compute_1") << glu::ComputeSource(
906 		"#version 310 es\n"
907 		"layout(local_size_x = 1) in;\n"
908 		"layout(std430) buffer;\n"
909 		"layout(binding = 0) readonly buffer Input0\n"
910 		"{\n"
911 		"  vec4 elements[];\n"
912 		"} input_data0;\n"
913 		"layout(binding = 1) writeonly buffer Output\n"
914 		"{\n"
915 		"  vec4 elements[];\n"
916 		"} output_data;\n"
917 		"void main()\n"
918 		"{\n"
919 		"  uint ident = gl_GlobalInvocationID.x;\n"
920 		"  output_data.elements[ident] = input_data0.elements[ident] * input_data0.elements[ident];\n"
921 		"}");
922 	programCollection.glslSources.add("basic_compute_2") << glu::ComputeSource(
923 		"#version 310 es\n"
924 		"layout(local_size_x = 1) in;\n"
925 		"layout(std430) buffer;\n"
926 		"layout(binding = 0) readonly buffer Input0\n"
927 		"{\n"
928 		"  vec4 elements[];\n"
929 		"} input_data0;\n"
930 		"layout(binding = 1) writeonly buffer Output\n"
931 		"{\n"
932 		"  vec4 elements[];\n"
933 		"} output_data;\n"
934 		"void main()\n"
935 		"{\n"
936 		"  uint ident = gl_GlobalInvocationID.x;\n"
937 		"  output_data.elements[ident] = input_data0.elements[ident];\n"
938 		"}");
939 }
940 
createInstance(Context & context) const941 TestInstance* ComputeCacheTest::createInstance (Context& context) const
942 {
943 	return new ComputeCacheTestInstance(context, &m_param);
944 }
945 
buildDescriptorSets(deUint32 ndx)946 void ComputeCacheTestInstance::buildDescriptorSets (deUint32 ndx)
947 {
948 	const DeviceInterface&	vk				= m_context.getDeviceInterface();
949 	const VkDevice			vkDevice		= m_context.getDevice();
950 
951 	// Create descriptor set layout
952 	DescriptorSetLayoutBuilder descLayoutBuilder;
953 	for (deUint32 bindingNdx = 0u; bindingNdx < 2u; bindingNdx++)
954 		descLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
955 	m_descriptorSetLayout[ndx] = descLayoutBuilder.build(vk, vkDevice);
956 }
957 
buildShader(deUint32 ndx)958 void ComputeCacheTestInstance::buildShader (deUint32 ndx)
959 {
960 	const DeviceInterface&	vk				= m_context.getDeviceInterface();
961 	const VkDevice			vkDevice		= m_context.getDevice();
962 
963 	std::string shader_name("basic_compute_");
964 
965 	shader_name += (ndx == PIPELINE_CACHE_NDX_DERIVATIVE) ? "2" : "1";
966 
967 	// Create compute shader
968 	VkShaderModuleCreateInfo shaderModuleCreateInfo =
969 	{
970 		VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,								// VkStructureType				sType;
971 		DE_NULL,																	// const void*					pNext;
972 		0u,																			// VkShaderModuleCreateFlags	flags;
973 		m_context.getBinaryCollection().get(shader_name).getSize(),					// deUintptr					codeSize;
974 		(deUint32*)m_context.getBinaryCollection().get(shader_name).getBinary(),	// const deUint32*				pCode;
975 	};
976 	m_computeShaderModule[ndx] = createShaderModule(vk, vkDevice, &shaderModuleCreateInfo);
977 }
978 
buildPipeline(const CacheTestParam * param,deUint32 ndx)979 void ComputeCacheTestInstance::buildPipeline (const CacheTestParam*	param, deUint32 ndx)
980 {
981 	const DeviceInterface&	vk					 = m_context.getDeviceInterface();
982 	const VkDevice			vkDevice			 = m_context.getDevice();
983 	const VkBool32			zeroOutFeedbackCount = param->isZeroOutFeedbackCount();
984 
985 	deMemset(&m_pipelineCreationFeedback[ndx], 0, sizeof(VkPipelineCreationFeedbackEXT));
986 	deMemset(&m_pipelineStageCreationFeedback[ndx], 0, sizeof(VkPipelineCreationFeedbackEXT));
987 
988 	const VkPipelineCreationFeedbackCreateInfoEXT pipelineCreationFeedbackCreateInfo =
989 	{
990 		VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT,	// VkStructureType					sType;
991 		DE_NULL,														// const void *						pNext;
992 		&m_pipelineCreationFeedback[ndx],								// VkPipelineCreationFeedbackEXT*	pPipelineCreationFeedback;
993 		zeroOutFeedbackCount ? 0u : 1u,									// deUint32							pipelineStageCreationFeedbackCount;
994 		&m_pipelineStageCreationFeedback[ndx]							// VkPipelineCreationFeedbackEXT*	pPipelineStageCreationFeedbacks;
995 	};
996 
997 	// Create compute pipeline layout
998 	const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
999 	{
1000 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,					// VkStructureType					sType;
1001 		DE_NULL,														// const void*						pNext;
1002 		0u,																// VkPipelineLayoutCreateFlags		flags;
1003 		1u,																// deUint32							setLayoutCount;
1004 		&m_descriptorSetLayout[ndx].get(),								// const VkDescriptorSetLayout*		pSetLayouts;
1005 		0u,																// deUint32							pushConstantRangeCount;
1006 		DE_NULL,														// const VkPushConstantRange*		pPushConstantRanges;
1007 	};
1008 
1009 	m_pipelineLayout[ndx] = createPipelineLayout(vk, vkDevice, &pipelineLayoutCreateInfo);
1010 
1011 	const VkPipelineShaderStageCreateInfo stageCreateInfo =
1012 	{
1013 		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,			// VkStructureType					sType;
1014 		DE_NULL,														// const void*						pNext;
1015 		0u,																// VkPipelineShaderStageCreateFlags	flags;
1016 		VK_SHADER_STAGE_COMPUTE_BIT,									// VkShaderStageFlagBits			stage;
1017 		*m_computeShaderModule[ndx],									// VkShaderModule					module;
1018 		"main",															// const char*						pName;
1019 		DE_NULL,														// const VkSpecializationInfo*		pSpecializationInfo;
1020 	};
1021 
1022 	VkComputePipelineCreateInfo pipelineCreateInfo =
1023 	{
1024 		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,					// VkStructureType					sType;
1025 		&pipelineCreationFeedbackCreateInfo,							// const void*						pNext;
1026 		0u,																// VkPipelineCreateFlags			flags;
1027 		stageCreateInfo,												// VkPipelineShaderStageCreateInfo	stage;
1028 		*m_pipelineLayout[ndx],											// VkPipelineLayout					layout;
1029 		(VkPipeline)0,													// VkPipeline						basePipelineHandle;
1030 		0u,																// deInt32							basePipelineIndex;
1031 	};
1032 
1033 	if (ndx != PIPELINE_CACHE_NDX_DERIVATIVE)
1034 	{
1035 		pipelineCreateInfo.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
1036 	}
1037 
1038 	if (ndx == PIPELINE_CACHE_NDX_DERIVATIVE)
1039 	{
1040 		pipelineCreateInfo.flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT;
1041 		pipelineCreateInfo.basePipelineHandle = m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE];
1042 		pipelineCreateInfo.basePipelineIndex = -1;
1043 	}
1044 
1045 	if (ndx == PIPELINE_CACHE_NDX_CACHED && !param->isDelayedDestroy())
1046 	{
1047 		// Destroy the NO_CACHE pipeline to check that the cached one really hits cache,
1048 		// except for the case where we're testing cache hit of a pipeline still active.
1049 		vk.destroyPipeline(vkDevice, m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE], DE_NULL);
1050 	}
1051 
1052 	vk.createComputePipelines(vkDevice, *m_cache, 1u, &pipelineCreateInfo, DE_NULL, &m_pipeline[ndx]);
1053 
1054 	if (ndx != PIPELINE_CACHE_NDX_NO_CACHE)
1055 	{
1056 		// Destroy the pipeline as soon as it is created, except the NO_CACHE because
1057 		// it is needed as a base pipeline for the derivative case.
1058 		vk.destroyPipeline(vkDevice, m_pipeline[ndx], DE_NULL);
1059 
1060 		if (ndx == PIPELINE_CACHE_NDX_CACHED && param->isDelayedDestroy())
1061 		{
1062 			// Destroy the pipeline we didn't destroy earlier for the isDelayedDestroy case.
1063 			vk.destroyPipeline(vkDevice, m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE], DE_NULL);
1064 		}
1065 	}
1066 }
1067 
ComputeCacheTestInstance(Context & context,const CacheTestParam * param)1068 ComputeCacheTestInstance::ComputeCacheTestInstance (Context&				context,
1069 													const CacheTestParam*	param)
1070 	: CacheTestInstance (context, param)
1071 {
1072 	for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
1073 	{
1074 		buildDescriptorSets(ndx);
1075 		buildShader(ndx);
1076 		buildPipeline(param, ndx);
1077 	}
1078 }
1079 
~ComputeCacheTestInstance(void)1080 ComputeCacheTestInstance::~ComputeCacheTestInstance (void)
1081 {
1082 }
1083 
verifyTestResult(void)1084 tcu::TestStatus ComputeCacheTestInstance::verifyTestResult (void)
1085 {
1086 	tcu::TestLog &log				= m_context.getTestContext().getLog();
1087 	deBool durationZeroWarning		= DE_FALSE;
1088 	deBool cachedPipelineWarning	= DE_FALSE;
1089 
1090 	for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
1091 	{
1092 		std::ostringstream message;
1093 		message << getCaseStr(ndx);
1094 
1095 		// No need to check per stage status as it is compute pipeline (only one stage) and Vulkan spec mentions that:
1096 		// "One common scenario for an implementation to skip per-stage feedback is when
1097 		// VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT is set in pPipelineCreationFeedback."
1098 		//
1099 		// Check first that the no cached pipeline was missed in the pipeline cache
1100 
1101 		// According to the spec:
1102 		// "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
1103 		//	may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
1104 		if (!(m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
1105 		{
1106 			// According to the spec:
1107 			// "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
1108 			//	must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
1109 			if (m_pipelineCreationFeedback[ndx].flags)
1110 			{
1111 				std::ostringstream			errorMsg;
1112 				errorMsg << ": Creation feedback is not valid but there are other flags written";
1113 				return tcu::TestStatus::fail(errorMsg.str());
1114 			}
1115 			message << "\t\t Pipeline Creation Feedback data is not valid\n";
1116 		}
1117 		else
1118 		{
1119 			if (m_param->isCacheDisabled() && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1120 			{
1121 				message << ": feedback indicates pipeline hit cache when it shouldn't";
1122 				return tcu::TestStatus::fail(message.str());
1123 			}
1124 
1125 			if (ndx == PIPELINE_CACHE_NDX_NO_CACHE && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1126 			{
1127 				message << ": hit the cache when it shouldn't";
1128 				return tcu::TestStatus::fail(message.str());
1129 			}
1130 
1131 			if (!(ndx == PIPELINE_CACHE_NDX_DERIVATIVE && !m_param->isCacheDisabled()) && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT)
1132 			{
1133 				message << ": feedback indicates base pipeline acceleration when it shouldn't";
1134 				return tcu::TestStatus::fail(message.str());
1135 			}
1136 
1137 			if (ndx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
1138 			{
1139 				message << "\nWarning: Cached pipeline case did not hit the cache";
1140 				cachedPipelineWarning = DE_TRUE;
1141 			}
1142 
1143 			if (m_pipelineCreationFeedback[ndx].duration == 0)
1144 			{
1145 				message << "\nWarning: Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds\n";
1146 				durationZeroWarning = DE_TRUE;
1147 			}
1148 
1149 			message << "\n";
1150 
1151 			message << "\t\t Hit cache ? \t\t\t"				<< (m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT ? "yes" : "no")	<< "\n";
1152 			message << "\t\t Base Pipeline Acceleration ? \t"	<< (m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ? "yes" : "no")		<< "\n";
1153 			message << "\t\t Duration (ns): \t\t"				<< m_pipelineCreationFeedback[ndx].duration																						<< "\n";
1154 
1155 			message << "\t Compute Stage\n";
1156 		}
1157 
1158 		// According to the spec:
1159 		// "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
1160 		//	may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
1161 		if (!(m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
1162 		{
1163 			// According to the spec:
1164 			// "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
1165 			//	must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
1166 			if (m_pipelineStageCreationFeedback[ndx].flags)
1167 			{
1168 				std::ostringstream			errorMsg;
1169 				errorMsg << getCaseStr(ndx) << ": Creation feedback is not valid for compute stage but there are other flags written";
1170 				return tcu::TestStatus::fail(errorMsg.str());
1171 			}
1172 			message << "\t\t Pipeline Creation Feedback data is not valid\n";
1173 		}
1174 		else
1175 		{
1176 			if (m_param->isCacheDisabled() && m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1177 			{
1178 				std::ostringstream			errorMsg;
1179 				errorMsg << getCaseStr(ndx) << ": feedback indicates pipeline compute stage hit cache when it shouldn't";
1180 				return tcu::TestStatus::fail(errorMsg.str());
1181 			}
1182 
1183 			if (ndx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
1184 			{
1185 				message << "Warning: pipeline stage did not hit the cache\n";
1186 				cachedPipelineWarning = DE_TRUE;
1187 			}
1188 			if (cachedPipelineWarning && m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1189 			{
1190 				// We only set the warning when the pipeline nor the pipeline stages hit the cache. If any of them did, them disable the warning.
1191 				cachedPipelineWarning = DE_FALSE;
1192 			}
1193 
1194 			message << "\t\t Hit cache ? \t\t\t"				<< (m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT ? "yes" : "no")	<< "\n";
1195 			message << "\t\t Base Pipeline Acceleration ? \t"	<< (m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ? "yes" : "no")		<< "\n";
1196 			message << "\t\t Duration (ns): \t\t"				<< m_pipelineStageCreationFeedback[ndx].duration																						<< "\n";
1197 		}
1198 
1199 		log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
1200 	}
1201 
1202 	if (cachedPipelineWarning)
1203 	{
1204 		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Cached pipeline or stage did not hit the cache");
1205 	}
1206 	if (durationZeroWarning)
1207 	{
1208 		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds");
1209 	}
1210 	return tcu::TestStatus::pass("Pass");
1211 }
1212 } // anonymous
1213 
createCreationFeedbackTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1214 tcu::TestCaseGroup* createCreationFeedbackTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
1215 {
1216 	de::MovePtr<tcu::TestCaseGroup> cacheTests (new tcu::TestCaseGroup(testCtx, "creation_feedback", "pipeline creation feedback tests"));
1217 
1218 	// Graphics Pipeline Tests
1219 	{
1220 		de::MovePtr<tcu::TestCaseGroup> graphicsTests (new tcu::TestCaseGroup(testCtx, "graphics_tests", "Test pipeline creation feedback with graphics pipeline."));
1221 
1222 		const VkShaderStageFlags vertFragStages		= VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
1223 		const VkShaderStageFlags vertGeomFragStages	= vertFragStages | VK_SHADER_STAGE_GEOMETRY_BIT;
1224 		const VkShaderStageFlags vertTessFragStages	= vertFragStages | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
1225 
1226 		const std::vector<CacheTestParam> testParams
1227 		{
1228 			{ pipelineConstructionType, vertFragStages,		DE_FALSE, DE_FALSE },
1229 			{ pipelineConstructionType, vertGeomFragStages,	DE_FALSE, DE_FALSE },
1230 			{ pipelineConstructionType, vertTessFragStages,	DE_FALSE, DE_FALSE },
1231 			{ pipelineConstructionType, vertFragStages,		DE_TRUE,  DE_FALSE },
1232 			{ pipelineConstructionType, vertFragStages,		DE_TRUE,  DE_FALSE, DE_TRUE },
1233 			{ pipelineConstructionType, vertGeomFragStages,	DE_TRUE,  DE_FALSE },
1234 			{ pipelineConstructionType, vertTessFragStages,	DE_TRUE,  DE_FALSE },
1235 			{ pipelineConstructionType, vertFragStages,		DE_FALSE, DE_TRUE },
1236 			{ pipelineConstructionType, vertGeomFragStages,	DE_FALSE, DE_TRUE },
1237 			{ pipelineConstructionType, vertTessFragStages,	DE_FALSE, DE_TRUE },
1238 		};
1239 
1240 		for (auto& param : testParams)
1241 			graphicsTests->addChild(newTestCase<GraphicsCacheTest>(testCtx, &param));
1242 
1243 		cacheTests->addChild(graphicsTests.release());
1244 	}
1245 
1246 	// Compute Pipeline Tests - don't repeat those tests for graphics pipeline library
1247 	if (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
1248 	{
1249 		de::MovePtr<tcu::TestCaseGroup> computeTests (new tcu::TestCaseGroup(testCtx, "compute_tests", "Test pipeline creation feedback with compute pipeline."));
1250 
1251 		const std::vector<CacheTestParam> testParams
1252 		{
1253 			{ pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_FALSE, DE_FALSE },
1254 			{ pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_TRUE, DE_FALSE },
1255 			{ pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_FALSE, DE_TRUE },
1256 		};
1257 
1258 		for (auto& param : testParams)
1259 			computeTests->addChild(newTestCase<ComputeCacheTest>(testCtx, &param));
1260 
1261 		cacheTests->addChild(computeTests.release());
1262 	}
1263 
1264 	return cacheTests.release();
1265 }
1266 
1267 } // pipeline
1268 
1269 } // vkt
1270