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