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 "vkTypeUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "tcuTestLog.hpp"
35
36 #include <sstream>
37 #include <vector>
38
39 namespace vkt
40 {
41 namespace pipeline
42 {
43
44 using namespace vk;
45
46 namespace
47 {
48 enum
49 {
50 VK_MAX_SHADER_STAGES = 6,
51 };
52
53 enum
54 {
55 PIPELINE_CACHE_NDX_NO_CACHE = 0,
56 PIPELINE_CACHE_NDX_DERIVATIVE = 1,
57 PIPELINE_CACHE_NDX_CACHED = 2,
58 PIPELINE_CACHE_NDX_COUNT,
59 };
60
61 // helper functions
62
getShaderFlagStr(const VkShaderStageFlagBits shader,bool isDescription)63 std::string getShaderFlagStr (const VkShaderStageFlagBits shader,
64 bool isDescription)
65 {
66 std::ostringstream desc;
67 switch(shader)
68 {
69 case VK_SHADER_STAGE_VERTEX_BIT:
70 {
71 desc << ((isDescription) ? "vertex stage" : "vertex_stage");
72 break;
73 }
74 case VK_SHADER_STAGE_FRAGMENT_BIT:
75 {
76 desc << ((isDescription) ? "fragment stage" : "fragment_stage");
77 break;
78 }
79 case VK_SHADER_STAGE_GEOMETRY_BIT:
80 {
81 desc << ((isDescription) ? "geometry stage" : "geometry_stage");
82 break;
83 }
84 case VK_SHADER_STAGE_COMPUTE_BIT:
85 {
86 desc << ((isDescription) ? "compute stage" : "compute_stage");
87 break;
88 }
89 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
90 {
91 desc << ((isDescription) ? "tessellation control stage" : "tessellation_control_stage");
92 break;
93 }
94 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
95 {
96 desc << ((isDescription) ? "tessellation evaluation stage" : "tessellation_evaluation_stage");
97 break;
98 }
99 default:
100 desc << "unknown shader stage!";
101 DE_FATAL("Unknown shader Stage!");
102 break;
103 }
104
105 return desc.str();
106 }
107
getCaseStr(const deUint32 ndx)108 std::string getCaseStr (const deUint32 ndx)
109 {
110 std::ostringstream desc;
111 switch(ndx)
112 {
113 case PIPELINE_CACHE_NDX_NO_CACHE:
114 {
115 desc << "No cached pipeline";
116 break;
117 }
118 case PIPELINE_CACHE_NDX_CACHED:
119 {
120 desc << "Cached pipeline";
121 break;
122 }
123 case PIPELINE_CACHE_NDX_DERIVATIVE:
124 {
125 desc << "Pipeline derivative";
126 break;
127 }
128 default:
129 desc << "Unknown case";
130 DE_FATAL("Unknown case!");
131 break;
132 }
133
134 return desc.str();
135 }
136
137 // helper classes
138 class CacheTestParam
139 {
140 public:
141 CacheTestParam (const VkShaderStageFlagBits* shaders,
142 deUint32 count,
143 deBool noCache,
144 deBool delayedDestroy);
145 virtual ~CacheTestParam (void);
146 virtual const std::string generateTestName (void) const;
147 virtual const std::string generateTestDescription (void) const;
getShaderFlag(deUint32 ndx) const148 VkShaderStageFlagBits getShaderFlag (deUint32 ndx) const { return m_shaders[ndx]; }
getShaderCount(void) const149 deUint32 getShaderCount (void) const { return (deUint32)m_shaderCount; }
isCacheDisabled(void) const150 deBool isCacheDisabled (void) const { return m_noCache; }
isDelayedDestroy(void) const151 deBool isDelayedDestroy (void) const { return m_delayedDestroy; }
152
153 protected:
154 VkShaderStageFlagBits m_shaders[VK_MAX_SHADER_STAGES];
155 size_t m_shaderCount;
156 bool m_noCache;
157 bool m_delayedDestroy;
158 };
159
CacheTestParam(const VkShaderStageFlagBits * shaders,deUint32 count,deBool noCache,deBool delayedDestroy)160 CacheTestParam::CacheTestParam (const VkShaderStageFlagBits* shaders, deUint32 count, deBool noCache, deBool delayedDestroy)
161 {
162 DE_ASSERT(count <= VK_MAX_SHADER_STAGES);
163 for (deUint32 ndx = 0; ndx < count; ndx++)
164 m_shaders[ndx] = shaders[ndx];
165 m_shaderCount = count;
166 m_noCache = noCache;
167 m_delayedDestroy = delayedDestroy;
168 }
169
~CacheTestParam(void)170 CacheTestParam::~CacheTestParam (void)
171 {
172 }
173
generateTestName(void) const174 const std::string CacheTestParam::generateTestName (void) const
175 {
176 std::string result(getShaderFlagStr(m_shaders[0], false));
177 std::string cacheString [] = { "", "_no_cache" };
178 std::string delayedDestroyString [] = { "", "_delayed_destroy" };
179
180 for(deUint32 ndx = 1; ndx < m_shaderCount; ndx++)
181 result += '_' + getShaderFlagStr(m_shaders[ndx], false) + cacheString[m_noCache ? 1 : 0] + delayedDestroyString[m_delayedDestroy ? 1 : 0];
182
183 if (m_shaderCount == 1)
184 result += cacheString[m_noCache ? 1 : 0] + delayedDestroyString[m_delayedDestroy ? 1 : 0];
185
186 return result;
187 }
188
generateTestDescription(void) const189 const std::string CacheTestParam::generateTestDescription (void) const
190 {
191 std::string result("Get pipeline creation feedback with " + getShaderFlagStr(m_shaders[0], true));
192 if (m_noCache)
193 result += " with no cache";
194 if (m_delayedDestroy)
195 result += " with delayed destroy";
196
197 for(deUint32 ndx = 1; ndx < m_shaderCount; ndx++)
198 result += ' ' + getShaderFlagStr(m_shaders[ndx], true);
199
200 return result;
201 }
202
203 class SimpleGraphicsPipelineBuilder
204 {
205 public:
206 SimpleGraphicsPipelineBuilder (Context& context);
~SimpleGraphicsPipelineBuilder(void)207 ~SimpleGraphicsPipelineBuilder (void) { }
208 void bindShaderStage (VkShaderStageFlagBits stage,
209 const char* sourceName,
210 const char* entryName);
211 void enableTessellationStage (deUint32 patchControlPoints);
212 VkPipeline buildPipeline (tcu::UVec2 renderSize,
213 VkRenderPass renderPass,
214 VkPipelineCache cache,
215 VkPipelineLayout pipelineLayout,
216 VkPipelineCreationFeedbackEXT *pipelineCreationFeedback,
217 VkPipelineCreationFeedbackEXT *pipelineStageCreationFeedbacks,
218 VkPipeline basePipelineHandle);
219 void resetBuilder (void);
220
221 protected:
222 Context& m_context;
223
224 Move<VkShaderModule> m_shaderModules[VK_MAX_SHADER_STAGES];
225 deUint32 m_shaderStageCount;
226 VkPipelineShaderStageCreateInfo m_shaderStageInfo[VK_MAX_SHADER_STAGES];
227
228 deUint32 m_patchControlPoints;
229 };
230
SimpleGraphicsPipelineBuilder(Context & context)231 SimpleGraphicsPipelineBuilder::SimpleGraphicsPipelineBuilder (Context& context)
232 : m_context(context)
233 {
234 m_patchControlPoints = 0;
235 m_shaderStageCount = 0;
236 }
237
resetBuilder(void)238 void SimpleGraphicsPipelineBuilder::resetBuilder (void)
239 {
240 m_shaderStageCount = 0;
241 }
242
bindShaderStage(VkShaderStageFlagBits stage,const char * sourceName,const char * entryName)243 void SimpleGraphicsPipelineBuilder::bindShaderStage (VkShaderStageFlagBits stage,
244 const char* sourceName,
245 const char* entryName)
246 {
247 const DeviceInterface& vk = m_context.getDeviceInterface();
248 const VkDevice vkDevice = m_context.getDevice();
249
250 // Create shader module
251 deUint32* code = (deUint32*)m_context.getBinaryCollection().get(sourceName).getBinary();
252 deUint32 codeSize = (deUint32)m_context.getBinaryCollection().get(sourceName).getSize();
253
254 const VkShaderModuleCreateInfo moduleCreateInfo =
255 {
256 VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // VkStructureType sType;
257 DE_NULL, // const void* pNext;
258 0u, // VkShaderModuleCreateFlags flags;
259 codeSize, // deUintptr codeSize;
260 code, // const deUint32* pCode;
261 };
262
263 m_shaderModules[m_shaderStageCount] = createShaderModule(vk, vkDevice, &moduleCreateInfo);
264
265 // Prepare shader stage info
266 m_shaderStageInfo[m_shaderStageCount].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
267 m_shaderStageInfo[m_shaderStageCount].pNext = DE_NULL;
268 m_shaderStageInfo[m_shaderStageCount].flags = 0u;
269 m_shaderStageInfo[m_shaderStageCount].stage = stage;
270 m_shaderStageInfo[m_shaderStageCount].module = *m_shaderModules[m_shaderStageCount];
271 m_shaderStageInfo[m_shaderStageCount].pName = entryName;
272 m_shaderStageInfo[m_shaderStageCount].pSpecializationInfo = DE_NULL;
273
274 m_shaderStageCount++;
275 }
276
buildPipeline(tcu::UVec2 renderSize,VkRenderPass renderPass,VkPipelineCache cache,VkPipelineLayout pipelineLayout,VkPipelineCreationFeedbackEXT * pipelineCreationFeedback,VkPipelineCreationFeedbackEXT * pipelineStageCreationFeedbacks,VkPipeline basePipelineHandle)277 VkPipeline SimpleGraphicsPipelineBuilder::buildPipeline (tcu::UVec2 renderSize, VkRenderPass renderPass, VkPipelineCache cache,
278 VkPipelineLayout pipelineLayout, VkPipelineCreationFeedbackEXT *pipelineCreationFeedback,
279 VkPipelineCreationFeedbackEXT *pipelineStageCreationFeedbacks, VkPipeline basePipelineHandle)
280 {
281 const DeviceInterface& vk = m_context.getDeviceInterface();
282 const VkDevice vkDevice = m_context.getDevice();
283
284 // Create pipeline
285 const VkVertexInputBindingDescription vertexInputBindingDescription =
286 {
287 0u, // deUint32 binding;
288 sizeof(Vertex4RGBA), // deUint32 strideInBytes;
289 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
290 };
291
292 const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
293 {
294 {
295 0u, // deUint32 location;
296 0u, // deUint32 binding;
297 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
298 0u // deUint32 offsetInBytes;
299 },
300 {
301 1u, // deUint32 location;
302 0u, // deUint32 binding;
303 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
304 DE_OFFSET_OF(Vertex4RGBA, color), // deUint32 offsetInBytes;
305 }
306 };
307
308 const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
309 {
310 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
311 DE_NULL, // const void* pNext;
312 0u, // VkPipelineVertexInputStateCreateFlags flags;
313 1u, // deUint32 vertexBindingDescriptionCount;
314 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
315 2u, // deUint32 vertexAttributeDescriptionCount;
316 vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
317 };
318
319 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
320 {
321 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
322 DE_NULL, // const void* pNext;
323 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
324 (m_patchControlPoints == 0 ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
325 : VK_PRIMITIVE_TOPOLOGY_PATCH_LIST), // VkPrimitiveTopology topology;
326 VK_FALSE, // VkBool32 primitiveRestartEnable;
327 };
328
329 const VkViewport viewport = makeViewport(renderSize);
330 const VkRect2D scissor = makeRect2D(renderSize);
331
332 const VkPipelineViewportStateCreateInfo viewportStateParams =
333 {
334 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
335 DE_NULL, // const void* pNext;
336 0u, // VkPipelineViewportStateCreateFlags flags;
337 1u, // deUint32 viewportCount;
338 &viewport, // const VkViewport* pViewports;
339 1u, // deUint32 scissorCount;
340 &scissor // const VkRect2D* pScissors;
341 };
342
343 const VkPipelineRasterizationStateCreateInfo rasterStateParams =
344 {
345 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
346 DE_NULL, // const void* pNext;
347 0u, // VkPipelineRasterizationStateCreateFlags flags;
348 VK_FALSE, // VkBool32 depthClampEnable;
349 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
350 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
351 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
352 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
353 VK_FALSE, // VkBool32 depthBiasEnable;
354 0.0f, // float depthBiasConstantFactor;
355 0.0f, // float depthBiasClamp;
356 0.0f, // float depthBiasSlopeFactor;
357 1.0f, // float lineWidth;
358 };
359
360 const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
361 {
362 VK_FALSE, // VkBool32 blendEnable;
363 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
364 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
365 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
366 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
367 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
368 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
369 VK_COLOR_COMPONENT_R_BIT |
370 VK_COLOR_COMPONENT_G_BIT |
371 VK_COLOR_COMPONENT_B_BIT |
372 VK_COLOR_COMPONENT_A_BIT // VkColorComponentFlags colorWriteMask;
373 };
374
375 const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
376 {
377 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
378 DE_NULL, // const void* pNext;
379 0u, // VkPipelineColorBlendStateCreateFlags flags;
380 VK_FALSE, // VkBool32 logicOpEnable;
381 VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
382 1u, // deUint32 attachmentCount;
383 &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
384 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConst[4];
385 };
386
387 const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
388 {
389 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
390 DE_NULL, // const void* pNext;
391 0u, // VkPipelineMultisampleStateCreateFlags flags;
392 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
393 VK_FALSE, // VkBool32 sampleShadingEnable;
394 0.0f, // float minSampleShading;
395 DE_NULL, // const VkSampleMask* pSampleMask;
396 VK_FALSE, // VkBool32 alphaToCoverageEnable;
397 VK_FALSE, // VkBool32 alphaToOneEnable;
398 };
399
400 VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
401 {
402 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
403 DE_NULL, // const void* pNext;
404 0u, // VkPipelineDepthStencilStateCreateFlags flags;
405 VK_TRUE, // VkBool32 depthTestEnable;
406 VK_TRUE, // VkBool32 depthWriteEnable;
407 VK_COMPARE_OP_LESS_OR_EQUAL, // VkCompareOp depthCompareOp;
408 VK_FALSE, // VkBool32 depthBoundsTestEnable;
409 VK_FALSE, // VkBool32 stencilTestEnable;
410 // VkStencilOpState front;
411 {
412 VK_STENCIL_OP_KEEP, // VkStencilOp failOp;
413 VK_STENCIL_OP_KEEP, // VkStencilOp passOp;
414 VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp;
415 VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
416 0u, // deUint32 compareMask;
417 0u, // deUint32 writeMask;
418 0u, // deUint32 reference;
419 },
420 // VkStencilOpState back;
421 {
422 VK_STENCIL_OP_KEEP, // VkStencilOp failOp;
423 VK_STENCIL_OP_KEEP, // VkStencilOp passOp;
424 VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp;
425 VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
426 0u, // deUint32 compareMask;
427 0u, // deUint32 writeMask;
428 0u, // deUint32 reference;
429 },
430 0.0f, // float minDepthBounds;
431 1.0f, // float maxDepthBounds;
432 };
433
434 const VkPipelineTessellationStateCreateInfo tessStateCreateInfo =
435 {
436 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType;
437 DE_NULL, // const void* pNext;
438 0u, // VkPipelineTesselationStateCreateFlags flags;
439 m_patchControlPoints, // deUint32 patchControlPoints;
440 };
441 const VkPipelineTessellationStateCreateInfo* pTessCreateInfo = (m_patchControlPoints > 0)
442 ? &tessStateCreateInfo
443 : DE_NULL;
444
445 const VkPipelineCreationFeedbackCreateInfoEXT pipelineCreationFeedbackCreateInfo =
446 {
447 VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT, // VkStructureType sType;
448 DE_NULL, // const void* pNext;
449 pipelineCreationFeedback, // VkPipelineCreationFeedbackEXT* pPipelineCreationFeedback;
450 m_shaderStageCount, // deUint32 pipelineStageCreationFeedbackCount;
451 pipelineStageCreationFeedbacks // VkPipelineCreationFeedbackEXT* pPipelineStageCreationFeedbacks;
452 };
453
454 deUint32 flagsCreateInfo = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
455 if (basePipelineHandle != DE_NULL)
456 {
457 flagsCreateInfo = VK_PIPELINE_CREATE_DERIVATIVE_BIT;
458 }
459
460 const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
461 {
462 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
463 &pipelineCreationFeedbackCreateInfo, // const void* pNext;
464 flagsCreateInfo, // VkPipelineCreateFlags flags;
465 m_shaderStageCount, // deUint32 stageCount;
466 m_shaderStageInfo, // const VkPipelineShaderStageCreateInfo* pStages;
467 &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
468 &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
469 pTessCreateInfo, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
470 &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState;
471 &rasterStateParams, // const VkPipelineRasterizationStateCreateInfo* pRasterState;
472 &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
473 &depthStencilStateParams, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
474 &colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
475 (const VkPipelineDynamicStateCreateInfo*)DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
476 pipelineLayout, // VkPipelineLayout layout;
477 renderPass, // VkRenderPass renderPass;
478 0u, // deUint32 subpass;
479 basePipelineHandle, // VkPipeline basePipelineHandle;
480 basePipelineHandle != DE_NULL ? -1 : 0, // deInt32 basePipelineIndex;
481 };
482 VkPipeline pipeline;
483 vk.createGraphicsPipelines(vkDevice, cache, 1u, &graphicsPipelineParams, DE_NULL, &pipeline);
484 return pipeline;
485 }
486
enableTessellationStage(deUint32 patchControlPoints)487 void SimpleGraphicsPipelineBuilder::enableTessellationStage (deUint32 patchControlPoints)
488 {
489 m_patchControlPoints = patchControlPoints;
490 }
491
492 template <class Test>
newTestCase(tcu::TestContext & testContext,const CacheTestParam * testParam)493 vkt::TestCase* newTestCase (tcu::TestContext& testContext,
494 const CacheTestParam* testParam)
495 {
496 return new Test(testContext,
497 testParam->generateTestName().c_str(),
498 testParam->generateTestDescription().c_str(),
499 testParam);
500 }
501
502 // Test Classes
503 class CacheTest : public vkt::TestCase
504 {
505 public:
CacheTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,const CacheTestParam * param)506 CacheTest(tcu::TestContext& testContext,
507 const std::string& name,
508 const std::string& description,
509 const CacheTestParam* param)
510 : vkt::TestCase (testContext, name, description)
511 , m_param (*param)
512 { }
~CacheTest(void)513 virtual ~CacheTest (void) { }
514 protected:
515 const CacheTestParam m_param;
516 };
517
518 class CacheTestInstance : public vkt::TestInstance
519 {
520 public:
521 CacheTestInstance (Context& context,
522 const CacheTestParam* param);
523 virtual ~CacheTestInstance (void);
524 virtual tcu::TestStatus iterate (void);
525 protected:
526 virtual tcu::TestStatus verifyTestResult (void) = 0;
527 protected:
528 const CacheTestParam* m_param;
529
530 Move<VkPipelineCache> m_cache;
531 deBool m_extensions;
532 };
533
CacheTestInstance(Context & context,const CacheTestParam * param)534 CacheTestInstance::CacheTestInstance (Context& context,
535 const CacheTestParam* param)
536 : TestInstance (context)
537 , m_param (param)
538 , m_extensions (m_context.requireDeviceFunctionality("VK_EXT_pipeline_creation_feedback"))
539 {
540 const DeviceInterface& vk = m_context.getDeviceInterface();
541 const VkDevice vkDevice = m_context.getDevice();
542
543 if (m_param->isCacheDisabled() == DE_FALSE)
544 {
545 const VkPipelineCacheCreateInfo pipelineCacheCreateInfo =
546 {
547 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
548 DE_NULL, // const void* pNext;
549 0u, // VkPipelineCacheCreateFlags flags;
550 0u, // deUintptr initialDataSize;
551 DE_NULL, // const void* pInitialData;
552 };
553
554 m_cache = createPipelineCache(vk, vkDevice, &pipelineCacheCreateInfo);
555 }
556 }
557
~CacheTestInstance(void)558 CacheTestInstance::~CacheTestInstance (void)
559 {
560 }
561
iterate(void)562 tcu::TestStatus CacheTestInstance::iterate (void)
563 {
564 return verifyTestResult();
565 }
566
567 class GraphicsCacheTest : public CacheTest
568 {
569 public:
GraphicsCacheTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,const CacheTestParam * param)570 GraphicsCacheTest (tcu::TestContext& testContext,
571 const std::string& name,
572 const std::string& description,
573 const CacheTestParam* param)
574 : CacheTest (testContext, name, description, param)
575 { }
~GraphicsCacheTest(void)576 virtual ~GraphicsCacheTest (void) { }
577 virtual void initPrograms (SourceCollections& programCollection) const;
578 virtual void checkSupport (Context& context) const;
579 virtual TestInstance* createInstance (Context& context) const;
580 };
581
582 class GraphicsCacheTestInstance : public CacheTestInstance
583 {
584 public:
585 GraphicsCacheTestInstance (Context& context,
586 const CacheTestParam* param);
587 virtual ~GraphicsCacheTestInstance (void);
588 protected:
589 virtual tcu::TestStatus verifyTestResult (void);
590
591 protected:
592 const tcu::UVec2 m_renderSize;
593 const VkFormat m_colorFormat;
594 const VkFormat m_depthFormat;
595 Move<VkPipelineLayout> m_pipelineLayout;
596
597 SimpleGraphicsPipelineBuilder m_pipelineBuilder;
598 SimpleGraphicsPipelineBuilder m_missPipelineBuilder;
599 Move<VkRenderPass> m_renderPass;
600
601 VkPipeline m_pipeline[PIPELINE_CACHE_NDX_COUNT];
602 VkPipelineCreationFeedbackEXT m_pipelineCreationFeedback[PIPELINE_CACHE_NDX_COUNT];
603 VkPipelineCreationFeedbackEXT m_pipelineStageCreationFeedbacks[PIPELINE_CACHE_NDX_COUNT * VK_MAX_SHADER_STAGES];
604 };
605
initPrograms(SourceCollections & programCollection) const606 void GraphicsCacheTest::initPrograms (SourceCollections& programCollection) const
607 {
608 for (deUint32 shaderNdx = 0; shaderNdx < m_param.getShaderCount(); shaderNdx++)
609 {
610 switch(m_param.getShaderFlag(shaderNdx))
611 {
612 case VK_SHADER_STAGE_VERTEX_BIT:
613 programCollection.glslSources.add("color_vert_1") << glu::VertexSource(
614 "#version 310 es\n"
615 "layout(location = 0) in vec4 position;\n"
616 "layout(location = 1) in vec4 color;\n"
617 "layout(location = 0) out highp vec4 vtxColor;\n"
618 "void main (void)\n"
619 "{\n"
620 " gl_Position = position;\n"
621 " vtxColor = color;\n"
622 "}\n");
623 programCollection.glslSources.add("color_vert_2") << glu::VertexSource(
624 "#version 310 es\n"
625 "layout(location = 0) in vec4 position;\n"
626 "layout(location = 1) in vec4 color;\n"
627 "layout(location = 0) out highp vec4 vtxColor;\n"
628 "void main (void)\n"
629 "{\n"
630 " gl_Position = position;\n"
631 " gl_PointSize = 1.0f;\n"
632 " vtxColor = color + vec4(0.1, 0.2, 0.3, 0.0);\n"
633 "}\n");
634 break;
635 case VK_SHADER_STAGE_FRAGMENT_BIT:
636 programCollection.glslSources.add("color_frag") << glu::FragmentSource(
637 "#version 310 es\n"
638 "layout(location = 0) in highp vec4 vtxColor;\n"
639 "layout(location = 0) out highp vec4 fragColor;\n"
640 "void main (void)\n"
641 "{\n"
642 " fragColor = vtxColor;\n"
643 "}\n");
644 break;
645
646 case VK_SHADER_STAGE_GEOMETRY_BIT:
647 programCollection.glslSources.add("dummy_geo") << glu::GeometrySource(
648 "#version 450 \n"
649 "layout(triangles) in;\n"
650 "layout(triangle_strip, max_vertices = 3) out;\n"
651 "layout(location = 0) in highp vec4 in_vtxColor[];\n"
652 "layout(location = 0) out highp vec4 vtxColor;\n"
653 "out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
654 "in gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_in[];\n"
655 "void main (void)\n"
656 "{\n"
657 " for(int ndx=0; ndx<3; ndx++)\n"
658 " {\n"
659 " gl_Position = gl_in[ndx].gl_Position;\n"
660 " gl_PointSize = gl_in[ndx].gl_PointSize;\n"
661 " vtxColor = in_vtxColor[ndx];\n"
662 " EmitVertex();\n"
663 " }\n"
664 " EndPrimitive();\n"
665 "}\n");
666 break;
667
668 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
669 programCollection.glslSources.add("basic_tcs") << glu::TessellationControlSource(
670 "#version 450 \n"
671 "layout(vertices = 3) out;\n"
672 "layout(location = 0) in highp vec4 color[];\n"
673 "layout(location = 0) out highp vec4 vtxColor[];\n"
674 "out gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_out[3];\n"
675 "in gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_in[gl_MaxPatchVertices];\n"
676 "void main()\n"
677 "{\n"
678 " gl_TessLevelOuter[0] = 4.0;\n"
679 " gl_TessLevelOuter[1] = 4.0;\n"
680 " gl_TessLevelOuter[2] = 4.0;\n"
681 " gl_TessLevelInner[0] = 4.0;\n"
682 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
683 " gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n"
684 " vtxColor[gl_InvocationID] = color[gl_InvocationID];\n"
685 "}\n");
686 break;
687
688 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
689 programCollection.glslSources.add("basic_tes") << glu::TessellationEvaluationSource(
690 "#version 450 \n"
691 "layout(triangles, fractional_even_spacing, ccw) in;\n"
692 "layout(location = 0) in highp vec4 colors[];\n"
693 "layout(location = 0) out highp vec4 vtxColor;\n"
694 "out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
695 "in gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_in[gl_MaxPatchVertices];\n"
696 "void main() \n"
697 "{\n"
698 " float u = gl_TessCoord.x;\n"
699 " float v = gl_TessCoord.y;\n"
700 " float w = gl_TessCoord.z;\n"
701 " vec4 pos = vec4(0);\n"
702 " vec4 color = vec4(0);\n"
703 " pos.xyz += u * gl_in[0].gl_Position.xyz;\n"
704 " color.xyz += u * colors[0].xyz;\n"
705 " pos.xyz += v * gl_in[1].gl_Position.xyz;\n"
706 " color.xyz += v * colors[1].xyz;\n"
707 " pos.xyz += w * gl_in[2].gl_Position.xyz;\n"
708 " color.xyz += w * colors[2].xyz;\n"
709 " pos.w = 1.0;\n"
710 " color.w = 1.0;\n"
711 " gl_Position = pos;\n"
712 " gl_PointSize = gl_in[0].gl_PointSize;"
713 " vtxColor = color;\n"
714 "}\n");
715 break;
716
717 default:
718 DE_FATAL("Unknown Shader Stage!");
719 break;
720 }
721 }
722 }
723
checkSupport(Context & context) const724 void GraphicsCacheTest::checkSupport (Context& context) const
725 {
726 for (deUint32 shaderNdx = 0; shaderNdx < m_param.getShaderCount(); shaderNdx++)
727 {
728 switch(m_param.getShaderFlag(shaderNdx))
729 {
730 case VK_SHADER_STAGE_GEOMETRY_BIT:
731 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
732 break;
733 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
734 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
735 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
736 break;
737 default:
738 break;
739 }
740 }
741 }
742
createInstance(Context & context) const743 TestInstance* GraphicsCacheTest::createInstance (Context& context) const
744 {
745 return new GraphicsCacheTestInstance(context, &m_param);
746 }
747
GraphicsCacheTestInstance(Context & context,const CacheTestParam * param)748 GraphicsCacheTestInstance::GraphicsCacheTestInstance (Context& context,
749 const CacheTestParam* param)
750 : CacheTestInstance (context, param)
751 , m_renderSize (32u, 32u)
752 , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
753 , m_depthFormat (VK_FORMAT_D16_UNORM)
754 , m_pipelineBuilder (context)
755 , m_missPipelineBuilder (context)
756 {
757 const DeviceInterface& vk = m_context.getDeviceInterface();
758 const VkDevice vkDevice = m_context.getDevice();
759
760 // Create pipeline layout
761 {
762 const VkPipelineLayoutCreateInfo pipelineLayoutParams =
763 {
764 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
765 DE_NULL, // const void* pNext;
766 0u, // VkPipelineLayoutCreateFlags flags;
767 0u, // deUint32 setLayoutCount;
768 DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
769 0u, // deUint32 pushConstantRangeCount;
770 DE_NULL // const VkPushConstantRange* pPushConstantRanges;
771 };
772
773 m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
774 }
775
776 // Create render pass
777 m_renderPass = makeRenderPass(vk, vkDevice, m_colorFormat, m_depthFormat);
778
779 // Bind shader stages
780 for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
781 {
782 for (deUint32 shaderNdx = 0; shaderNdx < m_param->getShaderCount(); shaderNdx++)
783 {
784 switch(m_param->getShaderFlag(shaderNdx))
785 {
786 case VK_SHADER_STAGE_VERTEX_BIT:
787 {
788 std::string shader_name("color_vert_");
789 shader_name += (ndx == PIPELINE_CACHE_NDX_DERIVATIVE) ? "2" : "1";
790 m_pipelineBuilder.bindShaderStage(VK_SHADER_STAGE_VERTEX_BIT, shader_name.c_str(), "main");
791 }
792 break;
793 case VK_SHADER_STAGE_FRAGMENT_BIT:
794 m_pipelineBuilder.bindShaderStage(VK_SHADER_STAGE_FRAGMENT_BIT, "color_frag", "main");
795 break;
796 case VK_SHADER_STAGE_GEOMETRY_BIT:
797 m_pipelineBuilder.bindShaderStage(VK_SHADER_STAGE_GEOMETRY_BIT, "dummy_geo", "main");
798 break;
799 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
800 m_pipelineBuilder.bindShaderStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, "basic_tcs", "main");
801 m_pipelineBuilder.enableTessellationStage(3);
802 break;
803 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
804 m_pipelineBuilder.bindShaderStage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, "basic_tes", "main");
805 m_pipelineBuilder.enableTessellationStage(3);
806 break;
807 default:
808 DE_FATAL("Unknown Shader Stage!");
809 break;
810 }
811 }
812 if (ndx == PIPELINE_CACHE_NDX_CACHED && !param->isDelayedDestroy())
813 {
814 // Destroy the NO_CACHE pipeline to check that the cached one really hits cache,
815 // except for the case where we're testing cache hit of a pipeline still active.
816 vk.destroyPipeline(vkDevice, m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE], DE_NULL);
817 }
818
819 m_pipeline[ndx] = m_pipelineBuilder.buildPipeline(m_renderSize, *m_renderPass, *m_cache, *m_pipelineLayout,
820 &m_pipelineCreationFeedback[ndx],
821 &m_pipelineStageCreationFeedbacks[VK_MAX_SHADER_STAGES * ndx],
822 ndx == PIPELINE_CACHE_NDX_DERIVATIVE ? m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE] : DE_NULL);
823 m_pipelineBuilder.resetBuilder();
824
825 if (ndx != PIPELINE_CACHE_NDX_NO_CACHE)
826 {
827 // Destroy the pipeline as soon as it is created, except the NO_CACHE because
828 // it is needed as a base pipeline for the derivative case.
829 vk.destroyPipeline(vkDevice, m_pipeline[ndx], DE_NULL);
830
831 if (ndx == PIPELINE_CACHE_NDX_CACHED && param->isDelayedDestroy())
832 {
833 // Destroy the pipeline we didn't destroy earlier for the isDelayedDestroy case.
834 vk.destroyPipeline(vkDevice, m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE], DE_NULL);
835 }
836 }
837 }
838 }
839
~GraphicsCacheTestInstance(void)840 GraphicsCacheTestInstance::~GraphicsCacheTestInstance (void)
841 {
842 }
843
verifyTestResult(void)844 tcu::TestStatus GraphicsCacheTestInstance::verifyTestResult (void)
845 {
846 tcu::TestLog &log = m_context.getTestContext().getLog();
847 bool durationZeroWarning = DE_FALSE;
848 bool cachedPipelineWarning = DE_FALSE;
849
850 for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
851 {
852 std::ostringstream message;
853 message << getCaseStr(ndx);
854
855 // No need to check per stage status as it is compute pipeline (only one stage) and Vulkan spec mentions that:
856 // "One common scenario for an implementation to skip per-stage feedback is when
857 // VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT is set in pPipelineCreationFeedback."
858 //
859 // Check first that the no cached pipeline was missed in the pipeline cache
860 if (!(m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
861 {
862 message << ": invalid data";
863 return tcu::TestStatus::fail(message.str());
864 }
865
866 if (m_param->isCacheDisabled() && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
867 {
868 message << ": feedback indicates pipeline hit cache when it shouldn't";
869 return tcu::TestStatus::fail(message.str());
870 }
871
872 if (ndx == PIPELINE_CACHE_NDX_NO_CACHE && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
873 {
874 message << ": hit the cache when it shouldn't";
875 return tcu::TestStatus::fail(message.str());
876 }
877
878 if (ndx != PIPELINE_CACHE_NDX_DERIVATIVE && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT)
879 {
880 message << ": feedback indicates base pipeline acceleration when it shouldn't";
881 return tcu::TestStatus::fail(message.str());
882 }
883
884 if (ndx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
885 {
886 message << "\nWarning: Cached pipeline case did not hit the cache";
887 cachedPipelineWarning = DE_TRUE;
888 }
889
890 if (m_pipelineCreationFeedback[ndx].duration == 0)
891 {
892 message << "\nWarning: Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds\n";
893 durationZeroWarning = DE_TRUE;
894 }
895
896 message << "\n";
897 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";
898 message << "\t\t Base Pipeline Acceleration ? \t" << (m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ? "yes" : "no") << "\n";
899 message << "\t\t Duration (ns): \t\t" << m_pipelineCreationFeedback[ndx].duration << "\n";
900
901 for(deUint32 shader = 0; shader < m_param->getShaderCount(); shader++)
902 {
903 const deUint32 index = VK_MAX_SHADER_STAGES * ndx + shader;
904 message << "\t" << getShaderFlagStr(m_param->getShaderFlag(shader), true) << "\n";
905
906 if (!(m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
907 {
908 if (m_pipelineStageCreationFeedbacks[index].flags)
909 {
910 std::ostringstream errorMsg;
911 errorMsg << getCaseStr(ndx) << ": Creation feedback is not valid for " + getShaderFlagStr(m_param->getShaderFlag(shader), true) + " but there are other flags written";
912 return tcu::TestStatus::fail(errorMsg.str());
913 }
914 message << "\t\t Pipeline Creation Feedback data is not valid\n";
915 continue;
916 }
917 if (m_param->isCacheDisabled() && m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
918 {
919 std::ostringstream errorMsg;
920 errorMsg << getCaseStr(ndx) << ": feedback indicates pipeline " + getShaderFlagStr(m_param->getShaderFlag(shader), true) + " stage hit cache when it shouldn't";
921 return tcu::TestStatus::fail(errorMsg.str());
922 }
923
924 if (ndx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
925 {
926 message << "Warning: pipeline stage did not hit the cache\n";
927 cachedPipelineWarning = DE_TRUE;
928 }
929 if (cachedPipelineWarning && m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
930 {
931 // We only set the warning when the pipeline nor the pipeline stages hit the cache. If any of them did, them disable the warning.
932 cachedPipelineWarning = DE_FALSE;
933 }
934
935 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";
936 message << "\t\t Base Pipeline Acceleration ? \t" << (m_pipelineStageCreationFeedbacks[index].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ? "yes" : "no") << "\n";
937 message << "\t\t Duration (ns): \t\t" << m_pipelineStageCreationFeedbacks[index].duration << "\n";
938 }
939
940 log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
941 }
942
943 if (cachedPipelineWarning)
944 {
945 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Cached pipeline or stage did not hit the cache");
946 }
947 if (durationZeroWarning)
948 {
949 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds");
950 }
951 return tcu::TestStatus::pass("Pass");
952 }
953
954 class ComputeCacheTest : public CacheTest
955 {
956 public:
ComputeCacheTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,const CacheTestParam * param)957 ComputeCacheTest (tcu::TestContext& testContext,
958 const std::string& name,
959 const std::string& description,
960 const CacheTestParam* param)
961 : CacheTest (testContext, name, description, param)
962 { }
~ComputeCacheTest(void)963 virtual ~ComputeCacheTest (void) { }
964 virtual void initPrograms (SourceCollections& programCollection) const;
965 virtual TestInstance* createInstance (Context& context) const;
966 };
967
968 class ComputeCacheTestInstance : public CacheTestInstance
969 {
970 public:
971 ComputeCacheTestInstance (Context& context,
972 const CacheTestParam* param);
973 virtual ~ComputeCacheTestInstance (void);
974 protected:
975 virtual tcu::TestStatus verifyTestResult (void);
976 void buildDescriptorSets (deUint32 ndx);
977 void buildShader (deUint32 ndx);
978 void buildPipeline (const CacheTestParam* param, deUint32 ndx);
979 protected:
980 Move<VkBuffer> m_inputBuf;
981 de::MovePtr<Allocation> m_inputBufferAlloc;
982 Move<VkShaderModule> m_computeShaderModule[PIPELINE_CACHE_NDX_COUNT];
983
984 Move<VkBuffer> m_outputBuf[PIPELINE_CACHE_NDX_COUNT];
985 de::MovePtr<Allocation> m_outputBufferAlloc[PIPELINE_CACHE_NDX_COUNT];
986
987 Move<VkDescriptorPool> m_descriptorPool[PIPELINE_CACHE_NDX_COUNT];
988 Move<VkDescriptorSetLayout> m_descriptorSetLayout[PIPELINE_CACHE_NDX_COUNT];
989 Move<VkDescriptorSet> m_descriptorSet[PIPELINE_CACHE_NDX_COUNT];
990
991 Move<VkPipelineLayout> m_pipelineLayout[PIPELINE_CACHE_NDX_COUNT];
992 VkPipeline m_pipeline[PIPELINE_CACHE_NDX_COUNT];
993 VkPipelineCreationFeedbackEXT m_pipelineCreationFeedback[PIPELINE_CACHE_NDX_COUNT];
994 VkPipelineCreationFeedbackEXT m_pipelineStageCreationFeedback[PIPELINE_CACHE_NDX_COUNT];
995 };
996
initPrograms(SourceCollections & programCollection) const997 void ComputeCacheTest::initPrograms (SourceCollections& programCollection) const
998 {
999 programCollection.glslSources.add("basic_compute_1") << glu::ComputeSource(
1000 "#version 310 es\n"
1001 "layout(local_size_x = 1) in;\n"
1002 "layout(std430) buffer;\n"
1003 "layout(binding = 0) readonly buffer Input0\n"
1004 "{\n"
1005 " vec4 elements[];\n"
1006 "} input_data0;\n"
1007 "layout(binding = 1) writeonly buffer Output\n"
1008 "{\n"
1009 " vec4 elements[];\n"
1010 "} output_data;\n"
1011 "void main()\n"
1012 "{\n"
1013 " uint ident = gl_GlobalInvocationID.x;\n"
1014 " output_data.elements[ident] = input_data0.elements[ident] * input_data0.elements[ident];\n"
1015 "}");
1016 programCollection.glslSources.add("basic_compute_2") << glu::ComputeSource(
1017 "#version 310 es\n"
1018 "layout(local_size_x = 1) in;\n"
1019 "layout(std430) buffer;\n"
1020 "layout(binding = 0) readonly buffer Input0\n"
1021 "{\n"
1022 " vec4 elements[];\n"
1023 "} input_data0;\n"
1024 "layout(binding = 1) writeonly buffer Output\n"
1025 "{\n"
1026 " vec4 elements[];\n"
1027 "} output_data;\n"
1028 "void main()\n"
1029 "{\n"
1030 " uint ident = gl_GlobalInvocationID.x;\n"
1031 " output_data.elements[ident] = input_data0.elements[ident];\n"
1032 "}");
1033 }
1034
createInstance(Context & context) const1035 TestInstance* ComputeCacheTest::createInstance (Context& context) const
1036 {
1037 return new ComputeCacheTestInstance(context, &m_param);
1038 }
1039
buildDescriptorSets(deUint32 ndx)1040 void ComputeCacheTestInstance::buildDescriptorSets (deUint32 ndx)
1041 {
1042 const DeviceInterface& vk = m_context.getDeviceInterface();
1043 const VkDevice vkDevice = m_context.getDevice();
1044
1045 // Create descriptor set layout
1046 DescriptorSetLayoutBuilder descLayoutBuilder;
1047 for (deUint32 bindingNdx = 0u; bindingNdx < 2u; bindingNdx++)
1048 descLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
1049 m_descriptorSetLayout[ndx] = descLayoutBuilder.build(vk, vkDevice);
1050 }
1051
buildShader(deUint32 ndx)1052 void ComputeCacheTestInstance::buildShader (deUint32 ndx)
1053 {
1054 const DeviceInterface& vk = m_context.getDeviceInterface();
1055 const VkDevice vkDevice = m_context.getDevice();
1056
1057 std::string shader_name("basic_compute_");
1058
1059 shader_name += (ndx == PIPELINE_CACHE_NDX_DERIVATIVE) ? "2" : "1";
1060
1061 // Create compute shader
1062 VkShaderModuleCreateInfo shaderModuleCreateInfo =
1063 {
1064 VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // VkStructureType sType;
1065 DE_NULL, // const void* pNext;
1066 0u, // VkShaderModuleCreateFlags flags;
1067 m_context.getBinaryCollection().get(shader_name).getSize(), // deUintptr codeSize;
1068 (deUint32*)m_context.getBinaryCollection().get(shader_name).getBinary(), // const deUint32* pCode;
1069 };
1070 m_computeShaderModule[ndx] = createShaderModule(vk, vkDevice, &shaderModuleCreateInfo);
1071 }
1072
buildPipeline(const CacheTestParam * param,deUint32 ndx)1073 void ComputeCacheTestInstance::buildPipeline (const CacheTestParam* param, deUint32 ndx)
1074 {
1075 const DeviceInterface& vk = m_context.getDeviceInterface();
1076 const VkDevice vkDevice = m_context.getDevice();
1077
1078 deMemset(&m_pipelineCreationFeedback[ndx], 0, sizeof(VkPipelineCreationFeedbackEXT));
1079 deMemset(&m_pipelineStageCreationFeedback[ndx], 0, sizeof(VkPipelineCreationFeedbackEXT));
1080
1081 const VkPipelineCreationFeedbackCreateInfoEXT pipelineCreationFeedbackCreateInfo =
1082 {
1083 VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT, // VkStructureType sType;
1084 DE_NULL, // const void * pNext;
1085 &m_pipelineCreationFeedback[ndx], // VkPipelineCreationFeedbackEXT* pPipelineCreationFeedback;
1086 1u, // deUint32 pipelineStageCreationFeedbackCount;
1087 &m_pipelineStageCreationFeedback[ndx] // VkPipelineCreationFeedbackEXT* pPipelineStageCreationFeedbacks;
1088 };
1089
1090 // Create compute pipeline layout
1091 const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
1092 {
1093 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1094 DE_NULL, // const void* pNext;
1095 0u, // VkPipelineLayoutCreateFlags flags;
1096 1u, // deUint32 setLayoutCount;
1097 &m_descriptorSetLayout[ndx].get(), // const VkDescriptorSetLayout* pSetLayouts;
1098 0u, // deUint32 pushConstantRangeCount;
1099 DE_NULL, // const VkPushConstantRange* pPushConstantRanges;
1100 };
1101
1102 m_pipelineLayout[ndx] = createPipelineLayout(vk, vkDevice, &pipelineLayoutCreateInfo);
1103
1104 const VkPipelineShaderStageCreateInfo stageCreateInfo =
1105 {
1106 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1107 DE_NULL, // const void* pNext;
1108 0u, // VkPipelineShaderStageCreateFlags flags;
1109 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
1110 *m_computeShaderModule[ndx], // VkShaderModule module;
1111 "main", // const char* pName;
1112 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
1113 };
1114
1115 VkComputePipelineCreateInfo pipelineCreateInfo =
1116 {
1117 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
1118 &pipelineCreationFeedbackCreateInfo, // const void* pNext;
1119 0u, // VkPipelineCreateFlags flags;
1120 stageCreateInfo, // VkPipelineShaderStageCreateInfo stage;
1121 *m_pipelineLayout[ndx], // VkPipelineLayout layout;
1122 (VkPipeline)0, // VkPipeline basePipelineHandle;
1123 0u, // deInt32 basePipelineIndex;
1124 };
1125
1126 if (ndx != PIPELINE_CACHE_NDX_DERIVATIVE)
1127 {
1128 pipelineCreateInfo.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
1129 }
1130
1131 if (ndx == PIPELINE_CACHE_NDX_DERIVATIVE)
1132 {
1133 pipelineCreateInfo.flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT;
1134 pipelineCreateInfo.basePipelineHandle = m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE];
1135 pipelineCreateInfo.basePipelineIndex = -1;
1136 }
1137
1138 if (ndx == PIPELINE_CACHE_NDX_CACHED && !param->isDelayedDestroy())
1139 {
1140 // Destroy the NO_CACHE pipeline to check that the cached one really hits cache,
1141 // except for the case where we're testing cache hit of a pipeline still active.
1142 vk.destroyPipeline(vkDevice, m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE], DE_NULL);
1143 }
1144
1145 vk.createComputePipelines(vkDevice, *m_cache, 1u, &pipelineCreateInfo, DE_NULL, &m_pipeline[ndx]);
1146
1147 if (ndx != PIPELINE_CACHE_NDX_NO_CACHE)
1148 {
1149 // Destroy the pipeline as soon as it is created, except the NO_CACHE because
1150 // it is needed as a base pipeline for the derivative case.
1151 vk.destroyPipeline(vkDevice, m_pipeline[ndx], DE_NULL);
1152
1153 if (ndx == PIPELINE_CACHE_NDX_CACHED && param->isDelayedDestroy())
1154 {
1155 // Destroy the pipeline we didn't destroy earlier for the isDelayedDestroy case.
1156 vk.destroyPipeline(vkDevice, m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE], DE_NULL);
1157 }
1158 }
1159 }
1160
ComputeCacheTestInstance(Context & context,const CacheTestParam * param)1161 ComputeCacheTestInstance::ComputeCacheTestInstance (Context& context,
1162 const CacheTestParam* param)
1163 : CacheTestInstance (context, param)
1164 {
1165 for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
1166 {
1167 buildDescriptorSets(ndx);
1168 buildShader(ndx);
1169 buildPipeline(param, ndx);
1170 }
1171 }
1172
~ComputeCacheTestInstance(void)1173 ComputeCacheTestInstance::~ComputeCacheTestInstance (void)
1174 {
1175 }
1176
verifyTestResult(void)1177 tcu::TestStatus ComputeCacheTestInstance::verifyTestResult (void)
1178 {
1179 tcu::TestLog &log = m_context.getTestContext().getLog();
1180 deBool durationZeroWarning = DE_FALSE;
1181 deBool cachedPipelineWarning = DE_FALSE;
1182
1183 for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
1184 {
1185 std::ostringstream message;
1186 message << getCaseStr(ndx);
1187
1188 // No need to check per stage status as it is compute pipeline (only one stage) and Vulkan spec mentions that:
1189 // "One common scenario for an implementation to skip per-stage feedback is when
1190 // VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT is set in pPipelineCreationFeedback."
1191 //
1192 // Check first that the no cached pipeline was missed in the pipeline cache
1193 if (!(m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
1194 {
1195 message << ": invalid data";
1196 return tcu::TestStatus::fail(message.str());
1197 }
1198
1199 if (m_param->isCacheDisabled() && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1200 {
1201 message << ": feedback indicates pipeline hit cache when it shouldn't";
1202 return tcu::TestStatus::fail(message.str());
1203 }
1204
1205 if (ndx == PIPELINE_CACHE_NDX_NO_CACHE && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1206 {
1207 message << ": hit the cache when it shouldn't";
1208 return tcu::TestStatus::fail(message.str());
1209 }
1210
1211 if (!(ndx == PIPELINE_CACHE_NDX_DERIVATIVE && !m_param->isCacheDisabled()) && m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT)
1212 {
1213 message << ": feedback indicates base pipeline acceleration when it shouldn't";
1214 return tcu::TestStatus::fail(message.str());
1215 }
1216
1217 if (ndx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
1218 {
1219 message << "\nWarning: Cached pipeline case did not hit the cache";
1220 cachedPipelineWarning = DE_TRUE;
1221 }
1222
1223 if (m_pipelineCreationFeedback[ndx].duration == 0)
1224 {
1225 message << "\nWarning: Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds\n";
1226 durationZeroWarning = DE_TRUE;
1227 }
1228
1229 message << "\n";
1230
1231 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";
1232 message << "\t\t Base Pipeline Acceleration ? \t" << (m_pipelineCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ? "yes" : "no") << "\n";
1233 message << "\t\t Duration (ns): \t\t" << m_pipelineCreationFeedback[ndx].duration << "\n";
1234
1235 message << "\t Compute Stage\n";
1236
1237 // According to the spec:
1238 //
1239 // "An implementation should write pipeline creation feedback to pPipelineCreationFeedback and
1240 // may write pipeline stage creation feedback to pPipelineStageCreationFeedbacks."
1241 if (!(m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))
1242 {
1243 // According to the spec:
1244 // "If the VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT is not set in flags, an implementation
1245 // must not set any other bits in flags, and all other VkPipelineCreationFeedbackEXT data members are undefined."
1246 if (m_pipelineStageCreationFeedback[ndx].flags)
1247 {
1248 std::ostringstream errorMsg;
1249 errorMsg << getCaseStr(ndx) << ": Creation feedback is not valid for compute stage but there are other flags written";
1250 return tcu::TestStatus::fail(errorMsg.str());
1251 }
1252 message << "\t\t Pipeline Creation Feedback data is not valid\n";
1253 }
1254 else
1255 {
1256 if (m_param->isCacheDisabled() && m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1257 {
1258 std::ostringstream errorMsg;
1259 errorMsg << getCaseStr(ndx) << ": feedback indicates pipeline compute stage hit cache when it shouldn't";
1260 return tcu::TestStatus::fail(errorMsg.str());
1261 }
1262
1263 if (ndx == PIPELINE_CACHE_NDX_CACHED && !m_param->isCacheDisabled() && (m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT) == 0)
1264 {
1265 message << "Warning: pipeline stage did not hit the cache\n";
1266 cachedPipelineWarning = DE_TRUE;
1267 }
1268 if (cachedPipelineWarning && m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT)
1269 {
1270 // We only set the warning when the pipeline nor the pipeline stages hit the cache. If any of them did, them disable the warning.
1271 cachedPipelineWarning = DE_FALSE;
1272 }
1273
1274 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";
1275 message << "\t\t Base Pipeline Acceleration ? \t" << (m_pipelineStageCreationFeedback[ndx].flags & VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT ? "yes" : "no") << "\n";
1276 message << "\t\t Duration (ns): \t\t" << m_pipelineStageCreationFeedback[ndx].duration << "\n";
1277 }
1278
1279 log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
1280 }
1281
1282 if (cachedPipelineWarning)
1283 {
1284 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Cached pipeline or stage did not hit the cache");
1285 }
1286 if (durationZeroWarning)
1287 {
1288 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Pipeline creation feedback reports duration spent creating a pipeline was zero nanoseconds");
1289 }
1290 return tcu::TestStatus::pass("Pass");
1291 }
1292 } // anonymous
1293
createCreationFeedbackTests(tcu::TestContext & testCtx)1294 tcu::TestCaseGroup* createCreationFeedbackTests (tcu::TestContext& testCtx)
1295 {
1296 de::MovePtr<tcu::TestCaseGroup> cacheTests (new tcu::TestCaseGroup(testCtx, "creation_feedback", "pipeline creation feedback tests"));
1297
1298 // Graphics Pipeline Tests
1299 {
1300 de::MovePtr<tcu::TestCaseGroup> graphicsTests (new tcu::TestCaseGroup(testCtx, "graphics_tests", "Test pipeline creation feedback with graphics pipeline."));
1301
1302 const VkShaderStageFlagBits testParamShaders0[] =
1303 {
1304 VK_SHADER_STAGE_VERTEX_BIT,
1305 VK_SHADER_STAGE_FRAGMENT_BIT,
1306 };
1307 const VkShaderStageFlagBits testParamShaders1[] =
1308 {
1309 VK_SHADER_STAGE_VERTEX_BIT,
1310 VK_SHADER_STAGE_GEOMETRY_BIT,
1311 VK_SHADER_STAGE_FRAGMENT_BIT,
1312 };
1313 const VkShaderStageFlagBits testParamShaders2[] =
1314 {
1315 VK_SHADER_STAGE_VERTEX_BIT,
1316 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
1317 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
1318 VK_SHADER_STAGE_FRAGMENT_BIT,
1319 };
1320 const CacheTestParam testParams[] =
1321 {
1322 CacheTestParam(testParamShaders0, DE_LENGTH_OF_ARRAY(testParamShaders0), DE_FALSE, DE_FALSE),
1323 CacheTestParam(testParamShaders1, DE_LENGTH_OF_ARRAY(testParamShaders1), DE_FALSE, DE_FALSE),
1324 CacheTestParam(testParamShaders2, DE_LENGTH_OF_ARRAY(testParamShaders2), DE_FALSE, DE_FALSE),
1325 CacheTestParam(testParamShaders0, DE_LENGTH_OF_ARRAY(testParamShaders0), DE_TRUE, DE_FALSE),
1326 CacheTestParam(testParamShaders1, DE_LENGTH_OF_ARRAY(testParamShaders1), DE_TRUE, DE_FALSE),
1327 CacheTestParam(testParamShaders2, DE_LENGTH_OF_ARRAY(testParamShaders2), DE_TRUE, DE_FALSE),
1328 CacheTestParam(testParamShaders0, DE_LENGTH_OF_ARRAY(testParamShaders0), DE_FALSE, DE_TRUE),
1329 CacheTestParam(testParamShaders1, DE_LENGTH_OF_ARRAY(testParamShaders1), DE_FALSE, DE_TRUE),
1330 CacheTestParam(testParamShaders2, DE_LENGTH_OF_ARRAY(testParamShaders2), DE_FALSE, DE_TRUE),
1331 };
1332
1333 for (deUint32 i = 0; i < DE_LENGTH_OF_ARRAY(testParams); i++)
1334 graphicsTests->addChild(newTestCase<GraphicsCacheTest>(testCtx, &testParams[i]));
1335
1336 cacheTests->addChild(graphicsTests.release());
1337 }
1338
1339 // Compute Pipeline Tests
1340 {
1341 de::MovePtr<tcu::TestCaseGroup> computeTests (new tcu::TestCaseGroup(testCtx, "compute_tests", "Test pipeline creation feedback with compute pipeline."));
1342
1343 const VkShaderStageFlagBits testParamShaders0[] =
1344 {
1345 VK_SHADER_STAGE_COMPUTE_BIT,
1346 };
1347 const CacheTestParam testParams[] =
1348 {
1349 CacheTestParam(testParamShaders0, DE_LENGTH_OF_ARRAY(testParamShaders0), DE_FALSE, DE_FALSE),
1350 CacheTestParam(testParamShaders0, DE_LENGTH_OF_ARRAY(testParamShaders0), DE_TRUE, DE_FALSE),
1351 CacheTestParam(testParamShaders0, DE_LENGTH_OF_ARRAY(testParamShaders0), DE_FALSE, DE_TRUE),
1352 };
1353
1354 for (deUint32 i = 0; i < DE_LENGTH_OF_ARRAY(testParams); i++)
1355 computeTests->addChild(newTestCase<ComputeCacheTest>(testCtx, &testParams[i]));
1356
1357 cacheTests->addChild(computeTests.release());
1358 }
1359
1360 return cacheTests.release();
1361 }
1362
1363 } // pipeline
1364
1365 } // vkt
1366