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