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, ¶m));
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, ¶m));
1245
1246 cacheTests->addChild(computeTests.release());
1247 }
1248
1249 return cacheTests.release();
1250 }
1251
1252 } // pipeline
1253
1254 } // vkt
1255