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 ¶m : testParams)
1466 {
1467 if (!param.isCacheDisabled() && (testMode == TestMode::BINARY))
1468 continue;
1469 graphicsTests->addChild(newTestCase<GraphicsTestCase>(testCtx, ¶m));
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 ¶m : testParams)
1487 {
1488 if (param.isCacheDisabled() && (testMode == TestMode::BINARY))
1489 continue;
1490 computeTests->addChild(newTestCase<ComputeTestCase>(testCtx, ¶m));
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