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 pipelineCreationFeedbackCreateInfo[4].pipelineStageCreationFeedbackCount = zeroOutFeedbackCount ? 0u : (1u + geometryStages);
647 pipelineCreationFeedbackCreateInfo[4].pPipelineStageCreationFeedbacks = pipelineStageCreationFeedbacks;
648
649 pipelineCreationIsHeavy[4] = true;
650 }
651 }
652
653 // pipelineCreationIsHeavy element 0 and 3 intentionally left false,
654 // because these relate to vertex input and fragment output stages, which may be
655 // created in nearly zero time.
656
657 gpw.setDefaultTopology((tescShaderModule == DE_NULL) ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST : VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)
658 .setDefaultRasterizationState()
659 .setDefaultMultisampleState()
660 .setupVertexInputState(&vertexInputStateParams, DE_NULL, *m_cache, pipelineCreationFeedbackWrapper[0])
661 .setupPreRasterizationShaderState(
662 viewport,
663 scissor,
664 *m_pipelineLayout,
665 *m_renderPass,
666 0u,
667 vertShaderModule,
668 DE_NULL,
669 tescShaderModule,
670 teseShaderModule,
671 geomShaderModule,
672 DE_NULL,
673 nullptr,
674 PipelineRenderingCreateInfoWrapper(),
675 *m_cache,
676 pipelineCreationFeedbackWrapper[1])
677 .setupFragmentShaderState(
678 *m_pipelineLayout,
679 *m_renderPass,
680 0u,
681 fragShaderModule,
682 &depthStencilStateParams,
683 DE_NULL,
684 DE_NULL,
685 *m_cache,
686 pipelineCreationFeedbackWrapper[2])
687 .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams, DE_NULL, *m_cache, pipelineCreationFeedbackWrapper[3])
688 .setMonolithicPipelineLayout(*m_pipelineLayout)
689 .buildPipeline(*m_cache, basePipelineHandle, basePipelineHandle != DE_NULL ? -1 : 0, pipelineCreationFeedbackWrapper[4]);
690 }
691
verifyTestResult(void)692 tcu::TestStatus GraphicsCacheTestInstance::verifyTestResult (void)
693 {
694 tcu::TestLog& log = m_context.getTestContext().getLog();
695 bool durationZeroWarning = DE_FALSE;
696 bool cachedPipelineWarning = DE_FALSE;
697 bool isMonolithic = m_param->getPipelineConstructionType() == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC;
698 bool isZeroOutFeedbackCout = m_param->isZeroOutFeedbackCount();
699 deUint32 finalPipelineIndex = deUint32(VK_MAX_PIPELINE_PARTS) - 1u;
700 deUint32 start = isMonolithic ? finalPipelineIndex : 0u;
701 deUint32 step = start + 1u;
702
703 // Iterate ofer creation feedback for all pipeline parts - if monolithic pipeline is tested then skip (step over) feedback for parts
704 for (deUint32 creationFeedbackNdx = start; creationFeedbackNdx < VK_MAX_PIPELINE_PARTS * PIPELINE_CACHE_NDX_COUNT; creationFeedbackNdx += step)
705 {
706 deUint32 pipelineCacheNdx = creationFeedbackNdx / deUint32(VK_MAX_PIPELINE_PARTS);
707 auto creationFeedbackFlags = m_pipelineCreationFeedback[creationFeedbackNdx].flags;
708 std::string caseString = getCaseStr(pipelineCacheNdx);
709 deUint32 pipelinePartIndex = creationFeedbackNdx % deUint32(VK_MAX_PIPELINE_PARTS);
710
711 std::ostringstream message;
712 message << caseString;
713 // Check first that the no cached pipeline was missed in the pipeline cache
714
715 // According to the spec:
716 // "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
717 // may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
718 if (!(creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
719 {
720 // According to the spec:
721 // "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
722 // must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
723 if (m_pipelineCreationFeedback[creationFeedbackNdx].flags)
724 {
725 std::ostringstream errorMsg;
726 errorMsg << ": Creation feedback is not valid but there are other flags written";
727 return tcu::TestStatus::fail(errorMsg.str());
728 }
729 message << "\t\t Pipeline Creation Feedback data is not valid\n";
730 }
731 else
732 {
733 if (m_param->isCacheDisabled() && creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
734 {
735 message << ": feedback indicates pipeline hit cache when it shouldn't";
736 return tcu::TestStatus::fail(message.str());
737 }
738
739 if (pipelineCacheNdx == PIPELINE_CACHE_NDX_NO_CACHE && creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
740 {
741 message << ": hit the cache when it shouldn't";
742 return tcu::TestStatus::fail(message.str());
743 }
744
745 if (pipelineCacheNdx != PIPELINE_CACHE_NDX_DERIVATIVE && creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT)
746 {
747 message << ": feedback indicates base pipeline acceleration when it shouldn't";
748 return tcu::TestStatus::fail(message.str());
749 }
750
751 if (pipelineCacheNdx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
752 {
753 // For graphics pipeline library cache is only hit for the pre_rasterization and fragment_shader stages
754 if (isMonolithic || (pipelinePartIndex == 1u) || (pipelinePartIndex == 2u))
755 {
756 message << "\nWarning: Cached pipeline case did not hit the cache";
757 cachedPipelineWarning = DE_TRUE;
758 }
759 }
760
761 if (m_pipelineCreationFeedback[creationFeedbackNdx].duration == 0)
762 {
763 if (m_pipelineCreationIsHeavy[creationFeedbackNdx])
764 {
765 // Emit warnings only for pipelines, that are expected to have large creation times.
766 // Pipelines containing only vertex input or fragment output stages may be created in
767 // time duration less than the timer precision available on given platform.
768
769 message << "\nWarning: Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds\n";
770 durationZeroWarning = DE_TRUE;
771 }
772 }
773
774 message << "\n";
775 message << "\t\t Hit cache ? \t\t\t" << (creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT ? "yes" : "no") << "\n";
776 message << "\t\t Base Pipeline Acceleration ? \t" << (creationFeedbackFlags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ? "yes" : "no") << "\n";
777 message << "\t\t Duration (ns): \t\t" << m_pipelineCreationFeedback[creationFeedbackNdx].duration << "\n";
778 }
779
780 // dont repeat checking shader feedback for pipeline parts - just check all shaders when checkin final pipelines
781 if (pipelinePartIndex == finalPipelineIndex)
782 {
783 VkShaderStageFlags testedShaderFlags = m_param->getShaderFlags();
784 deUint32 shaderCount = 2u + ((testedShaderFlags & VK_SHADER_STAGE_GEOMETRY_BIT) != 0) +
785 ((testedShaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) +
786 ((testedShaderFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0);
787 for(deUint32 shader = 0; shader < shaderCount; shader++)
788 {
789 const deUint32 index = VK_MAX_SHADER_STAGES * pipelineCacheNdx + shader;
790 message << "\t" <<(shader + 1) << " shader stage\n";
791
792 // According to the spec:
793 // "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
794 // may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
795 if (m_pipelineStageCreationFeedbacks[index].flags & isZeroOutFeedbackCout)
796 {
797 std::ostringstream errorMsg;
798 errorMsg << caseString << ": feedback indicates pipeline " << (shader + 1) << " shader stage feedback was generated despite setting feedback count to zero";
799 return tcu::TestStatus::fail(errorMsg.str());
800 }
801
802 if (!(m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
803 {
804 // According to the spec:
805 // "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
806 // must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
807 if (m_pipelineStageCreationFeedbacks[index].flags)
808 {
809 std::ostringstream errorMsg;
810 errorMsg << caseString << ": Creation feedback is not valid for " << (shader + 1) << " shader stage but there are other flags written";
811 return tcu::TestStatus::fail(errorMsg.str());
812 }
813 message << "\t\t Pipeline Creation Feedback data is not valid\n";
814 continue;
815 }
816 if (m_param->isCacheDisabled() && m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
817 {
818 std::ostringstream errorMsg;
819 errorMsg << caseString << ": feedback indicates pipeline " << (shader + 1) << " shader stage hit cache when it shouldn't";
820 return tcu::TestStatus::fail(errorMsg.str());
821 }
822
823 if (pipelineCacheNdx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
824 {
825 message << "Warning: pipeline stage did not hit the cache\n";
826 cachedPipelineWarning = DE_TRUE;
827 }
828 if (cachedPipelineWarning && m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
829 {
830 // We only set the warning when the pipeline nor the pipeline stages hit the cache. If any of them did, them disable the warning.
831 cachedPipelineWarning = DE_FALSE;
832 }
833
834 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";
835 message << "\t\t Base Pipeline Acceleration ? \t" << (m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ? "yes" : "no") << "\n";
836 message << "\t\t Duration (ns): \t\t" << m_pipelineStageCreationFeedbacks[index].duration << "\n";
837 }
838 }
839
840 log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
841 }
842
843 if (cachedPipelineWarning)
844 {
845 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Cached pipeline or stage did not hit the cache");
846 }
847 if (durationZeroWarning)
848 {
849 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds");
850 }
851 return tcu::TestStatus::pass("Pass");
852 }
853
clearFeedbacks(void)854 void GraphicsCacheTestInstance::clearFeedbacks(void)
855 {
856 deMemset(m_pipelineCreationFeedback, 0, sizeof(VkPipelineCreationFeedbackEXT) * VK_MAX_PIPELINE_PARTS * PIPELINE_CACHE_NDX_COUNT);
857 deMemset(m_pipelineStageCreationFeedbacks, 0, sizeof(VkPipelineCreationFeedbackEXT) * PIPELINE_CACHE_NDX_COUNT * VK_MAX_SHADER_STAGES);
858 }
859
860 class ComputeCacheTest : public CacheTest
861 {
862 public:
ComputeCacheTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,const CacheTestParam * param)863 ComputeCacheTest (tcu::TestContext& testContext,
864 const std::string& name,
865 const std::string& description,
866 const CacheTestParam* param)
867 : CacheTest (testContext, name, description, param)
868 { }
~ComputeCacheTest(void)869 virtual ~ComputeCacheTest (void) { }
870 virtual void initPrograms (SourceCollections& programCollection) const;
871 virtual TestInstance* createInstance (Context& context) const;
872 };
873
874 class ComputeCacheTestInstance : public CacheTestInstance
875 {
876 public:
877 ComputeCacheTestInstance (Context& context,
878 const CacheTestParam* param);
879 virtual ~ComputeCacheTestInstance (void);
880 protected:
881 virtual tcu::TestStatus verifyTestResult (void);
882 void buildDescriptorSets (deUint32 ndx);
883 void buildShader (deUint32 ndx);
884 void buildPipeline (const CacheTestParam* param, deUint32 ndx);
885 protected:
886 Move<VkBuffer> m_inputBuf;
887 de::MovePtr<Allocation> m_inputBufferAlloc;
888 Move<VkShaderModule> m_computeShaderModule[PIPELINE_CACHE_NDX_COUNT];
889
890 Move<VkBuffer> m_outputBuf[PIPELINE_CACHE_NDX_COUNT];
891 de::MovePtr<Allocation> m_outputBufferAlloc[PIPELINE_CACHE_NDX_COUNT];
892
893 Move<VkDescriptorPool> m_descriptorPool[PIPELINE_CACHE_NDX_COUNT];
894 Move<VkDescriptorSetLayout> m_descriptorSetLayout[PIPELINE_CACHE_NDX_COUNT];
895 Move<VkDescriptorSet> m_descriptorSet[PIPELINE_CACHE_NDX_COUNT];
896
897 Move<VkPipelineLayout> m_pipelineLayout[PIPELINE_CACHE_NDX_COUNT];
898 VkPipeline m_pipeline[PIPELINE_CACHE_NDX_COUNT];
899 VkPipelineCreationFeedbackEXT m_pipelineCreationFeedback[PIPELINE_CACHE_NDX_COUNT];
900 VkPipelineCreationFeedbackEXT m_pipelineStageCreationFeedback[PIPELINE_CACHE_NDX_COUNT];
901 };
902
initPrograms(SourceCollections & programCollection) const903 void ComputeCacheTest::initPrograms (SourceCollections& programCollection) const
904 {
905 programCollection.glslSources.add("basic_compute_1") << glu::ComputeSource(
906 "#version 310 es\n"
907 "layout(local_size_x = 1) in;\n"
908 "layout(std430) buffer;\n"
909 "layout(binding = 0) readonly buffer Input0\n"
910 "{\n"
911 " vec4 elements[];\n"
912 "} input_data0;\n"
913 "layout(binding = 1) writeonly buffer Output\n"
914 "{\n"
915 " vec4 elements[];\n"
916 "} output_data;\n"
917 "void main()\n"
918 "{\n"
919 " uint ident = gl_GlobalInvocationID.x;\n"
920 " output_data.elements[ident] = input_data0.elements[ident] * input_data0.elements[ident];\n"
921 "}");
922 programCollection.glslSources.add("basic_compute_2") << glu::ComputeSource(
923 "#version 310 es\n"
924 "layout(local_size_x = 1) in;\n"
925 "layout(std430) buffer;\n"
926 "layout(binding = 0) readonly buffer Input0\n"
927 "{\n"
928 " vec4 elements[];\n"
929 "} input_data0;\n"
930 "layout(binding = 1) writeonly buffer Output\n"
931 "{\n"
932 " vec4 elements[];\n"
933 "} output_data;\n"
934 "void main()\n"
935 "{\n"
936 " uint ident = gl_GlobalInvocationID.x;\n"
937 " output_data.elements[ident] = input_data0.elements[ident];\n"
938 "}");
939 }
940
createInstance(Context & context) const941 TestInstance* ComputeCacheTest::createInstance (Context& context) const
942 {
943 return new ComputeCacheTestInstance(context, &m_param);
944 }
945
buildDescriptorSets(deUint32 ndx)946 void ComputeCacheTestInstance::buildDescriptorSets (deUint32 ndx)
947 {
948 const DeviceInterface& vk = m_context.getDeviceInterface();
949 const VkDevice vkDevice = m_context.getDevice();
950
951 // Create descriptor set layout
952 DescriptorSetLayoutBuilder descLayoutBuilder;
953 for (deUint32 bindingNdx = 0u; bindingNdx < 2u; bindingNdx++)
954 descLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
955 m_descriptorSetLayout[ndx] = descLayoutBuilder.build(vk, vkDevice);
956 }
957
buildShader(deUint32 ndx)958 void ComputeCacheTestInstance::buildShader (deUint32 ndx)
959 {
960 const DeviceInterface& vk = m_context.getDeviceInterface();
961 const VkDevice vkDevice = m_context.getDevice();
962
963 std::string shader_name("basic_compute_");
964
965 shader_name += (ndx == PIPELINE_CACHE_NDX_DERIVATIVE) ? "2" : "1";
966
967 // Create compute shader
968 VkShaderModuleCreateInfo shaderModuleCreateInfo =
969 {
970 VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // VkStructureType sType;
971 DE_NULL, // const void* pNext;
972 0u, // VkShaderModuleCreateFlags flags;
973 m_context.getBinaryCollection().get(shader_name).getSize(), // deUintptr codeSize;
974 (deUint32*)m_context.getBinaryCollection().get(shader_name).getBinary(), // const deUint32* pCode;
975 };
976 m_computeShaderModule[ndx] = createShaderModule(vk, vkDevice, &shaderModuleCreateInfo);
977 }
978
buildPipeline(const CacheTestParam * param,deUint32 ndx)979 void ComputeCacheTestInstance::buildPipeline (const CacheTestParam* param, deUint32 ndx)
980 {
981 const DeviceInterface& vk = m_context.getDeviceInterface();
982 const VkDevice vkDevice = m_context.getDevice();
983 const VkBool32 zeroOutFeedbackCount = param->isZeroOutFeedbackCount();
984
985 deMemset(&m_pipelineCreationFeedback[ndx], 0, sizeof(VkPipelineCreationFeedbackEXT));
986 deMemset(&m_pipelineStageCreationFeedback[ndx], 0, sizeof(VkPipelineCreationFeedbackEXT));
987
988 const VkPipelineCreationFeedbackCreateInfoEXT pipelineCreationFeedbackCreateInfo =
989 {
990 VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT, // VkStructureType sType;
991 DE_NULL, // const void * pNext;
992 &m_pipelineCreationFeedback[ndx], // VkPipelineCreationFeedbackEXT* pPipelineCreationFeedback;
993 zeroOutFeedbackCount ? 0u : 1u, // deUint32 pipelineStageCreationFeedbackCount;
994 &m_pipelineStageCreationFeedback[ndx] // VkPipelineCreationFeedbackEXT* pPipelineStageCreationFeedbacks;
995 };
996
997 // Create compute pipeline layout
998 const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
999 {
1000 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1001 DE_NULL, // const void* pNext;
1002 0u, // VkPipelineLayoutCreateFlags flags;
1003 1u, // deUint32 setLayoutCount;
1004 &m_descriptorSetLayout[ndx].get(), // const VkDescriptorSetLayout* pSetLayouts;
1005 0u, // deUint32 pushConstantRangeCount;
1006 DE_NULL, // const VkPushConstantRange* pPushConstantRanges;
1007 };
1008
1009 m_pipelineLayout[ndx] = createPipelineLayout(vk, vkDevice, &pipelineLayoutCreateInfo);
1010
1011 const VkPipelineShaderStageCreateInfo stageCreateInfo =
1012 {
1013 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1014 DE_NULL, // const void* pNext;
1015 0u, // VkPipelineShaderStageCreateFlags flags;
1016 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
1017 *m_computeShaderModule[ndx], // VkShaderModule module;
1018 "main", // const char* pName;
1019 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
1020 };
1021
1022 VkComputePipelineCreateInfo pipelineCreateInfo =
1023 {
1024 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
1025 &pipelineCreationFeedbackCreateInfo, // const void* pNext;
1026 0u, // VkPipelineCreateFlags flags;
1027 stageCreateInfo, // VkPipelineShaderStageCreateInfo stage;
1028 *m_pipelineLayout[ndx], // VkPipelineLayout layout;
1029 (VkPipeline)0, // VkPipeline basePipelineHandle;
1030 0u, // deInt32 basePipelineIndex;
1031 };
1032
1033 if (ndx != PIPELINE_CACHE_NDX_DERIVATIVE)
1034 {
1035 pipelineCreateInfo.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
1036 }
1037
1038 if (ndx == PIPELINE_CACHE_NDX_DERIVATIVE)
1039 {
1040 pipelineCreateInfo.flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT;
1041 pipelineCreateInfo.basePipelineHandle = m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE];
1042 pipelineCreateInfo.basePipelineIndex = -1;
1043 }
1044
1045 if (ndx == PIPELINE_CACHE_NDX_CACHED && !param->isDelayedDestroy())
1046 {
1047 // Destroy the NO_CACHE pipeline to check that the cached one really hits cache,
1048 // except for the case where we're testing cache hit of a pipeline still active.
1049 vk.destroyPipeline(vkDevice, m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE], DE_NULL);
1050 }
1051
1052 vk.createComputePipelines(vkDevice, *m_cache, 1u, &pipelineCreateInfo, DE_NULL, &m_pipeline[ndx]);
1053
1054 if (ndx != PIPELINE_CACHE_NDX_NO_CACHE)
1055 {
1056 // Destroy the pipeline as soon as it is created, except the NO_CACHE because
1057 // it is needed as a base pipeline for the derivative case.
1058 vk.destroyPipeline(vkDevice, m_pipeline[ndx], DE_NULL);
1059
1060 if (ndx == PIPELINE_CACHE_NDX_CACHED && param->isDelayedDestroy())
1061 {
1062 // Destroy the pipeline we didn't destroy earlier for the isDelayedDestroy case.
1063 vk.destroyPipeline(vkDevice, m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE], DE_NULL);
1064 }
1065 }
1066 }
1067
ComputeCacheTestInstance(Context & context,const CacheTestParam * param)1068 ComputeCacheTestInstance::ComputeCacheTestInstance (Context& context,
1069 const CacheTestParam* param)
1070 : CacheTestInstance (context, param)
1071 {
1072 for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
1073 {
1074 buildDescriptorSets(ndx);
1075 buildShader(ndx);
1076 buildPipeline(param, ndx);
1077 }
1078 }
1079
~ComputeCacheTestInstance(void)1080 ComputeCacheTestInstance::~ComputeCacheTestInstance (void)
1081 {
1082 }
1083
verifyTestResult(void)1084 tcu::TestStatus ComputeCacheTestInstance::verifyTestResult (void)
1085 {
1086 tcu::TestLog &log = m_context.getTestContext().getLog();
1087 deBool durationZeroWarning = DE_FALSE;
1088 deBool cachedPipelineWarning = DE_FALSE;
1089
1090 for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
1091 {
1092 std::ostringstream message;
1093 message << getCaseStr(ndx);
1094
1095 // No need to check per stage status as it is compute pipeline (only one stage) and Vulkan spec mentions that:
1096 // "One common scenario for an implementation to skip per-stage feedback is when
1097 // VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT is set in pPipelineCreationFeedback."
1098 //
1099 // Check first that the no cached pipeline was missed in the pipeline cache
1100
1101 // According to the spec:
1102 // "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
1103 // may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
1104 if (!(m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
1105 {
1106 // According to the spec:
1107 // "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
1108 // must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
1109 if (m_pipelineCreationFeedback[ndx].flags)
1110 {
1111 std::ostringstream errorMsg;
1112 errorMsg << ": Creation feedback is not valid but there are other flags written";
1113 return tcu::TestStatus::fail(errorMsg.str());
1114 }
1115 message << "\t\t Pipeline Creation Feedback data is not valid\n";
1116 }
1117 else
1118 {
1119 if (m_param->isCacheDisabled() && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1120 {
1121 message << ": feedback indicates pipeline hit cache when it shouldn't";
1122 return tcu::TestStatus::fail(message.str());
1123 }
1124
1125 if (ndx == PIPELINE_CACHE_NDX_NO_CACHE && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1126 {
1127 message << ": hit the cache when it shouldn't";
1128 return tcu::TestStatus::fail(message.str());
1129 }
1130
1131 if (!(ndx == PIPELINE_CACHE_NDX_DERIVATIVE && !m_param->isCacheDisabled()) && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT)
1132 {
1133 message << ": feedback indicates base pipeline acceleration when it shouldn't";
1134 return tcu::TestStatus::fail(message.str());
1135 }
1136
1137 if (ndx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
1138 {
1139 message << "\nWarning: Cached pipeline case did not hit the cache";
1140 cachedPipelineWarning = DE_TRUE;
1141 }
1142
1143 if (m_pipelineCreationFeedback[ndx].duration == 0)
1144 {
1145 message << "\nWarning: Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds\n";
1146 durationZeroWarning = DE_TRUE;
1147 }
1148
1149 message << "\n";
1150
1151 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";
1152 message << "\t\t Base Pipeline Acceleration ? \t" << (m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ? "yes" : "no") << "\n";
1153 message << "\t\t Duration (ns): \t\t" << m_pipelineCreationFeedback[ndx].duration << "\n";
1154
1155 message << "\t Compute Stage\n";
1156 }
1157
1158 // According to the spec:
1159 // "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
1160 // may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
1161 if (!(m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
1162 {
1163 // According to the spec:
1164 // "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
1165 // must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
1166 if (m_pipelineStageCreationFeedback[ndx].flags)
1167 {
1168 std::ostringstream errorMsg;
1169 errorMsg << getCaseStr(ndx) << ": Creation feedback is not valid for compute stage but there are other flags written";
1170 return tcu::TestStatus::fail(errorMsg.str());
1171 }
1172 message << "\t\t Pipeline Creation Feedback data is not valid\n";
1173 }
1174 else
1175 {
1176 if (m_param->isCacheDisabled() && m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1177 {
1178 std::ostringstream errorMsg;
1179 errorMsg << getCaseStr(ndx) << ": feedback indicates pipeline compute stage hit cache when it shouldn't";
1180 return tcu::TestStatus::fail(errorMsg.str());
1181 }
1182
1183 if (ndx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
1184 {
1185 message << "Warning: pipeline stage did not hit the cache\n";
1186 cachedPipelineWarning = DE_TRUE;
1187 }
1188 if (cachedPipelineWarning && m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1189 {
1190 // We only set the warning when the pipeline nor the pipeline stages hit the cache. If any of them did, them disable the warning.
1191 cachedPipelineWarning = DE_FALSE;
1192 }
1193
1194 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";
1195 message << "\t\t Base Pipeline Acceleration ? \t" << (m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ? "yes" : "no") << "\n";
1196 message << "\t\t Duration (ns): \t\t" << m_pipelineStageCreationFeedback[ndx].duration << "\n";
1197 }
1198
1199 log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
1200 }
1201
1202 if (cachedPipelineWarning)
1203 {
1204 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Cached pipeline or stage did not hit the cache");
1205 }
1206 if (durationZeroWarning)
1207 {
1208 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds");
1209 }
1210 return tcu::TestStatus::pass("Pass");
1211 }
1212 } // anonymous
1213
createCreationFeedbackTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1214 tcu::TestCaseGroup* createCreationFeedbackTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
1215 {
1216 de::MovePtr<tcu::TestCaseGroup> cacheTests (new tcu::TestCaseGroup(testCtx, "creation_feedback", "pipeline creation feedback tests"));
1217
1218 // Graphics Pipeline Tests
1219 {
1220 de::MovePtr<tcu::TestCaseGroup> graphicsTests (new tcu::TestCaseGroup(testCtx, "graphics_tests", "Test pipeline creation feedback with graphics pipeline."));
1221
1222 const VkShaderStageFlags vertFragStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
1223 const VkShaderStageFlags vertGeomFragStages = vertFragStages | VK_SHADER_STAGE_GEOMETRY_BIT;
1224 const VkShaderStageFlags vertTessFragStages = vertFragStages | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
1225
1226 const std::vector<CacheTestParam> testParams
1227 {
1228 { pipelineConstructionType, vertFragStages, DE_FALSE, DE_FALSE },
1229 { pipelineConstructionType, vertGeomFragStages, DE_FALSE, DE_FALSE },
1230 { pipelineConstructionType, vertTessFragStages, DE_FALSE, DE_FALSE },
1231 { pipelineConstructionType, vertFragStages, DE_TRUE, DE_FALSE },
1232 { pipelineConstructionType, vertFragStages, DE_TRUE, DE_FALSE, DE_TRUE },
1233 { pipelineConstructionType, vertGeomFragStages, DE_TRUE, DE_FALSE },
1234 { pipelineConstructionType, vertTessFragStages, DE_TRUE, DE_FALSE },
1235 { pipelineConstructionType, vertFragStages, DE_FALSE, DE_TRUE },
1236 { pipelineConstructionType, vertGeomFragStages, DE_FALSE, DE_TRUE },
1237 { pipelineConstructionType, vertTessFragStages, DE_FALSE, DE_TRUE },
1238 };
1239
1240 for (auto& param : testParams)
1241 graphicsTests->addChild(newTestCase<GraphicsCacheTest>(testCtx, ¶m));
1242
1243 cacheTests->addChild(graphicsTests.release());
1244 }
1245
1246 // Compute Pipeline Tests - don't repeat those tests for graphics pipeline library
1247 if (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
1248 {
1249 de::MovePtr<tcu::TestCaseGroup> computeTests (new tcu::TestCaseGroup(testCtx, "compute_tests", "Test pipeline creation feedback with compute pipeline."));
1250
1251 const std::vector<CacheTestParam> testParams
1252 {
1253 { pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_FALSE, DE_FALSE },
1254 { pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_TRUE, DE_FALSE },
1255 { pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, DE_FALSE, DE_TRUE },
1256 };
1257
1258 for (auto& param : testParams)
1259 computeTests->addChild(newTestCase<ComputeCacheTest>(testCtx, ¶m));
1260
1261 cacheTests->addChild(computeTests.release());
1262 }
1263
1264 return cacheTests.release();
1265 }
1266
1267 } // pipeline
1268
1269 } // vkt
1270