1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "VkPipelineCache.hpp"
16
17 #include <cstring>
18
19 namespace vk {
20
SpirvBinaryKey(const sw::SpirvBinary & spirv,const VkSpecializationInfo * specializationInfo,bool optimize)21 PipelineCache::SpirvBinaryKey::SpirvBinaryKey(const sw::SpirvBinary &spirv,
22 const VkSpecializationInfo *specializationInfo,
23 bool optimize)
24 : spirv(spirv)
25 , specializationInfo(specializationInfo)
26 , optimize(optimize)
27 {
28 }
29
operator <(const SpirvBinaryKey & other) const30 bool PipelineCache::SpirvBinaryKey::operator<(const SpirvBinaryKey &other) const
31 {
32 if(spirv.size() != other.spirv.size())
33 {
34 return spirv.size() < other.spirv.size();
35 }
36
37 int cmp = memcmp(spirv.data(), other.spirv.data(), spirv.size() * sizeof(uint32_t));
38 if(cmp != 0)
39 {
40 return cmp < 0;
41 }
42
43 if(optimize != other.optimize)
44 {
45 return !optimize && other.optimize;
46 }
47
48 return (specializationInfo < other.specializationInfo);
49 }
50
ComputeProgramKey(uint64_t shaderIdentifier,uint32_t pipelineLayoutIdentifier)51 PipelineCache::ComputeProgramKey::ComputeProgramKey(uint64_t shaderIdentifier, uint32_t pipelineLayoutIdentifier)
52 : shaderIdentifier(shaderIdentifier)
53 , pipelineLayoutIdentifier(pipelineLayoutIdentifier)
54 {}
55
operator <(const ComputeProgramKey & other) const56 bool PipelineCache::ComputeProgramKey::operator<(const ComputeProgramKey &other) const
57 {
58 return std::tie(shaderIdentifier, pipelineLayoutIdentifier) < std::tie(other.shaderIdentifier, other.pipelineLayoutIdentifier);
59 }
60
PipelineCache(const VkPipelineCacheCreateInfo * pCreateInfo,void * mem)61 PipelineCache::PipelineCache(const VkPipelineCacheCreateInfo *pCreateInfo, void *mem)
62 : dataSize(ComputeRequiredAllocationSize(pCreateInfo))
63 , data(reinterpret_cast<uint8_t *>(mem))
64 {
65 CacheHeader *header = reinterpret_cast<CacheHeader *>(mem);
66 header->headerLength = sizeof(CacheHeader);
67 header->headerVersion = VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
68 header->vendorID = VENDOR_ID;
69 header->deviceID = DEVICE_ID;
70 memcpy(header->pipelineCacheUUID, SWIFTSHADER_UUID, VK_UUID_SIZE);
71
72 if(pCreateInfo->pInitialData && (pCreateInfo->initialDataSize > 0))
73 {
74 memcpy(data + sizeof(CacheHeader), pCreateInfo->pInitialData, pCreateInfo->initialDataSize);
75 }
76 }
77
~PipelineCache()78 PipelineCache::~PipelineCache()
79 {
80 spirvShaders.clear();
81 computePrograms.clear();
82 }
83
destroy(const VkAllocationCallbacks * pAllocator)84 void PipelineCache::destroy(const VkAllocationCallbacks *pAllocator)
85 {
86 vk::freeHostMemory(data, pAllocator);
87 }
88
ComputeRequiredAllocationSize(const VkPipelineCacheCreateInfo * pCreateInfo)89 size_t PipelineCache::ComputeRequiredAllocationSize(const VkPipelineCacheCreateInfo *pCreateInfo)
90 {
91 return pCreateInfo->initialDataSize + sizeof(CacheHeader);
92 }
93
getData(size_t * pDataSize,void * pData)94 VkResult PipelineCache::getData(size_t *pDataSize, void *pData)
95 {
96 if(!pData)
97 {
98 *pDataSize = dataSize;
99 return VK_SUCCESS;
100 }
101
102 if(*pDataSize != dataSize)
103 {
104 *pDataSize = 0;
105 return VK_INCOMPLETE;
106 }
107
108 if(*pDataSize > 0)
109 {
110 memcpy(pData, data, *pDataSize);
111 }
112
113 return VK_SUCCESS;
114 }
115
merge(uint32_t srcCacheCount,const VkPipelineCache * pSrcCaches)116 VkResult PipelineCache::merge(uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches)
117 {
118 for(uint32_t i = 0; i < srcCacheCount; i++)
119 {
120 PipelineCache *srcCache = Cast(pSrcCaches[i]);
121
122 {
123 marl::lock thisLock(spirvShadersMutex);
124 marl::lock srcLock(srcCache->spirvShadersMutex);
125 spirvShaders.insert(srcCache->spirvShaders.begin(), srcCache->spirvShaders.end());
126 }
127
128 {
129 marl::lock thisLock(computeProgramsMutex);
130 marl::lock srcLock(srcCache->computeProgramsMutex);
131 computePrograms.insert(srcCache->computePrograms.begin(), srcCache->computePrograms.end());
132 }
133 }
134
135 return VK_SUCCESS;
136 }
137
138 } // namespace vk
139