xref: /aosp_15_r20/external/deqp/external/vulkancts/vkscserver/pcreader.hpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 #ifndef _PCREADER_HPP
2 #define _PCREADER_HPP
3 
4 /* Copyright (c) 2021, NVIDIA CORPORATION
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * Author: Daniel Koch <[email protected]>
19  */
20 
21 #include <cstddef>
22 
23 #ifndef VKSC_ASSERT
24 #include <cassert>
25 #define VKSC_ASSERT assert
26 #endif // VKSC_ASSERT
27 #ifndef VKSC_MEMCMP
28 #include <cstring>
29 #define VKSC_MEMCMP memcmp
30 #endif // VKSC_MEMCPY
31 
32 // Must be version 1.0.6 or newer
33 //#include <vulkan/vulkan_sc_core.hpp>
34 
35 // Legacy Header for version 1.0.4
36 #define VK_PIPELINE_CACHE_HEADER_VERSION_SAFETY_CRITICAL_ONE_LEGACY (VkPipelineCacheHeaderVersion)1000298000
37 typedef struct VkPipelineCacheHeaderVersionSafetyCriticalOneLegacy
38 {
39     VkPipelineCacheHeaderVersionOne headerVersionOne;
40     VkPipelineCacheValidationVersion validationVersion;
41     uint32_t pipelineIndexCount;
42     uint32_t pipelineIndexStride;
43     uint64_t pipelineIndexOffset;
44 } VkPipelineCacheHeaderVersionSafetyCriticalOneLegacy;
45 
46 // VKSCPipelineCacheHeaderReader
47 //
48 // Utility class to handle extracting information about pipelines from a pipeline cache blob.
49 //
50 // Instantiate the class with a pointer to the pipeline cache blob and the size.
51 // The pipeline cache blob is NOT copied and the application must maintain the lifetime
52 // of the data that was passed in while this object is instantiated.
53 // The cache blob will never be modified by this class.
54 //
55 // getSafetyCriticalOneHeader - return the safety critical header field
56 //
57 // getPipelineIndexEntry(index) - return the pipeline index entry for a specified index in the header
58 //
59 // getPipelineIndexEntry(UUID) - return the pipeline index entry for a specified pipeline identifier
60 //
61 // getJson - get a pointer to the json for a specfied pipeline index entry
62 //
63 // getStageIndexEntry - return the stage index entry for a specified pipeline index entry and stage
64 //
65 // getSPIRV - get a pointer to the SPIRV code for a specified stage index entry
66 //
67 
68 class VKSCPipelineCacheHeaderReader
69 {
70 public:
71     // initialize the pipeline cache header reader with <cacheSize> bytes of data starting at <cacheData>
72     // the pipeline cache is not copied, but the pointer is saved
73     // cacheData is never modified
VKSCPipelineCacheHeaderReader(uint64_t cacheSize,const uint8_t * cacheData)74     VKSCPipelineCacheHeaderReader(uint64_t cacheSize, const uint8_t *cacheData)
75         : m_CacheSize{cacheSize}
76         , m_CacheData{cacheData}
77     {
78         const VkPipelineCacheHeaderVersionSafetyCriticalOne *const sc1 =
79             reinterpret_cast<const VkPipelineCacheHeaderVersionSafetyCriticalOne *>(m_CacheData);
80 
81         m_IsLegacy =
82             (sc1->headerVersionOne.headerVersion == VK_PIPELINE_CACHE_HEADER_VERSION_SAFETY_CRITICAL_ONE_LEGACY);
83     }
84 
85     // basic quick check of the referenced pipeline cache data
86     // make sure m_CacheData starts with a well-formed VkPipelineCacheHeaderVersionSafetyCriticalOne structure
isValid() const87     bool isValid() const
88     {
89         const VkPipelineCacheHeaderVersionSafetyCriticalOne *const sc1 =
90             reinterpret_cast<const VkPipelineCacheHeaderVersionSafetyCriticalOne *>(m_CacheData);
91 
92         if (sc1->headerVersionOne.headerSize != sizeof(VkPipelineCacheHeaderVersionSafetyCriticalOne) ||
93             !(sc1->headerVersionOne.headerVersion == VK_PIPELINE_CACHE_HEADER_VERSION_SAFETY_CRITICAL_ONE ||
94               isLegacy()) ||
95             sc1->validationVersion != VK_PIPELINE_CACHE_VALIDATION_VERSION_SAFETY_CRITICAL_ONE)
96         {
97             return false;
98         }
99         return true;
100     }
101 
isLegacy() const102     bool isLegacy() const
103     {
104         return m_IsLegacy;
105     }
106 
107     // return pointer to the VkPipelineCacheHeaderVersionOne structure
getHeaderVersionOne() const108     const VkPipelineCacheHeaderVersionOne *getHeaderVersionOne() const
109     {
110         const VkPipelineCacheHeaderVersionOne *const hv1 =
111             reinterpret_cast<const VkPipelineCacheHeaderVersionOne *>(m_CacheData);
112 
113         return hv1;
114     }
115 
116     // return the validation version from the SC1 header
getValidationVersion() const117     VkPipelineCacheValidationVersion getValidationVersion() const
118     {
119         if (isLegacy())
120         {
121             const VkPipelineCacheHeaderVersionSafetyCriticalOneLegacy *const sc1 = getSafetyCriticalOneHeaderLegacy();
122             return sc1->validationVersion;
123         }
124         else
125         {
126             const VkPipelineCacheHeaderVersionSafetyCriticalOne *const sc1 = getSafetyCriticalOneHeader();
127             return sc1->validationVersion;
128         }
129     }
130 
131     // return the implementation data field from the SC1 header
getImplementationData() const132     uint32_t getImplementationData() const
133     {
134         if (isLegacy())
135         {
136             return 0U;
137         }
138         else
139         {
140             const VkPipelineCacheHeaderVersionSafetyCriticalOne *const sc1 = getSafetyCriticalOneHeader();
141             return sc1->implementationData;
142         }
143     }
144 
145     // return the number of pipelines in the index
getPipelineIndexCount() const146     uint32_t getPipelineIndexCount() const
147     {
148         if (isLegacy())
149         {
150             const VkPipelineCacheHeaderVersionSafetyCriticalOneLegacy *const sc1 = getSafetyCriticalOneHeaderLegacy();
151             return sc1->pipelineIndexCount;
152         }
153         else
154         {
155             const VkPipelineCacheHeaderVersionSafetyCriticalOne *const sc1 = getSafetyCriticalOneHeader();
156             return sc1->pipelineIndexCount;
157         }
158     }
159 
160     // return the stride between pipeline index entries in the index
getPipelineIndexStride() const161     uint32_t getPipelineIndexStride() const
162     {
163         if (isLegacy())
164         {
165             const VkPipelineCacheHeaderVersionSafetyCriticalOneLegacy *const sc1 = getSafetyCriticalOneHeaderLegacy();
166             return sc1->pipelineIndexStride;
167         }
168         else
169         {
170             const VkPipelineCacheHeaderVersionSafetyCriticalOne *const sc1 = getSafetyCriticalOneHeader();
171             return sc1->pipelineIndexStride;
172         }
173     }
174 
175     // returns the offset to the start of pipeline index entries in the cache
getPipelineIndexOffset() const176     uint64_t getPipelineIndexOffset() const
177     {
178         if (isLegacy())
179         {
180             const VkPipelineCacheHeaderVersionSafetyCriticalOneLegacy *const sc1 = getSafetyCriticalOneHeaderLegacy();
181             return sc1->pipelineIndexOffset;
182         }
183         else
184         {
185             const VkPipelineCacheHeaderVersionSafetyCriticalOne *const sc1 = getSafetyCriticalOneHeader();
186             return sc1->pipelineIndexOffset;
187         }
188     }
189 
190     // return pointer to pipeline index entry by <index> in pipeline header
191     // typically used for iterating over all pipelines in the cache
192     // nullptr is returned if <index> is out of range
getPipelineIndexEntry(uint32_t index) const193     const VkPipelineCacheSafetyCriticalIndexEntry *getPipelineIndexEntry(uint32_t index) const
194     {
195         if (index >= getPipelineIndexCount())
196         {
197             return nullptr;
198         }
199 
200         uint64_t offset = getPipelineIndexOffset() + (index * getPipelineIndexStride());
201         VKSC_ASSERT(offset + sizeof(VkPipelineCacheSafetyCriticalIndexEntry) <= m_CacheSize);
202 
203         const VkPipelineCacheSafetyCriticalIndexEntry *const pipelineIndexEntry =
204             reinterpret_cast<const VkPipelineCacheSafetyCriticalIndexEntry *>(m_CacheData + offset);
205 
206         return pipelineIndexEntry;
207     }
208 
209     // return pointer to pipeline index entry for requested pipeline identifier
210     // nullptr is returned if not found
getPipelineIndexEntry(const uint8_t identifier[VK_UUID_SIZE]) const211     const VkPipelineCacheSafetyCriticalIndexEntry *getPipelineIndexEntry(const uint8_t identifier[VK_UUID_SIZE]) const
212     {
213         const uint32_t pipelineIndexCount  = getPipelineIndexCount();
214         const uint32_t pipelineIndexStride = getPipelineIndexStride();
215         const uint64_t pipelineIndexOffset = getPipelineIndexOffset();
216 
217         for (uint32_t i = 0U; i < pipelineIndexCount; ++i)
218         {
219             uint64_t offset = pipelineIndexOffset + (i * pipelineIndexStride);
220             VKSC_ASSERT(offset + sizeof(VkPipelineCacheSafetyCriticalIndexEntry) <= m_CacheSize);
221 
222             const VkPipelineCacheSafetyCriticalIndexEntry *const pipelineIndexEntry =
223                 reinterpret_cast<const VkPipelineCacheSafetyCriticalIndexEntry *>(m_CacheData + offset);
224 
225             if (VKSC_MEMCMP(identifier, pipelineIndexEntry->pipelineIdentifier, VK_UUID_SIZE) == 0U)
226             {
227                 return pipelineIndexEntry;
228             }
229         }
230 
231         return nullptr;
232     }
233 
234     // return pointer to json for a given pipeline index entry
235     // nullptr is returned if not present
getJson(const VkPipelineCacheSafetyCriticalIndexEntry * const pipelineIndexEntry) const236     const uint8_t *getJson(const VkPipelineCacheSafetyCriticalIndexEntry *const pipelineIndexEntry) const
237     {
238         uint64_t offset = pipelineIndexEntry->jsonOffset;
239         if (0U == offset)
240             return nullptr;
241 
242         VKSC_ASSERT(offset + pipelineIndexEntry->jsonSize <= m_CacheSize);
243 
244         return (m_CacheData + offset);
245     }
246 
247     // return pointer to stage validation index entry given a pipeline index entry <pipelineIndexEntry> and <stage>
248     // nullptr is returned if not present
getStageIndexEntry(const VkPipelineCacheSafetyCriticalIndexEntry * const pipelineIndexEntry,uint32_t stage) const249     const VkPipelineCacheStageValidationIndexEntry *getStageIndexEntry(
250         const VkPipelineCacheSafetyCriticalIndexEntry *const pipelineIndexEntry, uint32_t stage) const
251     {
252         if (stage >= pipelineIndexEntry->stageIndexCount)
253             return nullptr;
254 
255         uint64_t offset = pipelineIndexEntry->stageIndexOffset + (stage * pipelineIndexEntry->stageIndexStride);
256         VKSC_ASSERT(offset + sizeof(VkPipelineCacheStageValidationIndexEntry) <= m_CacheSize);
257 
258         const VkPipelineCacheStageValidationIndexEntry *const stageIndexEntry =
259             reinterpret_cast<const VkPipelineCacheStageValidationIndexEntry *>(m_CacheData + offset);
260 
261         return stageIndexEntry;
262     }
263 
264     // return pointer to spirv code in the pipeline cache for a given stage index entry
265     // nullptr is returned if not present
getSPIRV(const VkPipelineCacheStageValidationIndexEntry * const stageIndexEntry) const266     const uint8_t *getSPIRV(const VkPipelineCacheStageValidationIndexEntry *const stageIndexEntry) const
267     {
268         uint64_t offset = stageIndexEntry->codeOffset;
269         if (0U == offset)
270             return nullptr;
271 
272         VKSC_ASSERT(offset + stageIndexEntry->codeSize <= m_CacheSize);
273 
274         return (m_CacheData + offset);
275     }
276 
277 private:
278     // return pointer to the pipeline cache SafetyCriticalOne structure
getSafetyCriticalOneHeader() const279     const VkPipelineCacheHeaderVersionSafetyCriticalOne *getSafetyCriticalOneHeader() const
280     {
281         const VkPipelineCacheHeaderVersionSafetyCriticalOne *const sc1 =
282             reinterpret_cast<const VkPipelineCacheHeaderVersionSafetyCriticalOne *>(m_CacheData);
283 
284         return sc1;
285     }
286 
287     // return pointer to the pipeline cache SafetyCriticalOneLegacy structure
getSafetyCriticalOneHeaderLegacy() const288     const VkPipelineCacheHeaderVersionSafetyCriticalOneLegacy *getSafetyCriticalOneHeaderLegacy() const
289     {
290         const VkPipelineCacheHeaderVersionSafetyCriticalOneLegacy *const sc1 =
291             reinterpret_cast<const VkPipelineCacheHeaderVersionSafetyCriticalOneLegacy *>(m_CacheData);
292 
293         return sc1;
294     }
295     const uint64_t m_CacheSize;       // size of data pointed to by m_CacheData in bytes
296     const uint8_t *const m_CacheData; // pipeline cache data being read by this reader
297     bool m_IsLegacy;                  // is legacy (pre 1.0.5) pipeline cache format
298 };
299 
300 #endif // _PCREADER_HPP
301