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