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