1 /*-------------------------------------------------------------------------
2 * Vulkan CTS Framework
3 * --------------------
4 *
5 * Copyright (c) 2021 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Defines class for handling resources ( programs, pipelines, files, etc. )
22 *//*--------------------------------------------------------------------*/
23
24 #include "vkResourceInterface.hpp"
25 #include "vkQueryUtil.hpp"
26
27 #ifdef CTS_USES_VULKANSC
28 #include <functional>
29 #include <fstream>
30 #include "vkSafetyCriticalUtil.hpp"
31 #include "vkRefUtil.hpp"
32 #include "tcuCommandLine.hpp"
33 #include "vksCacheBuilder.hpp"
34 #include "vksSerializer.hpp"
35 #include "vkApiVersion.hpp"
36 using namespace vksc_server::json;
37 #endif // CTS_USES_VULKANSC
38
39 namespace vk
40 {
41
ResourceInterface(tcu::TestContext & testCtx)42 ResourceInterface::ResourceInterface(tcu::TestContext &testCtx)
43 : m_testCtx(testCtx)
44 #ifdef CTS_USES_VULKANSC
45 , m_commandPoolIndex(0u)
46 , m_resourceCounter(0u)
47 , m_statCurrent(resetDeviceObjectReservationCreateInfo())
48 , m_statMax(resetDeviceObjectReservationCreateInfo())
49 , m_enabledHandleDestroy(true)
50 #endif // CTS_USES_VULKANSC
51 {
52 #ifdef CTS_USES_VULKANSC
53 // pipelineCacheRequestCount does not contain one instance of createPipelineCache call that happens only in subprocess
54 m_statCurrent.pipelineCacheRequestCount = 1u;
55 m_statMax.pipelineCacheRequestCount = 1u;
56 #endif // CTS_USES_VULKANSC
57 }
58
~ResourceInterface()59 ResourceInterface::~ResourceInterface()
60 {
61 }
62
initTestCase(const std::string & casePath)63 void ResourceInterface::initTestCase(const std::string &casePath)
64 {
65 m_currentTestPath = casePath;
66 }
67
getCasePath() const68 const std::string &ResourceInterface::getCasePath() const
69 {
70 return m_currentTestPath;
71 }
72
73 #ifdef CTS_USES_VULKANSC
initApiVersion(const uint32_t version)74 void ResourceInterface::initApiVersion(const uint32_t version)
75 {
76 const ApiVersion apiVersion = unpackVersion(version);
77 const bool vulkanSC = (apiVersion.variantNum == 1);
78
79 m_version = tcu::Maybe<uint32_t>(version);
80 m_vulkanSC = vulkanSC;
81 }
82
isVulkanSC(void) const83 bool ResourceInterface::isVulkanSC(void) const
84 {
85 return m_vulkanSC.get();
86 }
87
getStatMutex()88 std::mutex &ResourceInterface::getStatMutex()
89 {
90 return m_mutex;
91 }
92
getStatCurrent()93 VkDeviceObjectReservationCreateInfo &ResourceInterface::getStatCurrent()
94 {
95 return m_statCurrent;
96 }
97
getStatMax()98 VkDeviceObjectReservationCreateInfo &ResourceInterface::getStatMax()
99 {
100 return m_statMax;
101 }
102
getStatMax() const103 const VkDeviceObjectReservationCreateInfo &ResourceInterface::getStatMax() const
104 {
105 return m_statMax;
106 }
107
setHandleDestroy(bool value)108 void ResourceInterface::setHandleDestroy(bool value)
109 {
110 m_enabledHandleDestroy = value;
111 }
112
isEnabledHandleDestroy() const113 bool ResourceInterface::isEnabledHandleDestroy() const
114 {
115 return m_enabledHandleDestroy;
116 }
117
removeRedundantObjects()118 void ResourceInterface::removeRedundantObjects()
119 {
120 // At the end of the day we only need to export objects used in pipelines.
121 // Rest of the objects may be removed from m_json* structures as redundant
122 std::set<VkSamplerYcbcrConversion> samplerYcbcrConversionsInPipeline;
123 std::set<VkSampler> samplersInPipeline;
124 std::set<VkShaderModule> shadersInPipeline;
125 std::set<VkRenderPass> renderPassesInPipeline;
126 std::set<VkPipelineLayout> pipelineLayoutsInPipeline;
127 std::set<VkDescriptorSetLayout> descriptorSetLayoutsInPipeline;
128
129 Context jsonReader;
130
131 for (auto it = begin(m_pipelineInput.pipelines); it != end(m_pipelineInput.pipelines); ++it)
132 {
133 if (it->pipelineContents.find("VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO") != std::string::npos)
134 {
135 VkGraphicsPipelineCreateInfo gpCI;
136 deMemset(&gpCI, 0, sizeof(gpCI));
137 readJSON_VkGraphicsPipelineCreateInfo(jsonReader, it->pipelineContents, gpCI);
138
139 for (uint32_t i = 0; i < gpCI.stageCount; ++i)
140 shadersInPipeline.insert(gpCI.pStages[i].module);
141 renderPassesInPipeline.insert(gpCI.renderPass);
142 pipelineLayoutsInPipeline.insert(gpCI.layout);
143 }
144 else if (it->pipelineContents.find("VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO") != std::string::npos)
145 {
146 VkComputePipelineCreateInfo cpCI;
147 deMemset(&cpCI, 0, sizeof(cpCI));
148 readJSON_VkComputePipelineCreateInfo(jsonReader, it->pipelineContents, cpCI);
149
150 shadersInPipeline.insert(cpCI.stage.module);
151 pipelineLayoutsInPipeline.insert(cpCI.layout);
152 }
153 else
154 TCU_THROW(InternalError, "Could not recognize pipeline type");
155 }
156 for (auto it = begin(m_pipelineInput.shaderModules); it != end(m_pipelineInput.shaderModules);)
157 {
158 if (shadersInPipeline.find(it->first) == end(shadersInPipeline))
159 it = m_pipelineInput.shaderModules.erase(it);
160 else
161 ++it;
162 }
163 for (auto it = begin(m_pipelineInput.renderPasses); it != end(m_pipelineInput.renderPasses);)
164 {
165 if (renderPassesInPipeline.find(it->first) == end(renderPassesInPipeline))
166 it = m_pipelineInput.renderPasses.erase(it);
167 else
168 ++it;
169 }
170 for (auto it = begin(m_pipelineInput.pipelineLayouts); it != end(m_pipelineInput.pipelineLayouts);)
171 {
172 if (pipelineLayoutsInPipeline.find(it->first) == end(pipelineLayoutsInPipeline))
173 {
174 it = m_pipelineInput.pipelineLayouts.erase(it);
175 }
176 else
177 {
178 VkPipelineLayoutCreateInfo plCI;
179 deMemset(&plCI, 0, sizeof(plCI));
180 readJSON_VkPipelineLayoutCreateInfo(jsonReader, it->second, plCI);
181 for (uint32_t i = 0; i < plCI.setLayoutCount; ++i)
182 descriptorSetLayoutsInPipeline.insert(plCI.pSetLayouts[i]);
183 ++it;
184 }
185 }
186 for (auto it = begin(m_pipelineInput.descriptorSetLayouts); it != end(m_pipelineInput.descriptorSetLayouts);)
187 {
188 if (descriptorSetLayoutsInPipeline.find(it->first) == end(descriptorSetLayoutsInPipeline))
189 it = m_pipelineInput.descriptorSetLayouts.erase(it);
190 else
191 {
192 VkDescriptorSetLayoutCreateInfo dsCI;
193 deMemset(&dsCI, 0, sizeof(dsCI));
194 readJSON_VkDescriptorSetLayoutCreateInfo(jsonReader, it->second, dsCI);
195
196 for (uint32_t i = 0; i < dsCI.bindingCount; ++i)
197 {
198 if (dsCI.pBindings[i].pImmutableSamplers == NULL)
199 continue;
200 for (uint32_t j = 0; j < dsCI.pBindings[i].descriptorCount; ++j)
201 {
202 if (dsCI.pBindings[i].pImmutableSamplers[j] == VK_NULL_HANDLE)
203 continue;
204 samplersInPipeline.insert(dsCI.pBindings[i].pImmutableSamplers[j]);
205 }
206 }
207 ++it;
208 }
209 }
210
211 for (auto it = begin(m_pipelineInput.samplers); it != end(m_pipelineInput.samplers);)
212 {
213 if (samplersInPipeline.find(it->first) == end(samplersInPipeline))
214 it = m_pipelineInput.samplers.erase(it);
215 else
216 {
217 VkSamplerCreateInfo sCI;
218 deMemset(&sCI, 0, sizeof(sCI));
219 readJSON_VkSamplerCreateInfo(jsonReader, it->second, sCI);
220
221 if (sCI.pNext != nullptr)
222 {
223 VkSamplerYcbcrConversionInfo *info = (VkSamplerYcbcrConversionInfo *)(sCI.pNext);
224 if (info->sType == VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO)
225 samplerYcbcrConversionsInPipeline.insert(info->conversion);
226 }
227 ++it;
228 }
229 }
230 for (auto it = begin(m_pipelineInput.samplerYcbcrConversions); it != end(m_pipelineInput.samplerYcbcrConversions);)
231 {
232 if (samplerYcbcrConversionsInPipeline.find(it->first) == end(samplerYcbcrConversionsInPipeline))
233 it = m_pipelineInput.samplerYcbcrConversions.erase(it);
234 else
235 ++it;
236 }
237 }
238
finalizeCommandBuffers()239 void ResourceInterface::finalizeCommandBuffers()
240 {
241 // We have information about command buffer sizes
242 // Now we have to convert it into command pool sizes
243 std::map<uint64_t, std::size_t> cpToIndex;
244 for (std::size_t i = 0; i < m_commandPoolMemoryConsumption.size(); ++i)
245 cpToIndex.insert({m_commandPoolMemoryConsumption[i].commandPool, i});
246 for (const auto &memC : m_commandBufferMemoryConsumption)
247 {
248 std::size_t j = cpToIndex[memC.second.commandPool];
249 m_commandPoolMemoryConsumption[j].updateValues(memC.second.maxCommandPoolAllocated,
250 memC.second.maxCommandPoolReservedSize,
251 memC.second.maxCommandBufferAllocated);
252 m_commandPoolMemoryConsumption[j].commandBufferCount++;
253 }
254 // Each m_commandPoolMemoryConsumption element must have at least one command buffer ( see DeviceDriverSC::createCommandPoolHandlerNorm() )
255 // As a result we have to ensure that commandBufferRequestCount is not less than the number of command pools
256 m_statMax.commandBufferRequestCount =
257 de::max(uint32_t(m_commandPoolMemoryConsumption.size()), m_statMax.commandBufferRequestCount);
258 }
259
exportData() const260 std::vector<uint8_t> ResourceInterface::exportData() const
261 {
262 vksc_server::VulkanDataTransmittedFromMainToSubprocess vdtfmtsp(m_pipelineInput, m_statMax,
263 m_commandPoolMemoryConsumption, m_pipelineSizes);
264
265 return vksc_server::Serialize(vdtfmtsp);
266 }
267
importData(std::vector<uint8_t> & importText) const268 void ResourceInterface::importData(std::vector<uint8_t> &importText) const
269 {
270 vksc_server::VulkanDataTransmittedFromMainToSubprocess vdtfmtsp =
271 vksc_server::Deserialize<vksc_server::VulkanDataTransmittedFromMainToSubprocess>(importText);
272
273 m_pipelineInput = vdtfmtsp.pipelineCacheInput;
274 m_statMax = vdtfmtsp.memoryReservation;
275 m_commandPoolMemoryConsumption = vdtfmtsp.commandPoolMemoryConsumption;
276 m_pipelineSizes = vdtfmtsp.pipelineSizes;
277 }
278
registerObjectHash(uint64_t handle,std::size_t hashValue) const279 void ResourceInterface::registerObjectHash(uint64_t handle, std::size_t hashValue) const
280 {
281 m_objectHashes[handle] = hashValue;
282 }
283
getObjectHashes() const284 const std::map<uint64_t, std::size_t> &ResourceInterface::getObjectHashes() const
285 {
286 return m_objectHashes;
287 }
288
289 struct PipelinePoolSizeInfo
290 {
291 uint32_t maxTestCount;
292 uint32_t size;
293 };
294
preparePipelinePoolSizes()295 void ResourceInterface::preparePipelinePoolSizes()
296 {
297 std::map<std::string, std::vector<PipelinePoolSizeInfo>> pipelineInfoPerTest;
298
299 // Step 1: collect information about all pipelines in each test, group by size
300 for (const auto &pipeline : m_pipelineInput.pipelines)
301 {
302 auto it = std::find_if(begin(m_pipelineSizes), end(m_pipelineSizes),
303 vksc_server::PipelineIdentifierEqual(pipeline.id));
304 if (it == end(m_pipelineSizes))
305 TCU_THROW(InternalError, "VkPipelinePoolEntrySizeCreateInfo not created for pipelineIdentifier");
306
307 PipelinePoolSizeInfo ppsi{it->count, it->size};
308
309 for (const auto &test : pipeline.tests)
310 {
311 auto pit = pipelineInfoPerTest.find(test);
312 if (pit == end(pipelineInfoPerTest))
313 pit = pipelineInfoPerTest.insert({test, std::vector<PipelinePoolSizeInfo>()}).first;
314 // group by the same sizes in a test
315 bool found = false;
316 for (size_t i = 0; i < pit->second.size(); ++i)
317 {
318 if (pit->second[i].size == ppsi.size)
319 {
320 pit->second[i].maxTestCount += ppsi.maxTestCount;
321 found = true;
322 break;
323 }
324 }
325 if (!found)
326 pit->second.push_back(ppsi);
327 }
328 }
329
330 // Step 2: choose pipeline pool sizes
331 std::vector<PipelinePoolSizeInfo> finalPoolSizes;
332 for (const auto &pInfo : pipelineInfoPerTest)
333 {
334 for (const auto &ppsi1 : pInfo.second)
335 {
336 auto it = std::find_if(begin(finalPoolSizes), end(finalPoolSizes),
337 [&ppsi1](const PipelinePoolSizeInfo &x) { return (x.size == ppsi1.size); });
338 if (it != end(finalPoolSizes))
339 it->maxTestCount = de::max(it->maxTestCount, ppsi1.maxTestCount);
340 else
341 finalPoolSizes.push_back(ppsi1);
342 }
343 }
344
345 // Step 3: convert results to VkPipelinePoolSize
346 m_pipelinePoolSizes.clear();
347 for (const auto &ppsi : finalPoolSizes)
348 {
349 VkPipelinePoolSize poolSize = {
350 VK_STRUCTURE_TYPE_PIPELINE_POOL_SIZE, // VkStructureType sType;
351 nullptr, // const void* pNext;
352 ppsi.size, // VkDeviceSize poolEntrySize;
353 ppsi.maxTestCount // uint32_t poolEntryCount;
354 };
355 m_pipelinePoolSizes.emplace_back(poolSize);
356 }
357 }
358
getPipelinePoolSizes() const359 std::vector<VkPipelinePoolSize> ResourceInterface::getPipelinePoolSizes() const
360 {
361 return m_pipelinePoolSizes;
362 }
363
fillPoolEntrySize(vk::VkPipelineOfflineCreateInfo & pipelineIdentifier) const364 void ResourceInterface::fillPoolEntrySize(vk::VkPipelineOfflineCreateInfo &pipelineIdentifier) const
365 {
366 auto it = std::find_if(begin(m_pipelineSizes), end(m_pipelineSizes),
367 vksc_server::PipelineIdentifierEqual(pipelineIdentifier));
368 if (it == end(m_pipelineSizes))
369 TCU_THROW(InternalError, "VkPipelinePoolEntrySizeCreateInfo not created for pipelineIdentifier");
370 pipelineIdentifier.poolEntrySize = it->size;
371 }
372
getNextCommandPoolSize()373 vksc_server::VulkanCommandMemoryConsumption ResourceInterface::getNextCommandPoolSize()
374 {
375 if (m_commandPoolMemoryConsumption.empty())
376 return vksc_server::VulkanCommandMemoryConsumption();
377
378 vksc_server::VulkanCommandMemoryConsumption result = m_commandPoolMemoryConsumption[m_commandPoolIndex];
379 // modulo operation is just a safeguard against excessive number of requests
380 m_commandPoolIndex = (m_commandPoolIndex + 1) % uint32_t(m_commandPoolMemoryConsumption.size());
381 return result;
382 }
383
getCacheDataSize() const384 std::size_t ResourceInterface::getCacheDataSize() const
385 {
386 return m_cacheData.size();
387 }
388
getCacheData() const389 const uint8_t *ResourceInterface::getCacheData() const
390 {
391 return m_cacheData.data();
392 }
393
getPipelineCache(VkDevice device) const394 VkPipelineCache ResourceInterface::getPipelineCache(VkDevice device) const
395 {
396 auto pit = m_pipelineCache.find(device);
397 if (pit == end(m_pipelineCache))
398 TCU_THROW(InternalError, "m_pipelineCache not found for this device");
399 return pit->second.get()->get();
400 }
401
402 #endif // CTS_USES_VULKANSC
403
ResourceInterfaceStandard(tcu::TestContext & testCtx)404 ResourceInterfaceStandard::ResourceInterfaceStandard(tcu::TestContext &testCtx) : ResourceInterface(testCtx)
405 {
406 }
407
initDevice(DeviceInterface & deviceInterface,VkDevice device)408 void ResourceInterfaceStandard::initDevice(DeviceInterface &deviceInterface, VkDevice device)
409 {
410 // ResourceInterfaceStandard is a class for running VulkanSC tests on normal Vulkan driver.
411 // CTS does not have vkCreateShaderModule function defined for Vulkan SC driver, but we need this function
412 // So ResourceInterfaceStandard class must have its own vkCreateShaderModule function pointer
413 // Moreover - we create additional function pointers for vkCreateGraphicsPipelines, vkCreateComputePipelines, etc.
414 // BTW: although ResourceInterfaceStandard exists in normal Vulkan tests - only initDevice and buildProgram functions are used by Vulkan tests
415 // Other functions are called from within DeviceDriverSC which does not exist in these tests ( DeviceDriver class is used instead )
416 m_createShaderModuleFunc[device] =
417 (CreateShaderModuleFunc)deviceInterface.getDeviceProcAddr(device, "vkCreateShaderModule");
418 m_createGraphicsPipelinesFunc[device] =
419 (CreateGraphicsPipelinesFunc)deviceInterface.getDeviceProcAddr(device, "vkCreateGraphicsPipelines");
420 m_createComputePipelinesFunc[device] =
421 (CreateComputePipelinesFunc)deviceInterface.getDeviceProcAddr(device, "vkCreateComputePipelines");
422 #ifdef CTS_USES_VULKANSC
423 if (m_testCtx.getCommandLine().isSubProcess())
424 {
425 if (m_cacheData.size() > 0)
426 {
427 VkPipelineCacheCreateInfo pCreateInfo = {
428 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
429 nullptr, // const void* pNext;
430 VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
431 VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT, // VkPipelineCacheCreateFlags flags;
432 m_cacheData.size(), // uintptr_t initialDataSize;
433 m_cacheData.data() // const void* pInitialData;
434 };
435 m_pipelineCache[device] = de::SharedPtr<Move<VkPipelineCache>>(
436 new Move<VkPipelineCache>(createPipelineCache(deviceInterface, device, &pCreateInfo, nullptr)));
437 }
438 }
439 #endif // CTS_USES_VULKANSC
440 }
441
deinitDevice(VkDevice device)442 void ResourceInterfaceStandard::deinitDevice(VkDevice device)
443 {
444 #ifdef CTS_USES_VULKANSC
445 if (m_testCtx.getCommandLine().isSubProcess())
446 {
447 m_pipelineCache.erase(device);
448 }
449 #else
450 DE_UNREF(device);
451 #endif // CTS_USES_VULKANSC
452 }
453
454 #ifdef CTS_USES_VULKANSC
455
registerDeviceFeatures(VkDevice device,const VkDeviceCreateInfo * pCreateInfo) const456 void ResourceInterfaceStandard::registerDeviceFeatures(VkDevice device, const VkDeviceCreateInfo *pCreateInfo) const
457 {
458 VkPhysicalDeviceFeatures2 *chainedFeatures = (VkPhysicalDeviceFeatures2 *)findStructureInChain(
459 pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2);
460 if (chainedFeatures != NULL)
461 {
462 m_deviceFeatures[device] = writeJSON_pNextChain(pCreateInfo->pNext);
463 }
464 else
465 {
466 VkPhysicalDeviceFeatures2 deviceFeatures2 = initVulkanStructure();
467 if (pCreateInfo->pEnabledFeatures != NULL)
468 deviceFeatures2.features = *(pCreateInfo->pEnabledFeatures);
469
470 deviceFeatures2.pNext = (void *)pCreateInfo->pNext;
471 m_deviceFeatures[device] = writeJSON_VkPhysicalDeviceFeatures2(deviceFeatures2);
472 }
473
474 std::vector<std::string> extensions;
475 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; ++i)
476 extensions.push_back(pCreateInfo->ppEnabledExtensionNames[i]);
477 m_deviceExtensions[device] = extensions;
478 }
479
unregisterDeviceFeatures(VkDevice device) const480 void ResourceInterfaceStandard::unregisterDeviceFeatures(VkDevice device) const
481 {
482 m_deviceFeatures.erase(device);
483 m_deviceExtensions.erase(device);
484 }
485
createShaderModule(VkDevice device,const VkShaderModuleCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkShaderModule * pShaderModule,bool normalMode) const486 VkResult ResourceInterfaceStandard::createShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
487 const VkAllocationCallbacks *pAllocator,
488 VkShaderModule *pShaderModule, bool normalMode) const
489 {
490 if (normalMode)
491 {
492 if (isVulkanSC())
493 {
494 *pShaderModule = incResourceCounter<VkShaderModule>();
495 registerObjectHash(pShaderModule->getInternal(),
496 calculateShaderModuleHash(*pCreateInfo, getObjectHashes()));
497 return VK_SUCCESS;
498 }
499 else
500 {
501 const auto it = m_createShaderModuleFunc.find(device);
502 if (it != end(m_createShaderModuleFunc))
503 {
504 VkResult result = it->second(device, pCreateInfo, pAllocator, pShaderModule);
505 registerObjectHash(pShaderModule->getInternal(),
506 calculateShaderModuleHash(*pCreateInfo, getObjectHashes()));
507 return result;
508 }
509 TCU_THROW(InternalError, "vkCreateShaderModule not defined");
510 }
511 }
512
513 // main process: store VkShaderModuleCreateInfo in JSON format. Shaders will be sent later for m_pipelineCache creation ( and sent through file to another process )
514 *pShaderModule = incResourceCounter<VkShaderModule>();
515 registerObjectHash(pShaderModule->getInternal(), calculateShaderModuleHash(*pCreateInfo, getObjectHashes()));
516 m_pipelineInput.shaderModules.insert({*pShaderModule, writeJSON_VkShaderModuleCreateInfo(*pCreateInfo)});
517 return VK_SUCCESS;
518 }
519
makeGraphicsPipelineIdentifier(const std::string & testPath,const VkGraphicsPipelineCreateInfo & gpCI,const std::map<uint64_t,std::size_t> & objectHashes)520 VkPipelineOfflineCreateInfo makeGraphicsPipelineIdentifier(const std::string &testPath,
521 const VkGraphicsPipelineCreateInfo &gpCI,
522 const std::map<uint64_t, std::size_t> &objectHashes)
523 {
524 DE_UNREF(testPath);
525 VkPipelineOfflineCreateInfo pipelineID = resetPipelineOfflineCreateInfo();
526 std::size_t hashValue = calculateGraphicsPipelineHash(gpCI, objectHashes);
527 memcpy(pipelineID.pipelineIdentifier, &hashValue, sizeof(std::size_t));
528 return pipelineID;
529 }
530
makeComputePipelineIdentifier(const std::string & testPath,const VkComputePipelineCreateInfo & cpCI,const std::map<uint64_t,std::size_t> & objectHashes)531 VkPipelineOfflineCreateInfo makeComputePipelineIdentifier(const std::string &testPath,
532 const VkComputePipelineCreateInfo &cpCI,
533 const std::map<uint64_t, std::size_t> &objectHashes)
534 {
535 DE_UNREF(testPath);
536 VkPipelineOfflineCreateInfo pipelineID = resetPipelineOfflineCreateInfo();
537 std::size_t hashValue = calculateComputePipelineHash(cpCI, objectHashes);
538 memcpy(pipelineID.pipelineIdentifier, &hashValue, sizeof(std::size_t));
539 return pipelineID;
540 }
541
createGraphicsPipelines(VkDevice device,VkPipelineCache pipelineCache,uint32_t createInfoCount,const VkGraphicsPipelineCreateInfo * pCreateInfos,const VkAllocationCallbacks * pAllocator,VkPipeline * pPipelines,bool normalMode) const542 VkResult ResourceInterfaceStandard::createGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache,
543 uint32_t createInfoCount,
544 const VkGraphicsPipelineCreateInfo *pCreateInfos,
545 const VkAllocationCallbacks *pAllocator,
546 VkPipeline *pPipelines, bool normalMode) const
547 {
548 DE_UNREF(pipelineCache);
549
550 // build pipeline identifiers (if required), make a copy of pCreateInfos
551 std::vector<VkPipelineOfflineCreateInfo> pipelineIDs;
552 std::vector<uint8_t> idInPNextChain;
553 std::vector<VkGraphicsPipelineCreateInfo> pCreateInfoCopies;
554
555 for (uint32_t i = 0; i < createInfoCount; ++i)
556 {
557 pCreateInfoCopies.push_back(pCreateInfos[i]);
558
559 // Check if test added pipeline identifier on its own
560 VkPipelineOfflineCreateInfo *idInfo = (VkPipelineOfflineCreateInfo *)findStructureInChain(
561 pCreateInfos[i].pNext, VK_STRUCTURE_TYPE_PIPELINE_OFFLINE_CREATE_INFO);
562 if (idInfo == nullptr)
563 {
564 pipelineIDs.push_back(
565 makeGraphicsPipelineIdentifier(m_currentTestPath, pCreateInfos[i], getObjectHashes()));
566 idInPNextChain.push_back(0);
567 }
568 else
569 {
570 pipelineIDs.push_back(*idInfo);
571 idInPNextChain.push_back(1);
572 }
573
574 if (normalMode)
575 fillPoolEntrySize(pipelineIDs.back());
576 }
577
578 // reset not used pointers, so that JSON generation does not crash
579 std::vector<VkPipelineViewportStateCreateInfo> viewportStateCopies(createInfoCount);
580 if (!normalMode)
581 {
582 for (uint32_t i = 0; i < createInfoCount; ++i)
583 {
584 bool vertexInputStateRequired = false;
585 bool inputAssemblyStateRequired = false;
586 bool tessellationStateRequired = false;
587 bool viewportStateRequired = false;
588 bool viewportStateViewportsRequired = false;
589 bool viewportStateScissorsRequired = false;
590 bool multiSampleStateRequired = false;
591 bool depthStencilStateRequired = false;
592 bool colorBlendStateRequired = false;
593
594 if (pCreateInfoCopies[i].pStages != nullptr)
595 {
596 for (uint32_t j = 0; j < pCreateInfoCopies[i].stageCount; ++j)
597 {
598 if (pCreateInfoCopies[i].pStages[j].stage == VK_SHADER_STAGE_VERTEX_BIT)
599 {
600 vertexInputStateRequired = true;
601 inputAssemblyStateRequired = true;
602 }
603 if (pCreateInfoCopies[i].pStages[j].stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
604 {
605 tessellationStateRequired = true;
606 }
607 }
608 }
609 if (pCreateInfoCopies[i].pDynamicState != nullptr)
610 {
611 if (pCreateInfoCopies[i].pDynamicState->pDynamicStates != nullptr)
612 for (uint32_t j = 0; j < pCreateInfoCopies[i].pDynamicState->dynamicStateCount; ++j)
613 {
614 if (pCreateInfoCopies[i].pDynamicState->pDynamicStates[j] == VK_DYNAMIC_STATE_VIEWPORT ||
615 pCreateInfoCopies[i].pDynamicState->pDynamicStates[j] ==
616 VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT)
617 {
618 viewportStateRequired = true;
619 viewportStateViewportsRequired = true;
620 }
621 if (pCreateInfoCopies[i].pDynamicState->pDynamicStates[j] == VK_DYNAMIC_STATE_SCISSOR ||
622 pCreateInfoCopies[i].pDynamicState->pDynamicStates[j] ==
623 VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT)
624 {
625 viewportStateRequired = true;
626 viewportStateScissorsRequired = true;
627 }
628 if (pCreateInfoCopies[i].pDynamicState->pDynamicStates[j] ==
629 VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT)
630 viewportStateRequired = true;
631 }
632 }
633 if (pCreateInfoCopies[i].pRasterizationState != nullptr)
634 {
635 if (pCreateInfoCopies[i].pRasterizationState->rasterizerDiscardEnable == VK_FALSE)
636 {
637 viewportStateRequired = true;
638 viewportStateViewportsRequired = true;
639 viewportStateScissorsRequired = true;
640 multiSampleStateRequired = true;
641 depthStencilStateRequired = true;
642 colorBlendStateRequired = true;
643 }
644 }
645 if (pCreateInfoCopies[i].pVertexInputState != nullptr && !vertexInputStateRequired)
646 pCreateInfoCopies[i].pVertexInputState = nullptr;
647 if (pCreateInfoCopies[i].pInputAssemblyState != nullptr && !inputAssemblyStateRequired)
648 pCreateInfoCopies[i].pInputAssemblyState = nullptr;
649 if (pCreateInfoCopies[i].pTessellationState != nullptr && !tessellationStateRequired)
650 pCreateInfoCopies[i].pTessellationState = nullptr;
651 if (pCreateInfoCopies[i].pViewportState != nullptr)
652 {
653 if (viewportStateRequired)
654 {
655 viewportStateCopies[i] = *(pCreateInfoCopies[i].pViewportState);
656 bool exchangeVP = false;
657 if (pCreateInfoCopies[i].pViewportState->pViewports != nullptr && !viewportStateViewportsRequired)
658 {
659 viewportStateCopies[i].pViewports = nullptr;
660 viewportStateCopies[i].viewportCount = 0u;
661 exchangeVP = true;
662 }
663 if (pCreateInfoCopies[i].pViewportState->pScissors != nullptr && !viewportStateScissorsRequired)
664 {
665 viewportStateCopies[i].pScissors = nullptr;
666 viewportStateCopies[i].scissorCount = 0u;
667 exchangeVP = true;
668 }
669 if (exchangeVP)
670 pCreateInfoCopies[i].pViewportState = &(viewportStateCopies[i]);
671 }
672 else
673 pCreateInfoCopies[i].pViewportState = nullptr;
674 }
675 if (pCreateInfoCopies[i].pMultisampleState != nullptr && !multiSampleStateRequired)
676 pCreateInfoCopies[i].pMultisampleState = nullptr;
677 if (pCreateInfoCopies[i].pDepthStencilState != nullptr && !depthStencilStateRequired)
678 pCreateInfoCopies[i].pDepthStencilState = nullptr;
679 if (pCreateInfoCopies[i].pColorBlendState != nullptr && !colorBlendStateRequired)
680 pCreateInfoCopies[i].pColorBlendState = nullptr;
681 }
682 }
683
684 // Include pipelineIdentifiers into pNext chain of pCreateInfoCopies - skip this operation if pipeline identifier was created inside test
685 for (uint32_t i = 0; i < createInfoCount; ++i)
686 {
687 if (idInPNextChain[i] == 0)
688 {
689 pipelineIDs[i].pNext = pCreateInfoCopies[i].pNext;
690 pCreateInfoCopies[i].pNext = &pipelineIDs[i];
691 }
692 }
693
694 // subprocess: load graphics pipelines from OUR m_pipelineCache cache
695 if (normalMode)
696 {
697 const auto it = m_createGraphicsPipelinesFunc.find(device);
698 if (it != end(m_createGraphicsPipelinesFunc))
699 {
700 auto pit = m_pipelineCache.find(device);
701 if (pit != end(m_pipelineCache))
702 {
703 VkPipelineCache pCache = pit->second->get();
704 return it->second(device, pCache, createInfoCount, pCreateInfoCopies.data(), pAllocator, pPipelines);
705 }
706 TCU_THROW(InternalError, "m_pipelineCache not initialized for this device");
707 }
708 TCU_THROW(InternalError, "vkCreateGraphicsPipelines not defined");
709 }
710
711 // main process: store pipelines in JSON format. Pipelines will be sent later for m_pipelineCache creation ( and sent through file to another process )
712 for (uint32_t i = 0; i < createInfoCount; ++i)
713 {
714 m_pipelineIdentifiers.insert({pPipelines[i], pipelineIDs[i]});
715
716 auto it = std::find_if(begin(m_pipelineInput.pipelines), end(m_pipelineInput.pipelines),
717 vksc_server::PipelineIdentifierEqual(pipelineIDs[i]));
718 pipelineIDs[i].pNext = nullptr;
719 if (it == end(m_pipelineInput.pipelines))
720 {
721 const auto &featIt = m_deviceFeatures.find(device);
722 if (featIt == end(m_deviceFeatures))
723 TCU_THROW(InternalError, "Can't find device features for this pipeline");
724 const auto &extIt = m_deviceExtensions.find(device);
725 if (extIt == end(m_deviceExtensions))
726 TCU_THROW(InternalError, "Can't find device extensions for this pipeline");
727
728 m_pipelineInput.pipelines.push_back(vksc_server::VulkanJsonPipelineDescription(
729 pipelineIDs[i], writeJSON_VkGraphicsPipelineCreateInfo(pCreateInfoCopies[i]), featIt->second,
730 extIt->second, m_currentTestPath));
731 }
732 else
733 it->add(m_currentTestPath);
734 }
735 return VK_SUCCESS;
736 }
737
createComputePipelines(VkDevice device,VkPipelineCache pipelineCache,uint32_t createInfoCount,const VkComputePipelineCreateInfo * pCreateInfos,const VkAllocationCallbacks * pAllocator,VkPipeline * pPipelines,bool normalMode) const738 VkResult ResourceInterfaceStandard::createComputePipelines(VkDevice device, VkPipelineCache pipelineCache,
739 uint32_t createInfoCount,
740 const VkComputePipelineCreateInfo *pCreateInfos,
741 const VkAllocationCallbacks *pAllocator,
742 VkPipeline *pPipelines, bool normalMode) const
743 {
744 DE_UNREF(pipelineCache);
745
746 // build pipeline identifiers (if required), make a copy of pCreateInfos
747 std::vector<VkPipelineOfflineCreateInfo> pipelineIDs;
748 std::vector<uint8_t> idInPNextChain;
749 std::vector<VkComputePipelineCreateInfo> pCreateInfoCopies;
750
751 for (uint32_t i = 0; i < createInfoCount; ++i)
752 {
753 pCreateInfoCopies.push_back(pCreateInfos[i]);
754
755 // Check if test added pipeline identifier on its own
756 VkPipelineOfflineCreateInfo *idInfo = (VkPipelineOfflineCreateInfo *)findStructureInChain(
757 pCreateInfos[i].pNext, VK_STRUCTURE_TYPE_PIPELINE_OFFLINE_CREATE_INFO);
758 if (idInfo == nullptr)
759 {
760 pipelineIDs.push_back(makeComputePipelineIdentifier(m_currentTestPath, pCreateInfos[i], getObjectHashes()));
761 idInPNextChain.push_back(0);
762 }
763 else
764 {
765 pipelineIDs.push_back(*idInfo);
766 idInPNextChain.push_back(1);
767 }
768
769 if (normalMode)
770 fillPoolEntrySize(pipelineIDs.back());
771 }
772
773 // Include pipelineIdentifiers into pNext chain of pCreateInfoCopies - skip this operation if pipeline identifier was created inside test
774 for (uint32_t i = 0; i < createInfoCount; ++i)
775 {
776 if (idInPNextChain[i] == 0)
777 {
778 pipelineIDs[i].pNext = pCreateInfoCopies[i].pNext;
779 pCreateInfoCopies[i].pNext = &pipelineIDs[i];
780 }
781 }
782
783 // subprocess: load compute pipelines from OUR pipeline cache
784 if (normalMode)
785 {
786 const auto it = m_createComputePipelinesFunc.find(device);
787 if (it != end(m_createComputePipelinesFunc))
788 {
789 auto pit = m_pipelineCache.find(device);
790 if (pit != end(m_pipelineCache))
791 {
792 VkPipelineCache pCache = pit->second->get();
793 return it->second(device, pCache, createInfoCount, pCreateInfoCopies.data(), pAllocator, pPipelines);
794 }
795 TCU_THROW(InternalError, "m_pipelineCache not initialized for this device");
796 }
797 TCU_THROW(InternalError, "vkCreateComputePipelines not defined");
798 }
799
800 // main process: store pipelines in JSON format. Pipelines will be sent later for m_pipelineCache creation ( and sent through file to another process )
801 for (uint32_t i = 0; i < createInfoCount; ++i)
802 {
803 m_pipelineIdentifiers.insert({pPipelines[i], pipelineIDs[i]});
804
805 auto it = std::find_if(begin(m_pipelineInput.pipelines), end(m_pipelineInput.pipelines),
806 vksc_server::PipelineIdentifierEqual(pipelineIDs[i]));
807 pipelineIDs[i].pNext = nullptr;
808 if (it == end(m_pipelineInput.pipelines))
809 {
810 const auto &featIt = m_deviceFeatures.find(device);
811 if (featIt == end(m_deviceFeatures))
812 TCU_THROW(InternalError, "Can't find device features for this pipeline");
813 const auto &extIt = m_deviceExtensions.find(device);
814 if (extIt == end(m_deviceExtensions))
815 TCU_THROW(InternalError, "Can't find device extensions for this pipeline");
816
817 m_pipelineInput.pipelines.push_back(vksc_server::VulkanJsonPipelineDescription(
818 pipelineIDs[i], writeJSON_VkComputePipelineCreateInfo(pCreateInfoCopies[i]), featIt->second,
819 extIt->second, m_currentTestPath));
820 }
821 else
822 it->add(m_currentTestPath);
823 }
824 return VK_SUCCESS;
825 }
826
destroyPipeline(VkDevice device,VkPipeline pipeline,const VkAllocationCallbacks * pAllocator) const827 void ResourceInterfaceStandard::destroyPipeline(VkDevice device, VkPipeline pipeline,
828 const VkAllocationCallbacks *pAllocator) const
829 {
830 DE_UNREF(device);
831 DE_UNREF(pAllocator);
832
833 auto it = m_pipelineIdentifiers.find(pipeline);
834 if (it == end(m_pipelineIdentifiers))
835 TCU_THROW(InternalError, "Can't find pipeline");
836
837 auto pit = std::find_if(begin(m_pipelineInput.pipelines), end(m_pipelineInput.pipelines),
838 vksc_server::PipelineIdentifierEqual(it->second));
839 if (pit == end(m_pipelineInput.pipelines))
840 TCU_THROW(InternalError, "Can't find pipeline identifier");
841 pit->remove();
842 }
843
createRenderPass(VkDevice device,const VkRenderPassCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkRenderPass * pRenderPass) const844 void ResourceInterfaceStandard::createRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
845 const VkAllocationCallbacks *pAllocator,
846 VkRenderPass *pRenderPass) const
847 {
848 DE_UNREF(device);
849 DE_UNREF(pAllocator);
850 m_pipelineInput.renderPasses.insert({*pRenderPass, writeJSON_VkRenderPassCreateInfo(*pCreateInfo)});
851 }
852
createRenderPass2(VkDevice device,const VkRenderPassCreateInfo2 * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkRenderPass * pRenderPass) const853 void ResourceInterfaceStandard::createRenderPass2(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo,
854 const VkAllocationCallbacks *pAllocator,
855 VkRenderPass *pRenderPass) const
856 {
857 DE_UNREF(device);
858 DE_UNREF(pAllocator);
859 m_pipelineInput.renderPasses.insert({*pRenderPass, writeJSON_VkRenderPassCreateInfo2(*pCreateInfo)});
860 }
861
createPipelineLayout(VkDevice device,const VkPipelineLayoutCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkPipelineLayout * pPipelineLayout) const862 void ResourceInterfaceStandard::createPipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
863 const VkAllocationCallbacks *pAllocator,
864 VkPipelineLayout *pPipelineLayout) const
865 {
866 DE_UNREF(device);
867 DE_UNREF(pAllocator);
868 m_pipelineInput.pipelineLayouts.insert({*pPipelineLayout, writeJSON_VkPipelineLayoutCreateInfo(*pCreateInfo)});
869 }
870
createDescriptorSetLayout(VkDevice device,const VkDescriptorSetLayoutCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDescriptorSetLayout * pSetLayout) const871 void ResourceInterfaceStandard::createDescriptorSetLayout(VkDevice device,
872 const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
873 const VkAllocationCallbacks *pAllocator,
874 VkDescriptorSetLayout *pSetLayout) const
875 {
876 DE_UNREF(device);
877 DE_UNREF(pAllocator);
878 m_pipelineInput.descriptorSetLayouts.insert({*pSetLayout, writeJSON_VkDescriptorSetLayoutCreateInfo(*pCreateInfo)});
879 }
880
createSampler(VkDevice device,const VkSamplerCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSampler * pSampler) const881 void ResourceInterfaceStandard::createSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
882 const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) const
883 {
884 DE_UNREF(device);
885 DE_UNREF(pAllocator);
886 m_pipelineInput.samplers.insert({*pSampler, writeJSON_VkSamplerCreateInfo(*pCreateInfo)});
887 }
888
createSamplerYcbcrConversion(VkDevice device,const VkSamplerYcbcrConversionCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSamplerYcbcrConversion * pYcbcrConversion) const889 void ResourceInterfaceStandard::createSamplerYcbcrConversion(VkDevice device,
890 const VkSamplerYcbcrConversionCreateInfo *pCreateInfo,
891 const VkAllocationCallbacks *pAllocator,
892 VkSamplerYcbcrConversion *pYcbcrConversion) const
893 {
894 DE_UNREF(device);
895 DE_UNREF(pAllocator);
896 m_pipelineInput.samplerYcbcrConversions.insert(
897 {*pYcbcrConversion, writeJSON_VkSamplerYcbcrConversionCreateInfo(*pCreateInfo)});
898 }
899
createCommandPool(VkDevice device,const VkCommandPoolCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkCommandPool * pCommandPool) const900 void ResourceInterfaceStandard::createCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
901 const VkAllocationCallbacks *pAllocator,
902 VkCommandPool *pCommandPool) const
903 {
904 DE_UNREF(device);
905 DE_UNREF(pCreateInfo);
906 DE_UNREF(pAllocator);
907 m_commandPoolMemoryConsumption.push_back(vksc_server::VulkanCommandMemoryConsumption(pCommandPool->getInternal()));
908 }
909
allocateCommandBuffers(VkDevice device,const VkCommandBufferAllocateInfo * pAllocateInfo,VkCommandBuffer * pCommandBuffers) const910 void ResourceInterfaceStandard::allocateCommandBuffers(VkDevice device,
911 const VkCommandBufferAllocateInfo *pAllocateInfo,
912 VkCommandBuffer *pCommandBuffers) const
913 {
914 DE_UNREF(device);
915 for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; ++i)
916 {
917 m_commandBufferMemoryConsumption.insert({pCommandBuffers[i], vksc_server::VulkanCommandMemoryConsumption(
918 pAllocateInfo->commandPool.getInternal())});
919 }
920 }
921
increaseCommandBufferSize(VkCommandBuffer commandBuffer,VkDeviceSize commandSize) const922 void ResourceInterfaceStandard::increaseCommandBufferSize(VkCommandBuffer commandBuffer, VkDeviceSize commandSize) const
923 {
924 auto it = m_commandBufferMemoryConsumption.find(commandBuffer);
925 if (it == end(m_commandBufferMemoryConsumption))
926 TCU_THROW(InternalError, "Unregistered command buffer");
927
928 it->second.updateValues(commandSize, commandSize, commandSize);
929 }
930
resetCommandPool(VkDevice device,VkCommandPool commandPool,VkCommandPoolResetFlags flags) const931 void ResourceInterfaceStandard::resetCommandPool(VkDevice device, VkCommandPool commandPool,
932 VkCommandPoolResetFlags flags) const
933 {
934 DE_UNREF(device);
935 DE_UNREF(flags);
936
937 for (auto &memC : m_commandBufferMemoryConsumption)
938 {
939 if (memC.second.commandPool == commandPool.getInternal())
940 memC.second.resetValues();
941 }
942 }
943
importPipelineCacheData(const PlatformInterface & vkp,VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,uint32_t queueIndex)944 void ResourceInterfaceStandard::importPipelineCacheData(const PlatformInterface &vkp, VkInstance instance,
945 const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
946 uint32_t queueIndex)
947 {
948 if (!std::string(m_testCtx.getCommandLine().getPipelineCompilerPath()).empty())
949 {
950 m_cacheData = vksc_server::buildOfflinePipelineCache(
951 m_pipelineInput, std::string(m_testCtx.getCommandLine().getPipelineCompilerPath()),
952 std::string(m_testCtx.getCommandLine().getPipelineCompilerDataDir()),
953 std::string(m_testCtx.getCommandLine().getPipelineCompilerArgs()),
954 std::string(m_testCtx.getCommandLine().getPipelineCompilerOutputFile()),
955 std::string(m_testCtx.getCommandLine().getPipelineCompilerLogFile()),
956 std::string(m_testCtx.getCommandLine().getPipelineCompilerFilePrefix()));
957 }
958 else
959 {
960 m_cacheData = vksc_server::buildPipelineCache(m_pipelineInput, vkp, instance, vki, physicalDevice, queueIndex);
961 }
962
963 VkPhysicalDeviceVulkanSC10Properties vulkanSC10Properties = initVulkanStructure();
964 VkPhysicalDeviceProperties2 deviceProperties2 = initVulkanStructure(&vulkanSC10Properties);
965 vki.getPhysicalDeviceProperties2(physicalDevice, &deviceProperties2);
966
967 m_pipelineSizes = vksc_server::extractSizesFromPipelineCache(
968 m_pipelineInput, m_cacheData, uint32_t(m_testCtx.getCommandLine().getPipelineDefaultSize()),
969 vulkanSC10Properties.recyclePipelineMemory == VK_TRUE);
970 preparePipelinePoolSizes();
971 }
972
resetObjects()973 void ResourceInterfaceStandard::resetObjects()
974 {
975 m_pipelineInput = {};
976 m_objectHashes.clear();
977 m_commandPoolMemoryConsumption.clear();
978 m_commandPoolIndex = 0u;
979 m_commandBufferMemoryConsumption.clear();
980 m_resourceCounter = 0u;
981 m_statCurrent = resetDeviceObjectReservationCreateInfo();
982 m_statMax = resetDeviceObjectReservationCreateInfo();
983 // pipelineCacheRequestCount does not contain one instance of createPipelineCache call that happens only in subprocess
984 m_statCurrent.pipelineCacheRequestCount = 1u;
985 m_statMax.pipelineCacheRequestCount = 1u;
986 m_cacheData.clear();
987 m_pipelineIdentifiers.clear();
988 m_pipelineSizes.clear();
989 m_pipelinePoolSizes.clear();
990 runGarbageCollection();
991 }
992
resetPipelineCaches()993 void ResourceInterfaceStandard::resetPipelineCaches()
994 {
995 if (m_testCtx.getCommandLine().isSubProcess())
996 {
997 m_pipelineCache.clear();
998 }
999 }
1000
1001 #endif // CTS_USES_VULKANSC
1002
compileProgram(const vk::ProgramIdentifier & progId,const vk::GlslSource & source,glu::ShaderProgramInfo * buildInfo,const tcu::CommandLine & commandLine)1003 vk::ProgramBinary *ResourceInterfaceStandard::compileProgram(const vk::ProgramIdentifier &progId,
1004 const vk::GlslSource &source,
1005 glu::ShaderProgramInfo *buildInfo,
1006 const tcu::CommandLine &commandLine)
1007 {
1008 DE_UNREF(progId);
1009 return vk::buildProgram(source, buildInfo, commandLine);
1010 }
1011
compileProgram(const vk::ProgramIdentifier & progId,const vk::HlslSource & source,glu::ShaderProgramInfo * buildInfo,const tcu::CommandLine & commandLine)1012 vk::ProgramBinary *ResourceInterfaceStandard::compileProgram(const vk::ProgramIdentifier &progId,
1013 const vk::HlslSource &source,
1014 glu::ShaderProgramInfo *buildInfo,
1015 const tcu::CommandLine &commandLine)
1016 {
1017 DE_UNREF(progId);
1018 return vk::buildProgram(source, buildInfo, commandLine);
1019 }
1020
compileProgram(const vk::ProgramIdentifier & progId,const vk::SpirVAsmSource & source,vk::SpirVProgramInfo * buildInfo,const tcu::CommandLine & commandLine)1021 vk::ProgramBinary *ResourceInterfaceStandard::compileProgram(const vk::ProgramIdentifier &progId,
1022 const vk::SpirVAsmSource &source,
1023 vk::SpirVProgramInfo *buildInfo,
1024 const tcu::CommandLine &commandLine)
1025 {
1026 DE_UNREF(progId);
1027 return vk::assembleProgram(source, buildInfo, commandLine);
1028 }
1029
1030 #ifdef CTS_USES_VULKANSC
1031
ResourceInterfaceVKSC(tcu::TestContext & testCtx)1032 ResourceInterfaceVKSC::ResourceInterfaceVKSC(tcu::TestContext &testCtx) : ResourceInterfaceStandard(testCtx)
1033 {
1034 m_address = std::string(testCtx.getCommandLine().getServerAddress());
1035 }
1036
getServer()1037 vksc_server::Server *ResourceInterfaceVKSC::getServer()
1038 {
1039 if (!m_server)
1040 {
1041 m_server = std::make_shared<vksc_server::Server>(m_address);
1042 }
1043 return m_server.get();
1044 }
1045
noServer() const1046 bool ResourceInterfaceVKSC::noServer() const
1047 {
1048 return m_address.empty();
1049 }
1050
compileProgram(const vk::ProgramIdentifier & progId,const vk::GlslSource & source,glu::ShaderProgramInfo * buildInfo,const tcu::CommandLine & commandLine)1051 vk::ProgramBinary *ResourceInterfaceVKSC::compileProgram(const vk::ProgramIdentifier &progId,
1052 const vk::GlslSource &source,
1053 glu::ShaderProgramInfo *buildInfo,
1054 const tcu::CommandLine &commandLine)
1055 {
1056 if (noServer())
1057 return ResourceInterfaceStandard::compileProgram(progId, source, buildInfo, commandLine);
1058
1059 DE_UNREF(progId);
1060 DE_UNREF(buildInfo);
1061
1062 vksc_server::CompileShaderRequest request;
1063 request.source.active = "glsl";
1064 request.source.glsl = source;
1065 request.commandLine = commandLine.getInitialCmdLine();
1066 vksc_server::CompileShaderResponse response;
1067 getServer()->SendRequest(request, response);
1068
1069 return new ProgramBinary(PROGRAM_FORMAT_SPIRV, response.binary.size(), response.binary.data());
1070 }
1071
compileProgram(const vk::ProgramIdentifier & progId,const vk::HlslSource & source,glu::ShaderProgramInfo * buildInfo,const tcu::CommandLine & commandLine)1072 vk::ProgramBinary *ResourceInterfaceVKSC::compileProgram(const vk::ProgramIdentifier &progId,
1073 const vk::HlslSource &source,
1074 glu::ShaderProgramInfo *buildInfo,
1075 const tcu::CommandLine &commandLine)
1076 {
1077 if (noServer())
1078 return ResourceInterfaceStandard::compileProgram(progId, source, buildInfo, commandLine);
1079
1080 DE_UNREF(progId);
1081 DE_UNREF(buildInfo);
1082
1083 vksc_server::CompileShaderRequest request;
1084 request.source.active = "hlsl";
1085 request.source.hlsl = source;
1086 request.commandLine = commandLine.getInitialCmdLine();
1087 vksc_server::CompileShaderResponse response;
1088 getServer()->SendRequest(request, response);
1089
1090 return new ProgramBinary(PROGRAM_FORMAT_SPIRV, response.binary.size(), response.binary.data());
1091 }
1092
compileProgram(const vk::ProgramIdentifier & progId,const vk::SpirVAsmSource & source,vk::SpirVProgramInfo * buildInfo,const tcu::CommandLine & commandLine)1093 vk::ProgramBinary *ResourceInterfaceVKSC::compileProgram(const vk::ProgramIdentifier &progId,
1094 const vk::SpirVAsmSource &source,
1095 vk::SpirVProgramInfo *buildInfo,
1096 const tcu::CommandLine &commandLine)
1097 {
1098 if (noServer())
1099 return ResourceInterfaceStandard::compileProgram(progId, source, buildInfo, commandLine);
1100
1101 DE_UNREF(progId);
1102 DE_UNREF(buildInfo);
1103
1104 vksc_server::CompileShaderRequest request;
1105 request.source.active = "spirv";
1106 request.source.spirv = source;
1107 request.commandLine = commandLine.getInitialCmdLine();
1108 vksc_server::CompileShaderResponse response;
1109 getServer()->SendRequest(request, response);
1110
1111 return new ProgramBinary(PROGRAM_FORMAT_SPIRV, response.binary.size(), response.binary.data());
1112 }
1113
createShaderModule(VkDevice device,const VkShaderModuleCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkShaderModule * pShaderModule,bool normalMode) const1114 VkResult ResourceInterfaceVKSC::createShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
1115 const VkAllocationCallbacks *pAllocator,
1116 VkShaderModule *pShaderModule, bool normalMode) const
1117 {
1118 if (noServer() || !normalMode || !isVulkanSC())
1119 return ResourceInterfaceStandard::createShaderModule(device, pCreateInfo, pAllocator, pShaderModule,
1120 normalMode);
1121
1122 // We will reach this place only in one case:
1123 // - server exists
1124 // - subprocess asks for creation of VkShaderModule which will be later ignored, because it will receive the whole pipeline from server
1125 // ( Are there any tests which receive VkShaderModule and do not use it in any pipeline ? )
1126 *pShaderModule = incResourceCounter<VkShaderModule>();
1127 registerObjectHash(pShaderModule->getInternal(), calculateShaderModuleHash(*pCreateInfo, getObjectHashes()));
1128 return VK_SUCCESS;
1129 }
1130
importPipelineCacheData(const PlatformInterface & vkp,VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,uint32_t queueIndex)1131 void ResourceInterfaceVKSC::importPipelineCacheData(const PlatformInterface &vkp, VkInstance instance,
1132 const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
1133 uint32_t queueIndex)
1134 {
1135 if (noServer())
1136 {
1137 ResourceInterfaceStandard::importPipelineCacheData(vkp, instance, vki, physicalDevice, queueIndex);
1138 return;
1139 }
1140
1141 vksc_server::CreateCacheRequest request;
1142 request.input = m_pipelineInput;
1143 std::vector<int> caseFraction = m_testCtx.getCommandLine().getCaseFraction();
1144 request.caseFraction = caseFraction.empty() ? -1 : caseFraction[0];
1145
1146 vksc_server::CreateCacheResponse response;
1147 getServer()->SendRequest(request, response);
1148
1149 if (response.status)
1150 {
1151 m_cacheData = std::move(response.binary);
1152
1153 VkPhysicalDeviceVulkanSC10Properties vulkanSC10Properties = initVulkanStructure();
1154 VkPhysicalDeviceProperties2 deviceProperties2 = initVulkanStructure(&vulkanSC10Properties);
1155 vki.getPhysicalDeviceProperties2(physicalDevice, &deviceProperties2);
1156
1157 m_pipelineSizes = vksc_server::extractSizesFromPipelineCache(
1158 m_pipelineInput, m_cacheData, uint32_t(m_testCtx.getCommandLine().getPipelineDefaultSize()),
1159 vulkanSC10Properties.recyclePipelineMemory == VK_TRUE);
1160 preparePipelinePoolSizes();
1161 }
1162 else
1163 {
1164 TCU_THROW(InternalError,
1165 "Server did not return pipeline cache data when requested (check server log for details)");
1166 }
1167 }
1168
MultithreadedDestroyGuard(de::SharedPtr<vk::ResourceInterface> resourceInterface)1169 MultithreadedDestroyGuard::MultithreadedDestroyGuard(de::SharedPtr<vk::ResourceInterface> resourceInterface)
1170 : m_resourceInterface{resourceInterface}
1171 {
1172 if (m_resourceInterface.get() != nullptr)
1173 m_resourceInterface->setHandleDestroy(false);
1174 }
1175
~MultithreadedDestroyGuard()1176 MultithreadedDestroyGuard::~MultithreadedDestroyGuard()
1177 {
1178 if (m_resourceInterface.get() != nullptr)
1179 m_resourceInterface->setHandleDestroy(true);
1180 }
1181
1182 #endif // CTS_USES_VULKANSC
1183
1184 } // namespace vk
1185