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