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