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