1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Intel 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 VK_KHR_pipeline_executable_properties
25  *
26  * These tests creates compute and graphics pipelines with a variety of
27  * stages both with and without a pipeline cache and exercise the new
28  * queries provided by VK_KHR_pipeline_executable_properties.
29  *
30  * For each query type, it asserts that the query works and doesn't crash
31  * and returns consistent results:
32  *
33  *  - The tests assert that the same set of pipeline executables is
34  *    reported regardless of whether or not a pipeline cache is used.
35  *
36  *  - For each pipeline executable, the tests assert that the same set of
37  *    statistics is returned regardless of whether or not a pipeline cache
38  *    is used.
39  *
40  *  - For each pipeline executable, the tests assert that the same set of
41  *    statistics is returned regardless of whether or not
42  *    CAPTURE_INTERNAL_REPRESENTATIONS_BIT is set.
43  *
44  *  - For each pipeline executable, the tests assert that the same set of
45  *    internal representations is returned regardless of whether or not a
46  *    pipeline cache is used.
47  *
48  *  - For each string returned (statistic names, etc.) the tests assert
49  *    that the string is NULL terminated.
50  *
51  *  - For each statistic, the tests compare the results of the two
52  *    compilations and report any differences.  (Statistics differing
53  *    between two compilations is not considered a failure.)
54  *
55  *  - For each binary internal representation, the tests attempt to assert
56  *    that the amount of data returned by the implementation matches the
57  *    amount the implementation claims.  (It's impossible to exactly do
58  *    this but the tests give it a good try.)
59  *
60  * All of the returned data is recorded in the output file.
61  *
62  *//*--------------------------------------------------------------------*/
63 
64 #include "vktPipelineExecutablePropertiesTests.hpp"
65 #include "vktPipelineVertexUtil.hpp"
66 #include "vktTestCase.hpp"
67 #include "vktTestCaseUtil.hpp"
68 #include "vkMemUtil.hpp"
69 #include "vkBuilderUtil.hpp"
70 #include "vkRefUtil.hpp"
71 #include "vkTypeUtil.hpp"
72 #include "vkObjUtil.hpp"
73 #include "tcuTestLog.hpp"
74 
75 #include <sstream>
76 #include <vector>
77 
78 namespace vkt
79 {
80 namespace pipeline
81 {
82 
83 using namespace vk;
84 
85 namespace
86 {
87 enum
88 {
89     VK_MAX_SHADER_STAGES = 6,
90 };
91 
92 enum
93 {
94     PIPELINE_CACHE_NDX_INITIAL = 0,
95     PIPELINE_CACHE_NDX_CACHED  = 1,
96     PIPELINE_CACHE_NDX_COUNT,
97 };
98 
99 // helper functions
100 
getShaderFlagStr(const VkShaderStageFlags shader,bool isDescription)101 std::string getShaderFlagStr(const VkShaderStageFlags shader, bool isDescription)
102 {
103     std::ostringstream desc;
104     if (shader & VK_SHADER_STAGE_COMPUTE_BIT)
105     {
106         desc << ((isDescription) ? "compute stage" : "compute_stage");
107     }
108     else
109     {
110         desc << ((isDescription) ? "vertex stage" : "vertex_stage");
111         if (shader & VK_SHADER_STAGE_GEOMETRY_BIT)
112             desc << ((isDescription) ? " geometry stage" : "_geometry_stage");
113         if (shader & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
114             desc << ((isDescription) ? " tessellation control stage" : "_tessellation_control_stage");
115         if (shader & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
116             desc << ((isDescription) ? " tessellation evaluation stage" : "_tessellation_evaluation_stage");
117         desc << ((isDescription) ? " fragment stage" : "_fragment_stage");
118     }
119 
120     return desc.str();
121 }
122 
getShaderFlagsStr(const VkShaderStageFlags flags)123 std::string getShaderFlagsStr(const VkShaderStageFlags flags)
124 {
125     std::ostringstream stream;
126     bool empty = true;
127     for (uint32_t b = 0; b < 8 * sizeof(flags); b++)
128     {
129         if (flags & (1u << b))
130         {
131             if (empty)
132             {
133                 empty = false;
134             }
135             else
136             {
137                 stream << ", ";
138             }
139 
140             stream << getShaderFlagStr((VkShaderStageFlagBits)(1u << b), true);
141         }
142     }
143 
144     if (empty)
145     {
146         stream << "none";
147     }
148 
149     return stream.str();
150 }
151 
152 // helper classes
153 class ExecutablePropertiesTestParam
154 {
155 public:
156     ExecutablePropertiesTestParam(PipelineConstructionType pipelineConstructionType, const VkShaderStageFlags shaders,
157                                   bool testStatistics, bool testInternalRepresentations);
158     virtual ~ExecutablePropertiesTestParam(void) = default;
159     virtual const std::string generateTestName(void) const;
getPipelineConstructionType(void) const160     PipelineConstructionType getPipelineConstructionType(void) const
161     {
162         return m_pipelineConstructionType;
163     }
getShaderFlags(void) const164     VkShaderStageFlags getShaderFlags(void) const
165     {
166         return m_shaders;
167     }
getTestStatistics(void) const168     bool getTestStatistics(void) const
169     {
170         return m_testStatistics;
171     }
getTestInternalRepresentations(void) const172     bool getTestInternalRepresentations(void) const
173     {
174         return m_testInternalRepresentations;
175     }
176 
177 protected:
178     PipelineConstructionType m_pipelineConstructionType;
179     VkShaderStageFlags m_shaders;
180     bool m_testStatistics;
181     bool m_testInternalRepresentations;
182 };
183 
ExecutablePropertiesTestParam(PipelineConstructionType pipelineConstructionType,const VkShaderStageFlags shaders,bool testStatistics,bool testInternalRepresentations)184 ExecutablePropertiesTestParam::ExecutablePropertiesTestParam(PipelineConstructionType pipelineConstructionType,
185                                                              const VkShaderStageFlags shaders, bool testStatistics,
186                                                              bool testInternalRepresentations)
187     : m_pipelineConstructionType(pipelineConstructionType)
188     , m_shaders(shaders)
189     , m_testStatistics(testStatistics)
190     , m_testInternalRepresentations(testInternalRepresentations)
191 {
192 }
193 
generateTestName(void) const194 const std::string ExecutablePropertiesTestParam::generateTestName(void) const
195 {
196     std::string result(getShaderFlagStr(m_shaders, false));
197 
198     if (m_testStatistics)
199         result += "_statistics";
200     if (m_testInternalRepresentations)
201         result += "_internal_representations";
202 
203     return result;
204 }
205 
206 template <class Test>
newTestCase(tcu::TestContext & testContext,const ExecutablePropertiesTestParam * testParam)207 vkt::TestCase *newTestCase(tcu::TestContext &testContext, const ExecutablePropertiesTestParam *testParam)
208 {
209     return new Test(testContext, testParam->generateTestName().c_str(), testParam);
210 }
211 
212 // Test Classes
213 class ExecutablePropertiesTest : public vkt::TestCase
214 {
215 public:
ExecutablePropertiesTest(tcu::TestContext & testContext,const std::string & name,const ExecutablePropertiesTestParam * param)216     ExecutablePropertiesTest(tcu::TestContext &testContext, const std::string &name,
217                              const ExecutablePropertiesTestParam *param)
218         : vkt::TestCase(testContext, name)
219         , m_param(*param)
220     {
221     }
~ExecutablePropertiesTest(void)222     virtual ~ExecutablePropertiesTest(void)
223     {
224     }
225 
226 protected:
227     const ExecutablePropertiesTestParam m_param;
228 };
229 
230 class ExecutablePropertiesTestInstance : public vkt::TestInstance
231 {
232 public:
233     ExecutablePropertiesTestInstance(Context &context, const ExecutablePropertiesTestParam *param);
234     virtual ~ExecutablePropertiesTestInstance(void);
235     virtual tcu::TestStatus iterate(void);
236 
237 protected:
238     virtual tcu::TestStatus verifyStatistics(uint32_t binaryNdx);
239     virtual tcu::TestStatus verifyInternalRepresentations(uint32_t binaryNdx);
240     virtual tcu::TestStatus verifyTestResult(void);
241 
242 protected:
243     const ExecutablePropertiesTestParam *m_param;
244 
245     Move<VkPipelineCache> m_cache;
246     bool m_extensions;
247 
248     Move<VkPipeline> m_pipeline[PIPELINE_CACHE_NDX_COUNT];
249 
getPipeline(uint32_t ndx)250     virtual VkPipeline getPipeline(uint32_t ndx)
251     {
252         return m_pipeline[ndx].get();
253     }
254 };
255 
ExecutablePropertiesTestInstance(Context & context,const ExecutablePropertiesTestParam * param)256 ExecutablePropertiesTestInstance::ExecutablePropertiesTestInstance(Context &context,
257                                                                    const ExecutablePropertiesTestParam *param)
258     : TestInstance(context)
259     , m_param(param)
260     , m_extensions(m_context.requireDeviceFunctionality("VK_KHR_pipeline_executable_properties"))
261 {
262     const DeviceInterface &vk = m_context.getDeviceInterface();
263     const VkDevice vkDevice   = m_context.getDevice();
264 
265     const VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {
266         VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
267         DE_NULL,                                      // const void* pNext;
268         0u,                                           // VkPipelineCacheCreateFlags flags;
269         0u,                                           // uintptr_t initialDataSize;
270         DE_NULL,                                      // const void* pInitialData;
271     };
272 
273     m_cache = createPipelineCache(vk, vkDevice, &pipelineCacheCreateInfo);
274 }
275 
~ExecutablePropertiesTestInstance(void)276 ExecutablePropertiesTestInstance::~ExecutablePropertiesTestInstance(void)
277 {
278 }
279 
iterate(void)280 tcu::TestStatus ExecutablePropertiesTestInstance::iterate(void)
281 {
282     return verifyTestResult();
283 }
284 
checkString(const char * string,size_t size)285 bool checkString(const char *string, size_t size)
286 {
287     size_t i = 0;
288     for (; i < size; i++)
289     {
290         if (string[i] == 0)
291         {
292             break;
293         }
294     }
295 
296     // The string needs to be non-empty and null terminated
297     if (i == 0 || i >= size)
298     {
299         return false;
300     }
301 
302     return true;
303 }
304 
verifyStatistics(uint32_t executableNdx)305 tcu::TestStatus ExecutablePropertiesTestInstance::verifyStatistics(uint32_t executableNdx)
306 {
307     const DeviceInterface &vk = m_context.getDeviceInterface();
308     const VkDevice vkDevice   = m_context.getDevice();
309     tcu::TestLog &log         = m_context.getTestContext().getLog();
310 
311     std::vector<VkPipelineExecutableStatisticKHR> statistics[PIPELINE_CACHE_NDX_COUNT];
312 
313     for (uint32_t ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
314     {
315         const VkPipelineExecutableInfoKHR pipelineExecutableInfo = {
316             VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR, // VkStructureType sType;
317             DE_NULL,                                        // const void* pNext;
318             getPipeline(ndx),                               // VkPipeline pipeline;
319             executableNdx,                                  // uint32_t executableIndex;
320         };
321 
322         uint32_t statisticCount = 0;
323         VK_CHECK(vk.getPipelineExecutableStatisticsKHR(vkDevice, &pipelineExecutableInfo, &statisticCount, DE_NULL));
324 
325         if (statisticCount == 0)
326         {
327             continue;
328         }
329 
330         statistics[ndx].resize(statisticCount);
331         for (uint32_t statNdx = 0; statNdx < statisticCount; statNdx++)
332         {
333             deMemset(&statistics[ndx][statNdx], 0, sizeof(statistics[ndx][statNdx]));
334             statistics[ndx][statNdx].sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR;
335             statistics[ndx][statNdx].pNext = DE_NULL;
336         }
337         VK_CHECK(vk.getPipelineExecutableStatisticsKHR(vkDevice, &pipelineExecutableInfo, &statisticCount,
338                                                        &statistics[ndx][0]));
339 
340         for (uint32_t statNdx = 0; statNdx < statisticCount; statNdx++)
341         {
342             if (!checkString(statistics[ndx][statNdx].name, DE_LENGTH_OF_ARRAY(statistics[ndx][statNdx].name)))
343             {
344                 return tcu::TestStatus::fail("Invalid statistic name string");
345             }
346 
347             for (uint32_t otherNdx = 0; otherNdx < statNdx; otherNdx++)
348             {
349                 if (deMemCmp(statistics[ndx][statNdx].name, statistics[ndx][otherNdx].name,
350                              DE_LENGTH_OF_ARRAY(statistics[ndx][statNdx].name)) == 0)
351                 {
352                     return tcu::TestStatus::fail("Statistic name string not unique within the executable");
353                 }
354             }
355 
356             if (!checkString(statistics[ndx][statNdx].description,
357                              DE_LENGTH_OF_ARRAY(statistics[ndx][statNdx].description)))
358             {
359                 return tcu::TestStatus::fail("Invalid statistic description string");
360             }
361 
362             if (statistics[ndx][statNdx].format == VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR)
363             {
364                 if (statistics[ndx][statNdx].value.b32 != VK_TRUE && statistics[ndx][statNdx].value.b32 != VK_FALSE)
365                 {
366                     return tcu::TestStatus::fail("Boolean statistic is neither VK_TRUE nor VK_FALSE");
367                 }
368             }
369         }
370     }
371 
372     if (statistics[0].size() != statistics[1].size())
373     {
374         return tcu::TestStatus::fail("Identical pipelines have different numbers of statistics");
375     }
376 
377     if (statistics[0].size() == 0)
378     {
379         return tcu::TestStatus::pass("No statistics reported");
380     }
381 
382     // Both compiles had better have specified the same infos
383     for (uint32_t statNdx0 = 0; statNdx0 < statistics[0].size(); statNdx0++)
384     {
385         uint32_t statNdx1 = 0;
386         for (; statNdx1 < statistics[1].size(); statNdx1++)
387         {
388             if (deMemCmp(statistics[0][statNdx0].name, statistics[1][statNdx1].name,
389                          DE_LENGTH_OF_ARRAY(statistics[0][statNdx0].name)) == 0)
390             {
391                 break;
392             }
393         }
394         if (statNdx1 >= statistics[1].size())
395         {
396             return tcu::TestStatus::fail("Identical pipelines have different statistics");
397         }
398 
399         if (deMemCmp(statistics[0][statNdx0].description, statistics[1][statNdx1].description,
400                      DE_LENGTH_OF_ARRAY(statistics[0][statNdx0].description)) != 0)
401         {
402             return tcu::TestStatus::fail("Invalid binary description string");
403         }
404 
405         if (statistics[0][statNdx0].format != statistics[1][statNdx1].format)
406         {
407             return tcu::TestStatus::fail("Identical pipelines have statistics with different formats");
408         }
409 
410         switch (statistics[0][statNdx0].format)
411         {
412         case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR:
413         {
414             bool match = statistics[0][statNdx0].value.b32 == statistics[1][statNdx1].value.b32;
415             log << tcu::TestLog::Message << statistics[0][statNdx0].name << ": "
416                 << (statistics[0][statNdx0].value.b32 ? "VK_TRUE" : "VK_FALSE") << (match ? "" : " (non-deterministic)")
417                 << " (" << statistics[0][statNdx0].description << ")" << tcu::TestLog::EndMessage;
418             break;
419         }
420         case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR:
421         {
422             bool match = statistics[0][statNdx0].value.i64 == statistics[1][statNdx1].value.i64;
423             log << tcu::TestLog::Message << statistics[0][statNdx0].name << ": " << statistics[0][statNdx0].value.i64
424                 << (match ? "" : " (non-deterministic)") << " (" << statistics[0][statNdx0].description << ")"
425                 << tcu::TestLog::EndMessage;
426             break;
427         }
428         case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR:
429         {
430             bool match = statistics[0][statNdx0].value.u64 == statistics[1][statNdx1].value.u64;
431             log << tcu::TestLog::Message << statistics[0][statNdx0].name << ": " << statistics[0][statNdx0].value.u64
432                 << (match ? "" : " (non-deterministic)") << " (" << statistics[0][statNdx0].description << ")"
433                 << tcu::TestLog::EndMessage;
434             break;
435         }
436         case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR:
437         {
438             bool match = statistics[0][statNdx0].value.f64 == statistics[1][statNdx1].value.f64;
439             log << tcu::TestLog::Message << statistics[0][statNdx0].name << ": " << statistics[0][statNdx0].value.f64
440                 << (match ? "" : " (non-deterministic)") << " (" << statistics[0][statNdx0].description << ")"
441                 << tcu::TestLog::EndMessage;
442             break;
443         }
444         default:
445             return tcu::TestStatus::fail("Invalid statistic format");
446         }
447     }
448 
449     return tcu::TestStatus::pass("Pass");
450 }
451 
verifyInternalRepresentations(uint32_t executableNdx)452 tcu::TestStatus ExecutablePropertiesTestInstance::verifyInternalRepresentations(uint32_t executableNdx)
453 {
454     const DeviceInterface &vk = m_context.getDeviceInterface();
455     const VkDevice vkDevice   = m_context.getDevice();
456     tcu::TestLog &log         = m_context.getTestContext().getLog();
457 
458     // We only care about internal representations on the second pipeline.
459     // We still compile twice to ensure that we still get the right thing
460     // even if the pipeline is hot in the cache.
461     const VkPipelineExecutableInfoKHR pipelineExecutableInfo = {
462         VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR, // VkStructureType sType;
463         DE_NULL,                                        // const void* pNext;
464         getPipeline(1),                                 // VkPipeline pipeline;
465         executableNdx,                                  // uint32_t executableIndex;
466     };
467 
468     std::vector<VkPipelineExecutableInternalRepresentationKHR> irs;
469     std::vector<std::vector<uint8_t>> irDatas;
470 
471     uint32_t irCount = 0;
472     VK_CHECK(vk.getPipelineExecutableInternalRepresentationsKHR(vkDevice, &pipelineExecutableInfo, &irCount, DE_NULL));
473 
474     if (irCount == 0)
475     {
476         return tcu::TestStatus::pass("No internal representations reported");
477     }
478 
479     irs.resize(irCount);
480     irDatas.resize(irCount);
481     for (uint32_t irNdx = 0; irNdx < irCount; irNdx++)
482     {
483         deMemset(&irs[irNdx], 0, sizeof(irs[irNdx]));
484         irs[irNdx].sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR;
485         irs[irNdx].pNext = DE_NULL;
486     }
487     VK_CHECK(vk.getPipelineExecutableInternalRepresentationsKHR(vkDevice, &pipelineExecutableInfo, &irCount, &irs[0]));
488 
489     for (uint32_t irNdx = 0; irNdx < irCount; irNdx++)
490     {
491         if (!checkString(irs[irNdx].name, DE_LENGTH_OF_ARRAY(irs[irNdx].name)))
492         {
493             return tcu::TestStatus::fail("Invalid internal representation name string");
494         }
495 
496         for (uint32_t otherNdx = 0; otherNdx < irNdx; otherNdx++)
497         {
498             if (deMemCmp(irs[irNdx].name, irs[otherNdx].name, DE_LENGTH_OF_ARRAY(irs[irNdx].name)) == 0)
499             {
500                 return tcu::TestStatus::fail("Internal representation name string not unique within the executable");
501             }
502         }
503 
504         if (!checkString(irs[irNdx].description, DE_LENGTH_OF_ARRAY(irs[irNdx].description)))
505         {
506             return tcu::TestStatus::fail("Invalid binary description string");
507         }
508 
509         if (irs[irNdx].dataSize == 0)
510         {
511             return tcu::TestStatus::fail("Internal representation has no data");
512         }
513 
514         irDatas[irNdx].resize(irs[irNdx].dataSize);
515         irs[irNdx].pData = &irDatas[irNdx][0];
516         if (irs[irNdx].isText)
517         {
518             // For binary data the size is important.  We check that the
519             // implementation fills the whole buffer by filling it with
520             // garbage first and then looking for that same garbage later.
521             for (size_t i = 0; i < irs[irNdx].dataSize; i++)
522             {
523                 irDatas[irNdx][i] = (uint8_t)(37 * (17 + i));
524             }
525         }
526     }
527 
528     VK_CHECK(vk.getPipelineExecutableInternalRepresentationsKHR(vkDevice, &pipelineExecutableInfo, &irCount, &irs[0]));
529 
530     for (uint32_t irNdx = 0; irNdx < irCount; irNdx++)
531     {
532         if (irs[irNdx].isText)
533         {
534             if (!checkString((char *)irs[irNdx].pData, irs[irNdx].dataSize))
535             {
536                 return tcu::TestStatus::fail("Textual internal representation isn't a valid string");
537             }
538             log << tcu::TestLog::Section(irs[irNdx].name, irs[irNdx].description)
539                 << tcu::LogKernelSource((char *)irs[irNdx].pData) << tcu::TestLog::EndSection;
540         }
541         else
542         {
543             size_t maxMatchingChunkSize = 0;
544             size_t matchingChunkSize    = 0;
545             for (size_t i = 0; i < irs[irNdx].dataSize; i++)
546             {
547                 if (irDatas[irNdx][i] == (uint8_t)(37 * (17 + i)))
548                 {
549                     matchingChunkSize++;
550                     if (matchingChunkSize > maxMatchingChunkSize)
551                     {
552                         maxMatchingChunkSize = matchingChunkSize;
553                     }
554                 }
555                 else
556                 {
557                     matchingChunkSize = 0;
558                 }
559             }
560 
561             // 64 bytes of our random data still being in the buffer probably
562             // isn't a coincidence
563             if (matchingChunkSize == irs[irNdx].dataSize || matchingChunkSize >= 64)
564             {
565                 return tcu::TestStatus::fail(
566                     "Implementation didn't fill the whole internal representation data buffer");
567             }
568 
569             log << tcu::TestLog::Section(irs[irNdx].name, irs[irNdx].description) << tcu::TestLog::Message
570                 << "Received " << irs[irNdx].dataSize << "B of binary data" << tcu::TestLog::EndMessage
571                 << tcu::TestLog::EndSection;
572         }
573     }
574 
575     return tcu::TestStatus::pass("Pass");
576 }
577 
verifyTestResult(void)578 tcu::TestStatus ExecutablePropertiesTestInstance::verifyTestResult(void)
579 {
580     const DeviceInterface &vk = m_context.getDeviceInterface();
581     const VkDevice vkDevice   = m_context.getDevice();
582     tcu::TestLog &log         = m_context.getTestContext().getLog();
583 
584     std::vector<VkPipelineExecutablePropertiesKHR> props[PIPELINE_CACHE_NDX_COUNT];
585 
586     for (uint32_t ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
587     {
588         const VkPipelineInfoKHR pipelineInfo = {
589             VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR, // VkStructureType sType;
590             DE_NULL,                             // const void* pNext;
591             getPipeline(ndx),                    // VkPipeline pipeline;
592 
593         };
594         uint32_t executableCount = 0;
595         VK_CHECK(vk.getPipelineExecutablePropertiesKHR(vkDevice, &pipelineInfo, &executableCount, DE_NULL));
596 
597         if (executableCount == 0)
598         {
599             continue;
600         }
601 
602         props[ndx].resize(executableCount);
603         for (uint32_t execNdx = 0; execNdx < executableCount; execNdx++)
604         {
605             deMemset(&props[ndx][execNdx], 0, sizeof(props[ndx][execNdx]));
606             props[ndx][execNdx].sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR;
607             props[ndx][execNdx].pNext = DE_NULL;
608         }
609         VK_CHECK(vk.getPipelineExecutablePropertiesKHR(vkDevice, &pipelineInfo, &executableCount, &props[ndx][0]));
610 
611         for (uint32_t execNdx = 0; execNdx < executableCount; execNdx++)
612         {
613             if (!checkString(props[ndx][execNdx].name, DE_LENGTH_OF_ARRAY(props[ndx][execNdx].name)))
614             {
615                 return tcu::TestStatus::fail("Invalid binary name string");
616             }
617 
618             for (uint32_t otherNdx = 0; otherNdx < execNdx; otherNdx++)
619             {
620                 if (deMemCmp(props[ndx][execNdx].name, props[ndx][otherNdx].name,
621                              DE_LENGTH_OF_ARRAY(props[ndx][execNdx].name)) == 0)
622                 {
623                     return tcu::TestStatus::fail("Binary name string not unique within the pipeline");
624                 }
625             }
626 
627             if (!checkString(props[ndx][execNdx].description, DE_LENGTH_OF_ARRAY(props[ndx][execNdx].description)))
628             {
629                 return tcu::TestStatus::fail("Invalid binary description string");
630             }
631 
632             // Check that the binary only contains stages actually used to
633             // compile the pipeline
634             VkShaderStageFlags stages = props[ndx][execNdx].stages;
635             stages &= ~m_param->getShaderFlags();
636             if (stages != 0)
637             {
638                 return tcu::TestStatus::fail("Binary uses unprovided stage");
639             }
640         }
641     }
642 
643     if (props[0].size() != props[1].size())
644     {
645         return tcu::TestStatus::fail("Identical pipelines have different numbers of props");
646     }
647 
648     if (props[0].size() == 0)
649     {
650         return tcu::TestStatus::pass("No executables reported");
651     }
652 
653     // Both compiles had better have specified the same infos
654     for (uint32_t execNdx0 = 0; execNdx0 < props[0].size(); execNdx0++)
655     {
656         uint32_t execNdx1 = 0;
657         for (; execNdx1 < props[1].size(); execNdx1++)
658         {
659             if (deMemCmp(props[0][execNdx0].name, props[1][execNdx1].name,
660                          DE_LENGTH_OF_ARRAY(props[0][execNdx0].name)) == 0)
661             {
662                 break;
663             }
664         }
665         if (execNdx1 >= props[1].size())
666         {
667             return tcu::TestStatus::fail("Identical pipelines have different sets of executables");
668         }
669 
670         if (deMemCmp(props[0][execNdx0].description, props[1][execNdx1].description,
671                      DE_LENGTH_OF_ARRAY(props[0][execNdx0].description)) != 0)
672         {
673             return tcu::TestStatus::fail("Same binary has different descriptions");
674         }
675 
676         if (props[0][execNdx0].stages != props[1][execNdx1].stages)
677         {
678             return tcu::TestStatus::fail("Same binary has different stages");
679         }
680 
681         if (props[0][execNdx0].subgroupSize != props[1][execNdx1].subgroupSize)
682         {
683             return tcu::TestStatus::fail("Same binary has different subgroup sizes");
684         }
685     }
686 
687     log << tcu::TestLog::Section("Binaries", "Binaries reported for this pipeline");
688     log << tcu::TestLog::Message << "Pipeline reported " << props[0].size() << " props" << tcu::TestLog::EndMessage;
689 
690     tcu::TestStatus status = tcu::TestStatus::pass("Pass");
691     for (uint32_t execNdx = 0; execNdx < props[0].size(); execNdx++)
692     {
693         log << tcu::TestLog::Section(props[0][execNdx].name, props[0][execNdx].description);
694         log << tcu::TestLog::Message << "Name: " << props[0][execNdx].name << tcu::TestLog::EndMessage;
695         log << tcu::TestLog::Message << "Description: " << props[0][execNdx].description << tcu::TestLog::EndMessage;
696         log << tcu::TestLog::Message << "Stages: " << getShaderFlagsStr(props[0][execNdx].stages)
697             << tcu::TestLog::EndMessage;
698         log << tcu::TestLog::Message << "Subgroup Size: " << props[0][execNdx].subgroupSize << tcu::TestLog::EndMessage;
699 
700         if (m_param->getTestStatistics())
701         {
702             status = verifyStatistics(execNdx);
703             if (status.getCode() != QP_TEST_RESULT_PASS)
704             {
705                 log << tcu::TestLog::EndSection;
706                 break;
707             }
708         }
709 
710         if (m_param->getTestInternalRepresentations())
711         {
712             status = verifyInternalRepresentations(execNdx);
713             if (status.getCode() != QP_TEST_RESULT_PASS)
714             {
715                 log << tcu::TestLog::EndSection;
716                 break;
717             }
718         }
719 
720         log << tcu::TestLog::EndSection;
721     }
722 
723     log << tcu::TestLog::EndSection;
724 
725     return status;
726 }
727 
728 class GraphicsExecutablePropertiesTest : public ExecutablePropertiesTest
729 {
730 public:
GraphicsExecutablePropertiesTest(tcu::TestContext & testContext,const std::string & name,const ExecutablePropertiesTestParam * param)731     GraphicsExecutablePropertiesTest(tcu::TestContext &testContext, const std::string &name,
732                                      const ExecutablePropertiesTestParam *param)
733         : ExecutablePropertiesTest(testContext, name, param)
734     {
735     }
~GraphicsExecutablePropertiesTest(void)736     virtual ~GraphicsExecutablePropertiesTest(void)
737     {
738     }
739     virtual void initPrograms(SourceCollections &programCollection) const;
740     virtual TestInstance *createInstance(Context &context) const;
741     void checkSupport(Context &context) const;
742 };
743 
744 class GraphicsExecutablePropertiesTestInstance : public ExecutablePropertiesTestInstance
745 {
746 public:
747     GraphicsExecutablePropertiesTestInstance(Context &context, const ExecutablePropertiesTestParam *param);
748     virtual ~GraphicsExecutablePropertiesTestInstance(void);
749 
750 protected:
751     void preparePipelineWrapper(GraphicsPipelineWrapper &gpw, ShaderWrapper vertShaderModule,
752                                 ShaderWrapper tescShaderModule, ShaderWrapper teseShaderModule,
753                                 ShaderWrapper geomShaderModule, ShaderWrapper fragShaderModule);
754 
getPipeline(uint32_t ndx)755     VkPipeline getPipeline(uint32_t ndx) override
756     {
757         return m_pipelineWrapper[ndx].getPipeline();
758     };
759 
760 protected:
761     const tcu::UVec2 m_renderSize;
762     const VkFormat m_colorFormat;
763     const VkFormat m_depthFormat;
764     PipelineLayoutWrapper m_pipelineLayout;
765     GraphicsPipelineWrapper m_pipelineWrapper[PIPELINE_CACHE_NDX_COUNT];
766     Move<VkRenderPass> m_renderPass;
767 };
768 
initPrograms(SourceCollections & programCollection) const769 void GraphicsExecutablePropertiesTest::initPrograms(SourceCollections &programCollection) const
770 {
771     programCollection.glslSources.add("color_vert")
772         << glu::VertexSource("#version 310 es\n"
773                              "layout(location = 0) in vec4 position;\n"
774                              "layout(location = 1) in vec4 color;\n"
775                              "layout(location = 0) out highp vec4 vtxColor;\n"
776                              "void main (void)\n"
777                              "{\n"
778                              "  gl_Position = position;\n"
779                              "  vtxColor = color;\n"
780                              "}\n");
781 
782     programCollection.glslSources.add("color_frag")
783         << glu::FragmentSource("#version 310 es\n"
784                                "layout(location = 0) in highp vec4 vtxColor;\n"
785                                "layout(location = 0) out highp vec4 fragColor;\n"
786                                "void main (void)\n"
787                                "{\n"
788                                "  fragColor = vtxColor;\n"
789                                "}\n");
790 
791     if (m_param.getShaderFlags() & VK_SHADER_STAGE_GEOMETRY_BIT)
792     {
793         programCollection.glslSources.add("dummy_geo")
794             << glu::GeometrySource("#version 450 \n"
795                                    "layout(triangles) in;\n"
796                                    "layout(triangle_strip, max_vertices = 3) out;\n"
797                                    "layout(location = 0) in highp vec4 in_vtxColor[];\n"
798                                    "layout(location = 0) out highp vec4 vtxColor;\n"
799                                    "out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
800                                    "in gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_in[];\n"
801                                    "void main (void)\n"
802                                    "{\n"
803                                    "  for(int ndx=0; ndx<3; ndx++)\n"
804                                    "  {\n"
805                                    "    gl_Position = gl_in[ndx].gl_Position;\n"
806                                    "    gl_PointSize = gl_in[ndx].gl_PointSize;\n"
807                                    "    vtxColor    = in_vtxColor[ndx];\n"
808                                    "    EmitVertex();\n"
809                                    "  }\n"
810                                    "  EndPrimitive();\n"
811                                    "}\n");
812     }
813     if (m_param.getShaderFlags() & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
814     {
815         programCollection.glslSources.add("basic_tcs") << glu::TessellationControlSource(
816             "#version 450 \n"
817             "layout(vertices = 3) out;\n"
818             "layout(location = 0) in highp vec4 color[];\n"
819             "layout(location = 0) out highp vec4 vtxColor[];\n"
820             "out gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_out[3];\n"
821             "in gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_in[gl_MaxPatchVertices];\n"
822             "void main()\n"
823             "{\n"
824             "  gl_TessLevelOuter[0] = 4.0;\n"
825             "  gl_TessLevelOuter[1] = 4.0;\n"
826             "  gl_TessLevelOuter[2] = 4.0;\n"
827             "  gl_TessLevelInner[0] = 4.0;\n"
828             "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
829             "  gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n"
830             "  vtxColor[gl_InvocationID] = color[gl_InvocationID];\n"
831             "}\n");
832 
833         programCollection.glslSources.add("basic_tes") << glu::TessellationEvaluationSource(
834             "#version 450 \n"
835             "layout(triangles, fractional_even_spacing, ccw) in;\n"
836             "layout(location = 0) in highp vec4 colors[];\n"
837             "layout(location = 0) out highp vec4 vtxColor;\n"
838             "out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
839             "in gl_PerVertex { vec4 gl_Position; float gl_PointSize; } gl_in[gl_MaxPatchVertices];\n"
840             "void main() \n"
841             "{\n"
842             "  float u = gl_TessCoord.x;\n"
843             "  float v = gl_TessCoord.y;\n"
844             "  float w = gl_TessCoord.z;\n"
845             "  vec4 pos = vec4(0);\n"
846             "  vec4 color = vec4(0);\n"
847             "  pos.xyz += u * gl_in[0].gl_Position.xyz;\n"
848             "  color.xyz += u * colors[0].xyz;\n"
849             "  pos.xyz += v * gl_in[1].gl_Position.xyz;\n"
850             "  color.xyz += v * colors[1].xyz;\n"
851             "  pos.xyz += w * gl_in[2].gl_Position.xyz;\n"
852             "  color.xyz += w * colors[2].xyz;\n"
853             "  pos.w = 1.0;\n"
854             "  color.w = 1.0;\n"
855             "  gl_Position = pos;\n"
856             "  gl_PointSize = gl_in[0].gl_PointSize;"
857             "  vtxColor = color;\n"
858             "}\n");
859     }
860 }
861 
createInstance(Context & context) const862 TestInstance *GraphicsExecutablePropertiesTest::createInstance(Context &context) const
863 {
864     return new GraphicsExecutablePropertiesTestInstance(context, &m_param);
865 }
866 
checkSupport(Context & context) const867 void GraphicsExecutablePropertiesTest::checkSupport(Context &context) const
868 {
869     VkShaderStageFlags shaderFlags    = m_param.getShaderFlags();
870     VkPhysicalDeviceFeatures features = context.getDeviceFeatures();
871     if ((shaderFlags & VK_SHADER_STAGE_GEOMETRY_BIT) && (features.geometryShader == VK_FALSE))
872         TCU_THROW(NotSupportedError, "Geometry Shader Not Supported");
873     if ((shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) ||
874         (shaderFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))
875     {
876         if (features.tessellationShader == VK_FALSE)
877             TCU_THROW(NotSupportedError, "Tessellation Not Supported");
878     }
879 
880     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
881                                           m_param.getPipelineConstructionType());
882 }
883 
GraphicsExecutablePropertiesTestInstance(Context & context,const ExecutablePropertiesTestParam * param)884 GraphicsExecutablePropertiesTestInstance::GraphicsExecutablePropertiesTestInstance(
885     Context &context, const ExecutablePropertiesTestParam *param)
886     : ExecutablePropertiesTestInstance(context, param)
887     , m_renderSize(32u, 32u)
888     , m_colorFormat(VK_FORMAT_R8G8B8A8_UNORM)
889     , m_depthFormat(VK_FORMAT_D16_UNORM)
890     , m_pipelineWrapper{
891           {m_context.getInstanceInterface(), m_context.getDeviceInterface(), m_context.getPhysicalDevice(),
892            m_context.getDevice(), m_context.getDeviceExtensions(), param->getPipelineConstructionType(),
893            (param->getTestStatistics() ? uint32_t(VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR) : 0u)},
894           {m_context.getInstanceInterface(), m_context.getDeviceInterface(), m_context.getPhysicalDevice(),
895            m_context.getDevice(), m_context.getDeviceExtensions(), param->getPipelineConstructionType(),
896            (param->getTestStatistics() ? uint32_t(VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR) : 0u) |
897                // Only check gather internal representations on the second pipeline.
898                // This way, it's more obvious if they failed to capture due to the pipeline being cached.
899                (param->getTestInternalRepresentations() ?
900                     uint32_t(VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR) :
901                     0u)},
902       }
903 {
904     const DeviceInterface &vk = m_context.getDeviceInterface();
905     const VkDevice vkDevice   = m_context.getDevice();
906 
907     // Create pipeline layout
908     {
909         const VkPipelineLayoutCreateInfo pipelineLayoutParams = {
910             VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
911             DE_NULL,                                       // const void* pNext;
912             0u,                                            // VkPipelineLayoutCreateFlags flags;
913             0u,                                            // uint32_t setLayoutCount;
914             DE_NULL,                                       // const VkDescriptorSetLayout* pSetLayouts;
915             0u,                                            // uint32_t pushConstantRangeCount;
916             DE_NULL                                        // const VkPushConstantRange* pPushConstantRanges;
917         };
918 
919         m_pipelineLayout =
920             PipelineLayoutWrapper(m_param->getPipelineConstructionType(), vk, vkDevice, &pipelineLayoutParams);
921     }
922 
923     // Create render pass
924     m_renderPass = makeRenderPass(vk, vkDevice, m_colorFormat, m_depthFormat);
925 
926     // Bind shader stages
927     ShaderWrapper vertShaderModule = ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("color_vert"), 0);
928     ShaderWrapper fragShaderModule = ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("color_frag"), 0);
929     ShaderWrapper tescShaderModule;
930     ShaderWrapper teseShaderModule;
931     ShaderWrapper geomShaderModule;
932 
933     VkShaderStageFlags shaderFlags = m_param->getShaderFlags();
934     if (shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
935         tescShaderModule = ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("basic_tcs"), 0);
936     if (shaderFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
937         teseShaderModule = ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("basic_tes"), 0);
938     if (shaderFlags & VK_SHADER_STAGE_GEOMETRY_BIT)
939         geomShaderModule = ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("dummy_geo"), 0);
940 
941     for (uint32_t ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
942         preparePipelineWrapper(m_pipelineWrapper[ndx], vertShaderModule, tescShaderModule, teseShaderModule,
943                                geomShaderModule, fragShaderModule);
944 }
945 
~GraphicsExecutablePropertiesTestInstance(void)946 GraphicsExecutablePropertiesTestInstance::~GraphicsExecutablePropertiesTestInstance(void)
947 {
948 }
949 
preparePipelineWrapper(GraphicsPipelineWrapper & gpw,ShaderWrapper vertShaderModule,ShaderWrapper tescShaderModule,ShaderWrapper teseShaderModule,ShaderWrapper geomShaderModule,ShaderWrapper fragShaderModule)950 void GraphicsExecutablePropertiesTestInstance::preparePipelineWrapper(
951     GraphicsPipelineWrapper &gpw, ShaderWrapper vertShaderModule, ShaderWrapper tescShaderModule,
952     ShaderWrapper teseShaderModule, ShaderWrapper geomShaderModule, ShaderWrapper fragShaderModule)
953 {
954     // Create pipeline
955     const VkVertexInputBindingDescription vertexInputBindingDescription = {
956         0u,                          // uint32_t binding;
957         sizeof(Vertex4RGBA),         // uint32_t strideInBytes;
958         VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
959     };
960 
961     const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = {
962         {
963             0u,                            // uint32_t location;
964             0u,                            // uint32_t binding;
965             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
966             0u                             // uint32_t offsetInBytes;
967         },
968         {
969             1u,                            // uint32_t location;
970             0u,                            // uint32_t binding;
971             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
972             offsetof(Vertex4RGBA, color),  // uint32_t offsetInBytes;
973         }};
974 
975     const VkPipelineVertexInputStateCreateInfo vertexInputStateParams{
976         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
977         DE_NULL,                                                   // const void* pNext;
978         0u,                                                        // VkPipelineVertexInputStateCreateFlags flags;
979         1u,                                                        // uint32_t vertexBindingDescriptionCount;
980         &vertexInputBindingDescription,   // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
981         2u,                               // uint32_t vertexAttributeDescriptionCount;
982         vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
983     };
984 
985     const std::vector<VkViewport> viewport{makeViewport(m_renderSize)};
986     const std::vector<VkRect2D> scissor{makeRect2D(m_renderSize)};
987 
988     const VkPipelineColorBlendAttachmentState colorBlendAttachmentState{
989         VK_FALSE,             // VkBool32 blendEnable;
990         VK_BLEND_FACTOR_ONE,  // VkBlendFactor srcColorBlendFactor;
991         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
992         VK_BLEND_OP_ADD,      // VkBlendOp colorBlendOp;
993         VK_BLEND_FACTOR_ONE,  // VkBlendFactor srcAlphaBlendFactor;
994         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
995         VK_BLEND_OP_ADD,      // VkBlendOp alphaBlendOp;
996         VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
997             VK_COLOR_COMPONENT_A_BIT // VkColorComponentFlags    colorWriteMask;
998     };
999 
1000     const VkPipelineColorBlendStateCreateInfo colorBlendStateParams{
1001         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
1002         DE_NULL,                                                  // const void* pNext;
1003         0u,                                                       // VkPipelineColorBlendStateCreateFlags flags;
1004         VK_FALSE,                                                 // VkBool32 logicOpEnable;
1005         VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
1006         1u,                                                       // uint32_t attachmentCount;
1007         &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
1008         {0.0f, 0.0f, 0.0f, 0.0f},   // float blendConst[4];
1009     };
1010 
1011     VkPipelineDepthStencilStateCreateInfo depthStencilStateParams{
1012         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
1013         DE_NULL,                                                    // const void* pNext;
1014         0u,                                                         // VkPipelineDepthStencilStateCreateFlags flags;
1015         VK_TRUE,                                                    // VkBool32 depthTestEnable;
1016         VK_TRUE,                                                    // VkBool32 depthWriteEnable;
1017         VK_COMPARE_OP_LESS_OR_EQUAL,                                // VkCompareOp depthCompareOp;
1018         VK_FALSE,                                                   // VkBool32 depthBoundsTestEnable;
1019         VK_FALSE,                                                   // VkBool32 stencilTestEnable;
1020         // VkStencilOpState front;
1021         {
1022             VK_STENCIL_OP_KEEP,  // VkStencilOp failOp;
1023             VK_STENCIL_OP_KEEP,  // VkStencilOp passOp;
1024             VK_STENCIL_OP_KEEP,  // VkStencilOp depthFailOp;
1025             VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
1026             0u,                  // uint32_t compareMask;
1027             0u,                  // uint32_t writeMask;
1028             0u,                  // uint32_t reference;
1029         },
1030         // VkStencilOpState back;
1031         {
1032             VK_STENCIL_OP_KEEP,  // VkStencilOp failOp;
1033             VK_STENCIL_OP_KEEP,  // VkStencilOp passOp;
1034             VK_STENCIL_OP_KEEP,  // VkStencilOp depthFailOp;
1035             VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
1036             0u,                  // uint32_t compareMask;
1037             0u,                  // uint32_t writeMask;
1038             0u,                  // uint32_t reference;
1039         },
1040         0.0f, // float minDepthBounds;
1041         1.0f, // float maxDepthBounds;
1042     };
1043 
1044     gpw.setDefaultTopology((!tescShaderModule.isSet()) ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST :
1045                                                          VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)
1046         .setDefaultRasterizationState()
1047         .setDefaultMultisampleState()
1048         .setupVertexInputState(&vertexInputStateParams)
1049         .setupPreRasterizationShaderState(viewport, scissor, m_pipelineLayout, *m_renderPass, 0u, vertShaderModule,
1050                                           DE_NULL, tescShaderModule, teseShaderModule, geomShaderModule)
1051         .setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, fragShaderModule, &depthStencilStateParams)
1052         .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams)
1053         .setMonolithicPipelineLayout(m_pipelineLayout)
1054         .buildPipeline(*m_cache);
1055 }
1056 
1057 class ComputeExecutablePropertiesTest : public ExecutablePropertiesTest
1058 {
1059 public:
ComputeExecutablePropertiesTest(tcu::TestContext & testContext,const std::string & name,const ExecutablePropertiesTestParam * param)1060     ComputeExecutablePropertiesTest(tcu::TestContext &testContext, const std::string &name,
1061                                     const ExecutablePropertiesTestParam *param)
1062         : ExecutablePropertiesTest(testContext, name, param)
1063     {
1064     }
~ComputeExecutablePropertiesTest(void)1065     virtual ~ComputeExecutablePropertiesTest(void)
1066     {
1067     }
1068     virtual void initPrograms(SourceCollections &programCollection) const;
1069     virtual TestInstance *createInstance(Context &context) const;
1070 };
1071 
1072 class ComputeExecutablePropertiesTestInstance : public ExecutablePropertiesTestInstance
1073 {
1074 public:
1075     ComputeExecutablePropertiesTestInstance(Context &context, const ExecutablePropertiesTestParam *param);
1076     virtual ~ComputeExecutablePropertiesTestInstance(void);
1077 
1078 protected:
1079     void buildDescriptorSets(uint32_t ndx);
1080     void buildShader(uint32_t ndx);
1081     void buildPipeline(uint32_t ndx);
1082 
1083 protected:
1084     Move<VkBuffer> m_inputBuf;
1085     de::MovePtr<Allocation> m_inputBufferAlloc;
1086     Move<VkShaderModule> m_computeShaderModule[PIPELINE_CACHE_NDX_COUNT];
1087 
1088     Move<VkBuffer> m_outputBuf[PIPELINE_CACHE_NDX_COUNT];
1089     de::MovePtr<Allocation> m_outputBufferAlloc[PIPELINE_CACHE_NDX_COUNT];
1090 
1091     Move<VkDescriptorPool> m_descriptorPool[PIPELINE_CACHE_NDX_COUNT];
1092     Move<VkDescriptorSetLayout> m_descriptorSetLayout[PIPELINE_CACHE_NDX_COUNT];
1093     Move<VkDescriptorSet> m_descriptorSet[PIPELINE_CACHE_NDX_COUNT];
1094 
1095     Move<VkPipelineLayout> m_pipelineLayout[PIPELINE_CACHE_NDX_COUNT];
1096 };
1097 
initPrograms(SourceCollections & programCollection) const1098 void ComputeExecutablePropertiesTest::initPrograms(SourceCollections &programCollection) const
1099 {
1100     programCollection.glslSources.add("basic_compute") << glu::ComputeSource(
1101         "#version 310 es\n"
1102         "layout(local_size_x = 1) in;\n"
1103         "layout(std430) buffer;\n"
1104         "layout(binding = 0) readonly buffer Input0\n"
1105         "{\n"
1106         "  vec4 elements[];\n"
1107         "} input_data0;\n"
1108         "layout(binding = 1) writeonly buffer Output\n"
1109         "{\n"
1110         "  vec4 elements[];\n"
1111         "} output_data;\n"
1112         "void main()\n"
1113         "{\n"
1114         "  uint ident = gl_GlobalInvocationID.x;\n"
1115         "  output_data.elements[ident] = input_data0.elements[ident] * input_data0.elements[ident];\n"
1116         "}");
1117 }
1118 
createInstance(Context & context) const1119 TestInstance *ComputeExecutablePropertiesTest::createInstance(Context &context) const
1120 {
1121     return new ComputeExecutablePropertiesTestInstance(context, &m_param);
1122 }
1123 
buildDescriptorSets(uint32_t ndx)1124 void ComputeExecutablePropertiesTestInstance::buildDescriptorSets(uint32_t ndx)
1125 {
1126     const DeviceInterface &vk = m_context.getDeviceInterface();
1127     const VkDevice vkDevice   = m_context.getDevice();
1128 
1129     // Create descriptor set layout
1130     DescriptorSetLayoutBuilder descLayoutBuilder;
1131     for (uint32_t bindingNdx = 0u; bindingNdx < 2u; bindingNdx++)
1132         descLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
1133     m_descriptorSetLayout[ndx] = descLayoutBuilder.build(vk, vkDevice);
1134 }
1135 
buildShader(uint32_t ndx)1136 void ComputeExecutablePropertiesTestInstance::buildShader(uint32_t ndx)
1137 {
1138     const DeviceInterface &vk = m_context.getDeviceInterface();
1139     const VkDevice vkDevice   = m_context.getDevice();
1140 
1141     // Create compute shader
1142     VkShaderModuleCreateInfo shaderModuleCreateInfo = {
1143         VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,                    // VkStructureType sType;
1144         DE_NULL,                                                        // const void* pNext;
1145         0u,                                                             // VkShaderModuleCreateFlags flags;
1146         m_context.getBinaryCollection().get("basic_compute").getSize(), // uintptr_t codeSize;
1147         (uint32_t *)m_context.getBinaryCollection().get("basic_compute").getBinary(), // const uint32_t* pCode;
1148     };
1149     m_computeShaderModule[ndx] = createShaderModule(vk, vkDevice, &shaderModuleCreateInfo);
1150 }
1151 
buildPipeline(uint32_t ndx)1152 void ComputeExecutablePropertiesTestInstance::buildPipeline(uint32_t ndx)
1153 {
1154     const DeviceInterface &vk = m_context.getDeviceInterface();
1155     const VkDevice vkDevice   = m_context.getDevice();
1156 
1157     // Create compute pipeline layout
1158     const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
1159         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1160         DE_NULL,                                       // const void* pNext;
1161         0u,                                            // VkPipelineLayoutCreateFlags flags;
1162         1u,                                            // uint32_t setLayoutCount;
1163         &m_descriptorSetLayout[ndx].get(),             // const VkDescriptorSetLayout* pSetLayouts;
1164         0u,                                            // uint32_t pushConstantRangeCount;
1165         DE_NULL,                                       // const VkPushConstantRange* pPushConstantRanges;
1166     };
1167 
1168     m_pipelineLayout[ndx] = createPipelineLayout(vk, vkDevice, &pipelineLayoutCreateInfo);
1169 
1170     const VkPipelineShaderStageCreateInfo stageCreateInfo = {
1171         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1172         DE_NULL,                                             // const void* pNext;
1173         0u,                                                  // VkPipelineShaderStageCreateFlags flags;
1174         VK_SHADER_STAGE_COMPUTE_BIT,                         // VkShaderStageFlagBits stage;
1175         *m_computeShaderModule[ndx],                         // VkShaderModule module;
1176         "main",                                              // const char* pName;
1177         DE_NULL,                                             // const VkSpecializationInfo* pSpecializationInfo;
1178     };
1179 
1180     VkPipelineCreateFlags flags = 0;
1181     if (m_param->getTestStatistics())
1182     {
1183         flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
1184     }
1185 
1186     // Only check gather internal representations on the second
1187     // pipeline.  This way, it's more obvious if they failed to capture
1188     // due to the pipeline being cached.
1189     if (ndx == PIPELINE_CACHE_NDX_CACHED && m_param->getTestInternalRepresentations())
1190     {
1191         flags |= VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR;
1192     }
1193 
1194     const VkComputePipelineCreateInfo pipelineCreateInfo = {
1195         VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
1196         DE_NULL,                                        // const void* pNext;
1197         flags,                                          // VkPipelineCreateFlags flags;
1198         stageCreateInfo,                                // VkPipelineShaderStageCreateInfo stage;
1199         *m_pipelineLayout[ndx],                         // VkPipelineLayout layout;
1200         (VkPipeline)0,                                  // VkPipeline basePipelineHandle;
1201         0u,                                             // int32_t basePipelineIndex;
1202     };
1203 
1204     m_pipeline[ndx] = createComputePipeline(vk, vkDevice, *m_cache, &pipelineCreateInfo, DE_NULL);
1205 }
1206 
ComputeExecutablePropertiesTestInstance(Context & context,const ExecutablePropertiesTestParam * param)1207 ComputeExecutablePropertiesTestInstance::ComputeExecutablePropertiesTestInstance(
1208     Context &context, const ExecutablePropertiesTestParam *param)
1209     : ExecutablePropertiesTestInstance(context, param)
1210 {
1211     for (uint32_t ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++)
1212     {
1213         buildDescriptorSets(ndx);
1214         buildShader(ndx);
1215         buildPipeline(ndx);
1216     }
1217 }
1218 
~ComputeExecutablePropertiesTestInstance(void)1219 ComputeExecutablePropertiesTestInstance::~ComputeExecutablePropertiesTestInstance(void)
1220 {
1221 }
1222 
1223 } // namespace
1224 
createExecutablePropertiesTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1225 tcu::TestCaseGroup *createExecutablePropertiesTests(tcu::TestContext &testCtx,
1226                                                     PipelineConstructionType pipelineConstructionType)
1227 {
1228 
1229     de::MovePtr<tcu::TestCaseGroup> binaryInfoTests(new tcu::TestCaseGroup(testCtx, "executable_properties"));
1230 
1231     // Graphics Pipeline Tests
1232     {
1233         de::MovePtr<tcu::TestCaseGroup> graphicsTests(new tcu::TestCaseGroup(testCtx, "graphics"));
1234 
1235         const VkShaderStageFlags vertFragStages     = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
1236         const VkShaderStageFlags vertGeomFragStages = vertFragStages | VK_SHADER_STAGE_GEOMETRY_BIT;
1237         const VkShaderStageFlags vertTessFragStages =
1238             vertFragStages | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
1239 
1240         const ExecutablePropertiesTestParam testParams[]{
1241             {pipelineConstructionType, vertFragStages, false, false},
1242             {pipelineConstructionType, vertGeomFragStages, false, false},
1243             {pipelineConstructionType, vertTessFragStages, false, false},
1244             {pipelineConstructionType, vertFragStages, true, false},
1245             {pipelineConstructionType, vertGeomFragStages, true, false},
1246             {pipelineConstructionType, vertTessFragStages, true, false},
1247             {pipelineConstructionType, vertFragStages, false, true},
1248             {pipelineConstructionType, vertGeomFragStages, false, true},
1249             {pipelineConstructionType, vertTessFragStages, false, true},
1250             {pipelineConstructionType, vertFragStages, true, true},
1251             {pipelineConstructionType, vertGeomFragStages, true, true},
1252             {pipelineConstructionType, vertTessFragStages, true, true},
1253         };
1254 
1255         for (uint32_t i = 0; i < DE_LENGTH_OF_ARRAY(testParams); i++)
1256             graphicsTests->addChild(newTestCase<GraphicsExecutablePropertiesTest>(testCtx, &testParams[i]));
1257 
1258         binaryInfoTests->addChild(graphicsTests.release());
1259     }
1260 
1261     // Compute Pipeline Tests - don't repeat those tests for graphics pipeline library
1262     if (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
1263     {
1264         de::MovePtr<tcu::TestCaseGroup> computeTests(new tcu::TestCaseGroup(testCtx, "compute"));
1265 
1266         const ExecutablePropertiesTestParam testParams[]{
1267             {pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, false, false},
1268             {pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, true, false},
1269             {pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, false, true},
1270             {pipelineConstructionType, VK_SHADER_STAGE_COMPUTE_BIT, true, true},
1271         };
1272 
1273         for (uint32_t i = 0; i < DE_LENGTH_OF_ARRAY(testParams); i++)
1274             computeTests->addChild(newTestCase<ComputeExecutablePropertiesTest>(testCtx, &testParams[i]));
1275 
1276         binaryInfoTests->addChild(computeTests.release());
1277     }
1278 
1279     return binaryInfoTests.release();
1280 }
1281 
1282 } // namespace pipeline
1283 
1284 } // namespace vkt
1285