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