1 #ifndef _VKBINARYREGISTRY_HPP
2 #define _VKBINARYREGISTRY_HPP
3 /*-------------------------------------------------------------------------
7 * Copyright (c) 2015 Google Inc.
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 * \brief Program binary registry.
24 *//*--------------------------------------------------------------------*/
27 #include "vkPrograms.hpp"
28 #include "tcuResource.hpp"
29 #include "deMemPool.hpp"
30 #include "dePoolHash.h"
31 #include "deUniquePtr.hpp"
39 namespace BinaryRegistryDetail
42 struct ProgramIdentifier
44 std::string testCasePath;
45 std::string programName;
47 ProgramIdentifier (const std::string& testCasePath_, const std::string& programName_)
48 : testCasePath (testCasePath_)
49 , programName (programName_)
54 inline bool operator< (const ProgramIdentifier& a, const ProgramIdentifier& b)
56 return (a.testCasePath < b.testCasePath) || ((a.testCasePath == b.testCasePath) && (a.programName < b.programName));
59 class ProgramNotFoundException : public tcu::ResourceError
62 ProgramNotFoundException (const ProgramIdentifier& id, const std::string& reason)
63 : tcu::ResourceError("Program " + id.testCasePath + " / '" + id.programName + "' not found: " + reason)
68 // Program Binary Index
69 // --------------------
71 // When SPIR-V binaries are stored on disk, duplicate binaries are eliminated
72 // to save a significant amount of space. Many tests use identical binaries and
73 // just storing each compiled binary without de-duplication would be incredibly
76 // To locate binary that corresponds given ProgramIdentifier, a program binary
77 // index is needed. Since that index is accessed every time a test requests shader
78 // binary, it must be fast to load (to reduce statup cost), and fast to access.
80 // Simple trie is used to store binary indices. It is laid out as an array of
81 // BinaryIndexNodes. Nodes store 4-byte pieces (words) of search string, rather
82 // than just a single character. This gives more regular memory layout in exchange
83 // of a little wasted storage.
85 // Search strings are created by splitting original string into 4-byte words and
86 // appending one or more terminating 0 bytes.
88 // For each node where word doesn't have trailing 0 bytes (not terminated), the
89 // index points into a offset of its child list. Children for each node are stored
90 // consecutively, and the list is terminated by child with word = 0.
92 // If word contains one or more trailing 0 bytes, index denotes the binary index
93 // instead of index of the child list.
95 struct BinaryIndexNode
97 deUint32 word; //!< 4 bytes of search string.
98 deUint32 index; //!< Binary index if word ends with 0 bytes, or index of first child node otherwise.
101 template<typename Element>
105 LazyResource (de::MovePtr<tcu::Resource> resource);
107 const Element& operator[] (size_t ndx);
108 size_t size (void) const { return m_elements.size(); }
113 ELEMENTS_PER_PAGE_LOG2 = 10
116 inline size_t getPageForElement (size_t elemNdx) const { return elemNdx >> ELEMENTS_PER_PAGE_LOG2; }
117 inline bool isPageResident (size_t pageNdx) const { return m_isPageResident[pageNdx]; }
119 void makePageResident (size_t pageNdx);
121 de::UniquePtr<tcu::Resource> m_resource;
123 std::vector<Element> m_elements;
124 std::vector<bool> m_isPageResident;
127 template<typename Element>
128 LazyResource<Element>::LazyResource (de::MovePtr<tcu::Resource> resource)
129 : m_resource(resource)
131 const size_t resSize = m_resource->getSize();
132 const size_t numElements = resSize/sizeof(Element);
133 const size_t numPages = (numElements >> ELEMENTS_PER_PAGE_LOG2) + ((numElements & ((1u<<ELEMENTS_PER_PAGE_LOG2)-1u)) == 0 ? 0 : 1);
135 TCU_CHECK_INTERNAL(numElements*sizeof(Element) == resSize);
137 m_elements.resize(numElements);
138 m_isPageResident.resize(numPages, false);
141 template<typename Element>
142 const Element& LazyResource<Element>::operator[] (size_t ndx)
144 const size_t pageNdx = getPageForElement(ndx);
146 if (ndx >= m_elements.size())
147 throw std::out_of_range("");
149 if (!isPageResident(pageNdx))
150 makePageResident(pageNdx);
152 return m_elements[ndx];
155 template<typename Element>
156 void LazyResource<Element>::makePageResident (size_t pageNdx)
158 const size_t pageSize = (size_t)(1<<ELEMENTS_PER_PAGE_LOG2)*sizeof(Element);
159 const size_t pageOffset = pageNdx*pageSize;
160 const size_t numBytesToRead = de::min(m_elements.size()*sizeof(Element) - pageOffset, pageSize);
162 DE_ASSERT(!isPageResident(pageNdx));
164 if ((size_t)m_resource->getPosition() != pageOffset)
165 m_resource->setPosition((int)pageOffset);
167 m_resource->read((deUint8*)&m_elements[pageNdx << ELEMENTS_PER_PAGE_LOG2], (int)numBytesToRead);
168 m_isPageResident[pageNdx] = true;
171 typedef LazyResource<BinaryIndexNode> BinaryIndexAccess;
173 DE_DECLARE_POOL_HASH(BinaryHash, const ProgramBinary*, deUint32);
175 class BinaryRegistryReader
178 BinaryRegistryReader (const tcu::Archive& archive, const std::string& srcPath);
179 ~BinaryRegistryReader (void);
181 ProgramBinary* loadProgram (const ProgramIdentifier& id) const;
184 typedef de::MovePtr<BinaryIndexAccess> BinaryIndexPtr;
186 const tcu::Archive& m_archive;
187 const std::string m_srcPath;
189 mutable BinaryIndexPtr m_binaryIndex;
192 class BinaryRegistryWriter
195 BinaryRegistryWriter (const std::string& dstPath);
196 ~BinaryRegistryWriter (void);
198 void storeProgram (const ProgramIdentifier& id, const ProgramBinary& binary);
199 void writeIndex (void) const;
204 ProgramIdentifier id;
207 BinaryIndex (const ProgramIdentifier& id_,
214 typedef std::vector<ProgramBinary*> BinaryVector;
215 typedef std::vector<BinaryIndex> BinaryIndexVector;
217 const std::string& m_dstPath;
219 de::MemPool m_memPool;
220 BinaryHash* m_binaryIndexMap; //!< ProgramBinary -> slot in m_compactedBinaries
221 BinaryVector m_compactedBinaries;
222 BinaryIndexVector m_binaryIndices; //!< ProgramIdentifier -> slot in m_compactedBinaries
225 } // BinaryRegistryDetail
227 using BinaryRegistryDetail::BinaryRegistryReader;
228 using BinaryRegistryDetail::BinaryRegistryWriter;
229 using BinaryRegistryDetail::ProgramIdentifier;
230 using BinaryRegistryDetail::ProgramNotFoundException;
234 #endif // _VKBINARYREGISTRY_HPP