• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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