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