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