• 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 			pipelineCreationIsHeavy[4] = true;
647 		}
648 	}
649 
650 	// pipelineCreationIsHeavy element 0 and 3 intentionally left false,
651 	// because these relate to vertex input and fragment output stages, which may be
652 	// created in nearly zero time.
653 
654 	gpw.setDefaultTopology((tescShaderModule == DE_NULL) ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST : VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)
655 	   .setDefaultRasterizationState()
656 	   .setDefaultMultisampleState()
657 	   .setupVertexInputState(&vertexInputStateParams, DE_NULL, *m_cache, pipelineCreationFeedbackWrapper[0])
658 	   .setupPreRasterizationShaderState(
659 			viewport,
660 			scissor,
661 			*m_pipelineLayout,
662 			*m_renderPass,
663 			0u,
664 			vertShaderModule,
665 			DE_NULL,
666 			tescShaderModule,
667 			teseShaderModule,
668 			geomShaderModule,
669 			DE_NULL,
670 			nullptr,
671 			PipelineRenderingCreateInfoWrapper(),
672 			*m_cache,
673 			pipelineCreationFeedbackWrapper[1])
674 	   .setupFragmentShaderState(
675 			*m_pipelineLayout,
676 			*m_renderPass,
677 			0u,
678 			fragShaderModule,
679 			&depthStencilStateParams,
680 			DE_NULL,
681 			DE_NULL,
682 			*m_cache,
683 			pipelineCreationFeedbackWrapper[2])
684 	   .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams, DE_NULL, *m_cache, pipelineCreationFeedbackWrapper[3])
685 	   .setMonolithicPipelineLayout(*m_pipelineLayout)
686 	   .buildPipeline(*m_cache, basePipelineHandle, basePipelineHandle != DE_NULL ? -1 : 0, pipelineCreationFeedbackWrapper[4]);
687 }
688 
verifyTestResult(void)689 tcu::TestStatus GraphicsCacheTestInstance::verifyTestResult (void)
690 {
691 	tcu::TestLog&	log						= m_context.getTestContext().getLog();
692 	bool			durationZeroWarning		= DE_FALSE;
693 	bool			cachedPipelineWarning	= DE_FALSE;
694 	bool			isMonolithic			= m_param->getPipelineConstructionType() == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC;
695 	bool			isZeroOutFeedbackCout	= m_param->isZeroOutFeedbackCount();
696 	deUint32		finalPipelineIndex		= deUint32(VK_MAX_PIPELINE_PARTS) - 1u;
697 	deUint32		start					= isMonolithic ? finalPipelineIndex : 0u;
698 	deUint32		step					= start + 1u;
699 
700 	// Iterate ofer creation feedback for all pipeline parts - if monolithic pipeline is tested then skip (step over) feedback for parts
701 	for (deUint32 creationFeedbackNdx = start; creationFeedbackNdx < VK_MAX_PIPELINE_PARTS * PIPELINE_CACHE_NDX_COUNT; creationFeedbackNdx += step)
702 	{
703 		deUint32		pipelineCacheNdx		= creationFeedbackNdx / deUint32(VK_MAX_PIPELINE_PARTS);
704 		auto			creationFeedbackFlags	= m_pipelineCreationFeedback[creationFeedbackNdx].flags;
705 		std::string		caseString				= getCaseStr(pipelineCacheNdx);
706 		deUint32		pipelinePartIndex	= creationFeedbackNdx % deUint32(VK_MAX_PIPELINE_PARTS);
707 
708 		std::ostringstream message;
709 		message << caseString;
710 		// Check first that the no cached pipeline was missed in the pipeline cache
711 
712 		// According to the spec:
713 		// "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
714 		//	may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
715 		if (!(creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
716 		{
717 			// According to the spec:
718 			// "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
719 			//	must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
720 			if (m_pipelineCreationFeedback[creationFeedbackNdx].flags)
721 			{
722 				std::ostringstream			errorMsg;
723 				errorMsg << ": Creation feedback is not valid but there are other flags written";
724 				return tcu::TestStatus::fail(errorMsg.str());
725 			}
726 			message << "\t\t Pipeline Creation Feedback data is not valid\n";
727 		}
728 		else
729 		{
730 			if (m_param->isCacheDisabled() && creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
731 			{
732 				message << ": feedback indicates pipeline hit cache when it shouldn't";
733 				return tcu::TestStatus::fail(message.str());
734 			}
735 
736 			if (pipelineCacheNdx == PIPELINE_CACHE_NDX_NO_CACHE && creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
737 			{
738 				message << ": hit the cache when it shouldn't";
739 				return tcu::TestStatus::fail(message.str());
740 			}
741 
742 			if (pipelineCacheNdx != PIPELINE_CACHE_NDX_DERIVATIVE && creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT)
743 			{
744 				message << ": feedback indicates base pipeline acceleration when it shouldn't";
745 				return tcu::TestStatus::fail(message.str());
746 			}
747 
748 			if (pipelineCacheNdx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
749 			{
750 				// For graphics pipeline library cache is only hit for the pre_rasterization and fragment_shader stages
751 				if (isMonolithic || (pipelinePartIndex == 1u) || (pipelinePartIndex == 2u))
752 				{
753 					message << "\nWarning: Cached pipeline case did not hit the cache";
754 					cachedPipelineWarning = DE_TRUE;
755 				}
756 			}
757 
758 			if (m_pipelineCreationFeedback[creationFeedbackNdx].duration == 0)
759 			{
760 				if (m_pipelineCreationIsHeavy[creationFeedbackNdx])
761 				{
762 					// Emit warnings only for pipelines, that are expected to have large creation times.
763 					// Pipelines containing only vertex input or fragment output stages may be created in
764 					// time duration less than the timer precision available on given platform.
765 
766 					message << "\nWarning: Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds\n";
767 					durationZeroWarning = DE_TRUE;
768 				}
769 			}
770 
771 			message << "\n";
772 			message << "\t\t Hit cache ? \t\t\t"				<< (creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT ? "yes" : "no")	<< "\n";
773 			message << "\t\t Base Pipeline Acceleration ? \t"	<< (creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ?	 "yes" : "no")		<< "\n";
774 			message << "\t\t Duration (ns): \t\t"				<< m_pipelineCreationFeedback[creationFeedbackNdx].duration																							<< "\n";
775 		}
776 
777 		// dont repeat checking shader feedback for pipeline parts - just check all shaders when checkin final pipelines
778 		if (pipelinePartIndex == finalPipelineIndex)
779 		{
780 			VkShaderStageFlags	testedShaderFlags	= m_param->getShaderFlags();
781 			deUint32			shaderCount			= 2u + ((testedShaderFlags & VK_SHADER_STAGE_GEOMETRY_BIT) != 0) +
782 														   ((testedShaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) +
783 														   ((testedShaderFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0);
784 			for(deUint32 shader = 0; shader < shaderCount; shader++)
785 			{
786 				const deUint32 index = VK_MAX_SHADER_STAGES * pipelineCacheNdx + shader;
787 				message << "\t" <<(shader + 1) << " shader stage\n";
788 
789 				// According to the spec:
790 				// "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
791 				//      may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
792 				if (m_pipelineStageCreationFeedbacks[index].flags & isZeroOutFeedbackCout)
793 				{
794 					std::ostringstream			errorMsg;
795 					errorMsg << caseString << ": feedback indicates pipeline " << (shader + 1) << " shader stage feedback was generated despite setting feedback count to zero";
796 					return tcu::TestStatus::fail(errorMsg.str());
797 				}
798 
799 				if (!(m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
800 				{
801 					// According to the spec:
802 					// "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
803 					//      must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
804 					if (m_pipelineStageCreationFeedbacks[index].flags)
805 					{
806 						std::ostringstream			errorMsg;
807 						errorMsg << caseString << ": Creation feedback is not valid for " << (shader + 1) << " shader stage but there are other flags written";
808 						return tcu::TestStatus::fail(errorMsg.str());
809 					}
810 					message << "\t\t Pipeline Creation Feedback data is not valid\n";
811 					continue;
812 				}
813 				if (m_param->isCacheDisabled() && m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
814 				{
815 					std::ostringstream			errorMsg;
816 					errorMsg << caseString << ": feedback indicates pipeline " << (shader + 1) << " shader stage hit cache when it shouldn't";
817 					return tcu::TestStatus::fail(errorMsg.str());
818 				}
819 
820 				if (pipelineCacheNdx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
821 				{
822 					message << "Warning: pipeline stage did not hit the cache\n";
823 					cachedPipelineWarning = DE_TRUE;
824 				}
825 				if (cachedPipelineWarning && m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
826 				{
827 					// We only set the warning when the pipeline nor the pipeline stages hit the cache. If any of them did, them disable the warning.
828 					cachedPipelineWarning = DE_FALSE;
829 				}
830 
831 				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";
832 				message << "\t\t Base Pipeline Acceleration ? \t"	<< (m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ?	 "yes" : "no")		<< "\n";
833 				message << "\t\t Duration (ns): \t\t"				<< m_pipelineStageCreationFeedbacks[index].duration																							<< "\n";
834 			}
835 		}
836 
837 		log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
838 	}
839 
840 	if (cachedPipelineWarning)
841 	{
842 		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Cached pipeline or stage did not hit the cache");
843 	}
844 	if (durationZeroWarning)
845 	{
846 		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds");
847 	}
848 	return tcu::TestStatus::pass("Pass");
849 }
850 
clearFeedbacks(void)851 void GraphicsCacheTestInstance::clearFeedbacks(void)
852 {
853 	deMemset(m_pipelineCreationFeedback, 0, sizeof(VkPipelineCreationFeedbackEXT) * VK_MAX_PIPELINE_PARTS * PIPELINE_CACHE_NDX_COUNT);
854 	deMemset(m_pipelineStageCreationFeedbacks, 0, sizeof(VkPipelineCreationFeedbackEXT) * PIPELINE_CACHE_NDX_COUNT * VK_MAX_SHADER_STAGES);
855 }
856 
857 class ComputeCacheTest : public CacheTest
858 {
859 public:
ComputeCacheTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,const CacheTestParam * param)860 							ComputeCacheTest		(tcu::TestContext&		testContext,
861 													 const std::string&		name,
862 													 const std::string&		description,
863 													 const CacheTestParam*	param)
864 								: CacheTest		(testContext, name, description, param)
865 								{ }
~ComputeCacheTest(void)866 	virtual					~ComputeCacheTest	(void) { }
867 	virtual void			initPrograms			(SourceCollections&	programCollection) const;
868 	virtual TestInstance*	createInstance			(Context&				context) const;
869 };
870 
871 class ComputeCacheTestInstance : public CacheTestInstance
872 {
873 public:
874 							ComputeCacheTestInstance		(Context&				context,
875 															 const CacheTestParam*	param);
876 	virtual					~ComputeCacheTestInstance	(void);
877 protected:
878 	virtual tcu::TestStatus verifyTestResult				(void);
879 			void			buildDescriptorSets				(deUint32 ndx);
880 			void			buildShader						(deUint32 ndx);
881 			void			buildPipeline					(const CacheTestParam*	param, deUint32 ndx);
882 protected:
883 	Move<VkBuffer>					m_inputBuf;
884 	de::MovePtr<Allocation>			m_inputBufferAlloc;
885 	Move<VkShaderModule>			m_computeShaderModule[PIPELINE_CACHE_NDX_COUNT];
886 
887 	Move<VkBuffer>					m_outputBuf[PIPELINE_CACHE_NDX_COUNT];
888 	de::MovePtr<Allocation>			m_outputBufferAlloc[PIPELINE_CACHE_NDX_COUNT];
889 
890 	Move<VkDescriptorPool>			m_descriptorPool[PIPELINE_CACHE_NDX_COUNT];
891 	Move<VkDescriptorSetLayout>		m_descriptorSetLayout[PIPELINE_CACHE_NDX_COUNT];
892 	Move<VkDescriptorSet>			m_descriptorSet[PIPELINE_CACHE_NDX_COUNT];
893 
894 	Move<VkPipelineLayout>			m_pipelineLayout[PIPELINE_CACHE_NDX_COUNT];
895 	VkPipeline						m_pipeline[PIPELINE_CACHE_NDX_COUNT];
896 	VkPipelineCreationFeedbackEXT	m_pipelineCreationFeedback[PIPELINE_CACHE_NDX_COUNT];
897 	VkPipelineCreationFeedbackEXT	m_pipelineStageCreationFeedback[PIPELINE_CACHE_NDX_COUNT];
898 };
899 
initPrograms(SourceCollections & programCollection) const900 void ComputeCacheTest::initPrograms (SourceCollections& programCollection) const
901 {
902 	programCollection.glslSources.add("basic_compute_1") << glu::ComputeSource(
903 		"#version 310 es\n"
904 		"layout(local_size_x = 1) in;\n"
905 		"layout(std430) buffer;\n"
906 		"layout(binding = 0) readonly buffer Input0\n"
907 		"{\n"
908 		"  vec4 elements[];\n"
909 		"} input_data0;\n"
910 		"layout(binding = 1) writeonly buffer Output\n"
911 		"{\n"
912 		"  vec4 elements[];\n"
913 		"} output_data;\n"
914 		"void main()\n"
915 		"{\n"
916 		"  uint ident = gl_GlobalInvocationID.x;\n"
917 		"  output_data.elements[ident] = input_data0.elements[ident] * input_data0.elements[ident];\n"
918 		"}");
919 	programCollection.glslSources.add("basic_compute_2") << glu::ComputeSource(
920 		"#version 310 es\n"
921 		"layout(local_size_x = 1) in;\n"
922 		"layout(std430) buffer;\n"
923 		"layout(binding = 0) readonly buffer Input0\n"
924 		"{\n"
925 		"  vec4 elements[];\n"
926 		"} input_data0;\n"
927 		"layout(binding = 1) writeonly buffer Output\n"
928 		"{\n"
929 		"  vec4 elements[];\n"
930 		"} output_data;\n"
931 		"void main()\n"
932 		"{\n"
933 		"  uint ident = gl_GlobalInvocationID.x;\n"
934 		"  output_data.elements[ident] = input_data0.elements[ident];\n"
935 		"}");
936 }
937 
createInstance(Context & context) const938 TestInstance* ComputeCacheTest::createInstance (Context& context) const
939 {
940 	return new ComputeCacheTestInstance(context, &m_param);
941 }
942 
buildDescriptorSets(deUint32 ndx)943 void ComputeCacheTestInstance::buildDescriptorSets (deUint32 ndx)
944 {
945 	const DeviceInterface&	vk				= m_context.getDeviceInterface();
946 	const VkDevice			vkDevice		= m_context.getDevice();
947 
948 	// Create descriptor set layout
949 	DescriptorSetLayoutBuilder descLayoutBuilder;
950 	for (deUint32 bindingNdx = 0u; bindingNdx < 2u; bindingNdx++)
951 		descLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
952 	m_descriptorSetLayout[ndx] = descLayoutBuilder.build(vk, vkDevice);
953 }
954 
buildShader(deUint32 ndx)955 void ComputeCacheTestInstance::buildShader (deUint32 ndx)
956 {
957 	const DeviceInterface&	vk				= m_context.getDeviceInterface();
958 	const VkDevice			vkDevice		= m_context.getDevice();
959 
960 	std::string shader_name("basic_compute_");
961 
962 	shader_name += (ndx == PIPELINE_CACHE_NDX_DERIVATIVE) ? "2" : "1";
963 
964 	// Create compute shader
965 	VkShaderModuleCreateInfo shaderModuleCreateInfo =
966 	{
967 		VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,								// VkStructureType				sType;
968 		DE_NULL,																	// const void*					pNext;
969 		0u,																			// VkShaderModuleCreateFlags	flags;
970 		m_context.getBinaryCollection().get(shader_name).getSize(),					// deUintptr					codeSize;
971 		(deUint32*)m_context.getBinaryCollection().get(shader_name).getBinary(),	// const deUint32*				pCode;
972 	};
973 	m_computeShaderModule[ndx] = createShaderModule(vk, vkDevice, &shaderModuleCreateInfo);
974 }
975 
buildPipeline(const CacheTestParam * param,deUint32 ndx)976 void ComputeCacheTestInstance::buildPipeline (const CacheTestParam*	param, deUint32 ndx)
977 {
978 	const DeviceInterface&	vk					 = m_context.getDeviceInterface();
979 	const VkDevice			vkDevice			 = m_context.getDevice();
980 	const VkBool32			zeroOutFeedbackCount = param->isZeroOutFeedbackCount();
981 
982 	deMemset(&m_pipelineCreationFeedback[ndx], 0, sizeof(VkPipelineCreationFeedbackEXT));
983 	deMemset(&m_pipelineStageCreationFeedback[ndx], 0, sizeof(VkPipelineCreationFeedbackEXT));
984 
985 	const VkPipelineCreationFeedbackCreateInfoEXT pipelineCreationFeedbackCreateInfo =
986 	{
987 		VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT,	// VkStructureType					sType;
988 		DE_NULL,														// const void *						pNext;
989 		&m_pipelineCreationFeedback[ndx],								// VkPipelineCreationFeedbackEXT*	pPipelineCreationFeedback;
990 		zeroOutFeedbackCount ? 0u : 1u,									// deUint32							pipelineStageCreationFeedbackCount;
991 		&m_pipelineStageCreationFeedback[ndx]							// VkPipelineCreationFeedbackEXT*	pPipelineStageCreationFeedbacks;
992 	};
993 
994 	// Create compute pipeline layout
995 	const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
996 	{
997 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,					// VkStructureType					sType;
998 		DE_NULL,														// const void*						pNext;
999 		0u,																// VkPipelineLayoutCreateFlags		flags;
1000 		1u,																// deUint32							setLayoutCount;
1001 		&m_descriptorSetLayout[ndx].get(),								// const VkDescriptorSetLayout*		pSetLayouts;
1002 		0u,																// deUint32							pushConstantRangeCount;
1003 		DE_NULL,														// const VkPushConstantRange*		pPushConstantRanges;
1004 	};
1005 
1006 	m_pipelineLayout[ndx] = createPipelineLayout(vk, vkDevice, &pipelineLayoutCreateInfo);
1007 
1008 	const VkPipelineShaderStageCreateInfo stageCreateInfo =
1009 	{
1010 		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,			// VkStructureType					sType;
1011 		DE_NULL,														// const void*						pNext;
1012 		0u,																// VkPipelineShaderStageCreateFlags	flags;
1013 		VK_SHADER_STAGE_COMPUTE_BIT,									// VkShaderStageFlagBits			stage;
1014 		*m_computeShaderModule[ndx],									// VkShaderModule					module;
1015 		"main",															// const char*						pName;
1016 		DE_NULL,														// const VkSpecializationInfo*		pSpecializationInfo;
1017 	};
1018 
1019 	VkComputePipelineCreateInfo pipelineCreateInfo =
1020 	{
1021 		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,					// VkStructureType					sType;
1022 		&pipelineCreationFeedbackCreateInfo,							// const void*						pNext;
1023 		0u,																// VkPipelineCreateFlags			flags;
1024 		stageCreateInfo,												// VkPipelineShaderStageCreateInfo	stage;
1025 		*m_pipelineLayout[ndx],											// VkPipelineLayout					layout;
1026 		(VkPipeline)0,													// VkPipeline						basePipelineHandle;
1027 		0u,																// deInt32							basePipelineIndex;
1028 	};
1029 
1030 	if (ndx != PIPELINE_CACHE_NDX_DERIVATIVE)
1031 	{
1032 		pipelineCreateInfo.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
1033 	}
1034 
1035 	if (ndx == PIPELINE_CACHE_NDX_DERIVATIVE)
1036 	{
1037 		pipelineCreateInfo.flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT;
1038 		pipelineCreateInfo.basePipelineHandle = m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE];
1039 		pipelineCreateInfo.basePipelineIndex = -1;
1040 	}
1041 
1042 	if (ndx == PIPELINE_CACHE_NDX_CACHED && !param->isDelayedDestroy())
1043 	{
1044 		// Destroy the NO_CACHE pipeline to check that the cached one really hits cache,
1045 		// except for the case where we're testing cache hit of a pipeline still active.
1046 		vk.destroyPipeline(vkDevice, m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE], DE_NULL);
1047 	}
1048 
1049 	vk.createComputePipelines(vkDevice, *m_cache, 1u, &pipelineCreateInfo, DE_NULL, &m_pipeline[ndx]);
1050 
1051 	if (ndx != PIPELINE_CACHE_NDX_NO_CACHE)
1052 	{
1053 		// Destroy the pipeline as soon as it is created, except the NO_CACHE because
1054 		// it is needed as a base pipeline for the derivative case.
1055 		vk.destroyPipeline(vkDevice, m_pipeline[ndx], DE_NULL);
1056 
1057 		if (ndx == PIPELINE_CACHE_NDX_CACHED && param->isDelayedDestroy())
1058 		{
1059 			// Destroy the pipeline we didn't destroy earlier for the isDelayedDestroy case.
1060 			vk.destroyPipeline(vkDevice, m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE], DE_NULL);
1061 		}
1062 	}
1063 }
1064 
ComputeCacheTestInstance(Context & context,const CacheTestParam * param)1065 ComputeCacheTestInstance::ComputeCacheTestInstance (Context&				context,
1066 													const CacheTestParam*	param)
1067 	: CacheTestInstance (context, param)
1068 {
1069 	for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
1070 	{
1071 		buildDescriptorSets(ndx);
1072 		buildShader(ndx);
1073 		buildPipeline(param, ndx);
1074 	}
1075 }
1076 
~ComputeCacheTestInstance(void)1077 ComputeCacheTestInstance::~ComputeCacheTestInstance (void)
1078 {
1079 }
1080 
verifyTestResult(void)1081 tcu::TestStatus ComputeCacheTestInstance::verifyTestResult (void)
1082 {
1083 	tcu::TestLog &log				= m_context.getTestContext().getLog();
1084 	deBool durationZeroWarning		= DE_FALSE;
1085 	deBool cachedPipelineWarning	= DE_FALSE;
1086 
1087 	for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
1088 	{
1089 		std::ostringstream message;
1090 		message << getCaseStr(ndx);
1091 
1092 		// No need to check per stage status as it is compute pipeline (only one stage) and Vulkan spec mentions that:
1093 		// "One common scenario for an implementation to skip per-stage feedback is when
1094 		// VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT is set in pPipelineCreationFeedback."
1095 		//
1096 		// Check first that the no cached pipeline was missed in the pipeline cache
1097 
1098 		// According to the spec:
1099 		// "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
1100 		//	may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
1101 		if (!(m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
1102 		{
1103 			// According to the spec:
1104 			// "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
1105 			//	must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
1106 			if (m_pipelineCreationFeedback[ndx].flags)
1107 			{
1108 				std::ostringstream			errorMsg;
1109 				errorMsg << ": Creation feedback is not valid but there are other flags written";
1110 				return tcu::TestStatus::fail(errorMsg.str());
1111 			}
1112 			message << "\t\t Pipeline Creation Feedback data is not valid\n";
1113 		}
1114 		else
1115 		{
1116 			if (m_param->isCacheDisabled() && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1117 			{
1118 				message << ": feedback indicates pipeline hit cache when it shouldn't";
1119 				return tcu::TestStatus::fail(message.str());
1120 			}
1121 
1122 			if (ndx == PIPELINE_CACHE_NDX_NO_CACHE && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1123 			{
1124 				message << ": hit the cache when it shouldn't";
1125 				return tcu::TestStatus::fail(message.str());
1126 			}
1127 
1128 			if (!(ndx == PIPELINE_CACHE_NDX_DERIVATIVE && !m_param->isCacheDisabled()) && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT)
1129 			{
1130 				message << ": feedback indicates base pipeline acceleration when it shouldn't";
1131 				return tcu::TestStatus::fail(message.str());
1132 			}
1133 
1134 			if (ndx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
1135 			{
1136 				message << "\nWarning: Cached pipeline case did not hit the cache";
1137 				cachedPipelineWarning = DE_TRUE;
1138 			}
1139 
1140 			if (m_pipelineCreationFeedback[ndx].duration == 0)
1141 			{
1142 				message << "\nWarning: Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds\n";
1143 				durationZeroWarning = DE_TRUE;
1144 			}
1145 
1146 			message << "\n";
1147 
1148 			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";
1149 			message << "\t\t Base Pipeline Acceleration ? \t"	<< (m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ? "yes" : "no")		<< "\n";
1150 			message << "\t\t Duration (ns): \t\t"				<< m_pipelineCreationFeedback[ndx].duration																						<< "\n";
1151 
1152 			message << "\t Compute Stage\n";
1153 		}
1154 
1155 		// According to the spec:
1156 		// "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
1157 		//	may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
1158 		if (!(m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
1159 		{
1160 			// According to the spec:
1161 			// "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
1162 			//	must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
1163 			if (m_pipelineStageCreationFeedback[ndx].flags)
1164 			{
1165 				std::ostringstream			errorMsg;
1166 				errorMsg << getCaseStr(ndx) << ": Creation feedback is not valid for compute stage but there are other flags written";
1167 				return tcu::TestStatus::fail(errorMsg.str());
1168 			}
1169 			message << "\t\t Pipeline Creation Feedback data is not valid\n";
1170 		}
1171 		else
1172 		{
1173 			if (m_param->isCacheDisabled() && m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1174 			{
1175 				std::ostringstream			errorMsg;
1176 				errorMsg << getCaseStr(ndx) << ": feedback indicates pipeline compute stage hit cache when it shouldn't";
1177 				return tcu::TestStatus::fail(errorMsg.str());
1178 			}
1179 
1180 			if (ndx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
1181 			{
1182 				message << "Warning: pipeline stage did not hit the cache\n";
1183 				cachedPipelineWarning = DE_TRUE;
1184 			}
1185 			if (cachedPipelineWarning && m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1186 			{
1187 				// We only set the warning when the pipeline nor the pipeline stages hit the cache. If any of them did, them disable the warning.
1188 				cachedPipelineWarning = DE_FALSE;
1189 			}
1190 
1191 			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";
1192 			message << "\t\t Base Pipeline Acceleration ? \t"	<< (m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ? "yes" : "no")		<< "\n";
1193 			message << "\t\t Duration (ns): \t\t"				<< m_pipelineStageCreationFeedback[ndx].duration																						<< "\n";
1194 		}
1195 
1196 		log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
1197 	}
1198 
1199 	if (cachedPipelineWarning)
1200 	{
1201 		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Cached pipeline or stage did not hit the cache");
1202 	}
1203 	if (durationZeroWarning)
1204 	{
1205 		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds");
1206 	}
1207 	return tcu::TestStatus::pass("Pass");
1208 }
1209 } // anonymous
1210 
createCreationFeedbackTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1211 tcu::TestCaseGroup* createCreationFeedbackTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
1212 {
1213 	de::MovePtr<tcu::TestCaseGroup> cacheTests (new tcu::TestCaseGroup(testCtx, "creation_feedback", "pipeline creation feedback tests"));
1214 
1215 	// Graphics Pipeline Tests
1216 	{
1217 		de::MovePtr<tcu::TestCaseGroup> graphicsTests (new tcu::TestCaseGroup(testCtx, "graphics_tests", "Test pipeline creation feedback with graphics pipeline."));
1218 
1219 		const VkShaderStageFlags vertFragStages		= VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
1220 		const VkShaderStageFlags vertGeomFragStages	= vertFragStages | VK_SHADER_STAGE_GEOMETRY_BIT;
1221 		const VkShaderStageFlags vertTessFragStages	= vertFragStages | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
1222 
1223 		const std::vector<CacheTestParam> testParams
1224 		{
1225 			{ pipelineConstructionType, vertFragStages,		DE_FALSE, DE_FALSE },
1226 			{ pipelineConstructionType, vertGeomFragStages,	DE_FALSE, DE_FALSE },
1227 			{ pipelineConstructionType, vertTessFragStages,	DE_FALSE, DE_FALSE },
1228 			{ pipelineConstructionType, vertFragStages,		DE_TRUE,  DE_FALSE },
1229 			{ pipelineConstructionType, vertFragStages,		DE_TRUE,  DE_FALSE, DE_TRUE },
1230 			{ pipelineConstructionType, vertGeomFragStages,	DE_TRUE,  DE_FALSE },
1231 			{ pipelineConstructionType, vertTessFragStages,	DE_TRUE,  DE_FALSE },
1232 			{ pipelineConstructionType, vertFragStages,		DE_FALSE, DE_TRUE },
1233 			{ pipelineConstructionType, vertGeomFragStages,	DE_FALSE, DE_TRUE },
1234 			{ pipelineConstructionType, vertTessFragStages,	DE_FALSE, DE_TRUE },
1235 		};
1236 
1237 		for (auto& param : testParams)
1238 			graphicsTests->addChild(newTestCase<GraphicsCacheTest>(testCtx, &param));
1239 
1240 		cacheTests->addChild(graphicsTests.release());
1241 	}
1242 
1243 	// Compute Pipeline Tests - don't repeat those tests for graphics pipeline library
1244 	if (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
1245 	{
1246 		de::MovePtr<tcu::TestCaseGroup> computeTests (new tcu::TestCaseGroup(testCtx, "compute_tests", "Test pipeline creation feedback with compute pipeline."));
1247 
1248 		const std::vector<CacheTestParam> testParams
1249 		{
1250 			{ pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_FALSE, DE_FALSE },
1251 			{ pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_TRUE, DE_FALSE },
1252 			{ pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_FALSE, DE_TRUE },
1253 		};
1254 
1255 		for (auto& param : testParams)
1256 			computeTests->addChild(newTestCase<ComputeCacheTest>(testCtx, &param));
1257 
1258 		cacheTests->addChild(computeTests.release());
1259 	}
1260 
1261 	return cacheTests.release();
1262 }
1263 
1264 } // pipeline
1265 
1266 } // vkt
1267