Update Vulkan framework to API 1.0.5
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / framework / vulkan / vkBinaryRegistry.hpp
1 #ifndef _VKBINARYREGISTRY_HPP
2 #define _VKBINARYREGISTRY_HPP
3 /*-------------------------------------------------------------------------
4  * Vulkan CTS Framework
5  * --------------------
6  *
7  * Copyright (c) 2015 Google Inc.
8  *
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
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
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.
20  *
21  *//*!
22  * \file
23  * \brief Program binary registry.
24  *//*--------------------------------------------------------------------*/
25
26 #include "vkDefs.hpp"
27 #include "vkPrograms.hpp"
28 #include "tcuResource.hpp"
29 #include "deMemPool.hpp"
30 #include "dePoolHash.h"
31 #include "deUniquePtr.hpp"
32
33 #include <map>
34 #include <vector>
35 #include <stdexcept>
36
37 namespace vk
38 {
39 namespace BinaryRegistryDetail
40 {
41
42 struct ProgramIdentifier
43 {
44         std::string             testCasePath;
45         std::string             programName;
46
47         ProgramIdentifier (const std::string& testCasePath_, const std::string& programName_)
48                 : testCasePath  (testCasePath_)
49                 , programName   (programName_)
50         {
51         }
52 };
53
54 inline bool operator< (const ProgramIdentifier& a, const ProgramIdentifier& b)
55 {
56         return (a.testCasePath < b.testCasePath) || ((a.testCasePath == b.testCasePath) && (a.programName < b.programName));
57 }
58
59 class ProgramNotFoundException : public tcu::ResourceError
60 {
61 public:
62         ProgramNotFoundException (const ProgramIdentifier& id, const std::string& reason)
63                 : tcu::ResourceError("Program " + id.testCasePath + " / '" + id.programName + "' not found: " + reason)
64         {
65         }
66 };
67
68 // Program Binary Index
69 // --------------------
70 //
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
74 // wasteful.
75 //
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.
79 //
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.
84 //
85 // Search strings are created by splitting original string into 4-byte words and
86 // appending one or more terminating 0 bytes.
87 //
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.
91 //
92 // If word contains one or more trailing 0 bytes, index denotes the binary index
93 // instead of index of the child list.
94
95 struct BinaryIndexNode
96 {
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.
99 };
100
101 template<typename Element>
102 class LazyResource
103 {
104 public:
105                                                                         LazyResource            (de::MovePtr<tcu::Resource> resource);
106
107         const Element&                                  operator[]                      (size_t ndx);
108         size_t                                                  size                            (void) const { return m_elements.size();        }
109
110 private:
111         enum
112         {
113                 ELEMENTS_PER_PAGE_LOG2  = 10
114         };
115
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];                      }
118
119         void                                                    makePageResident        (size_t pageNdx);
120
121         de::UniquePtr<tcu::Resource>    m_resource;
122
123         std::vector<Element>                    m_elements;
124         std::vector<bool>                               m_isPageResident;
125 };
126
127 template<typename Element>
128 LazyResource<Element>::LazyResource (de::MovePtr<tcu::Resource> resource)
129         : m_resource(resource)
130 {
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);
134
135         TCU_CHECK_INTERNAL(numElements*sizeof(Element) == resSize);
136
137         m_elements.resize(numElements);
138         m_isPageResident.resize(numPages, false);
139 }
140
141 template<typename Element>
142 const Element& LazyResource<Element>::operator[] (size_t ndx)
143 {
144         const size_t pageNdx = getPageForElement(ndx);
145
146         if (ndx >= m_elements.size())
147                 throw std::out_of_range("");
148
149         if (!isPageResident(pageNdx))
150                 makePageResident(pageNdx);
151
152         return m_elements[ndx];
153 }
154
155 template<typename Element>
156 void LazyResource<Element>::makePageResident (size_t pageNdx)
157 {
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);
161
162         DE_ASSERT(!isPageResident(pageNdx));
163
164         if ((size_t)m_resource->getPosition() != pageOffset)
165                 m_resource->setPosition((int)pageOffset);
166
167         m_resource->read((deUint8*)&m_elements[pageNdx << ELEMENTS_PER_PAGE_LOG2], (int)numBytesToRead);
168         m_isPageResident[pageNdx] = true;
169 }
170
171 typedef LazyResource<BinaryIndexNode> BinaryIndexAccess;
172
173 DE_DECLARE_POOL_HASH(BinaryHash, const ProgramBinary*, deUint32);
174
175 class BinaryRegistryReader
176 {
177 public:
178                                                         BinaryRegistryReader    (const tcu::Archive& archive, const std::string& srcPath);
179                                                         ~BinaryRegistryReader   (void);
180
181         ProgramBinary*                  loadProgram                             (const ProgramIdentifier& id) const;
182
183 private:
184         typedef de::MovePtr<BinaryIndexAccess> BinaryIndexPtr;
185
186         const tcu::Archive&             m_archive;
187         const std::string               m_srcPath;
188
189         mutable BinaryIndexPtr  m_binaryIndex;
190 };
191
192 class BinaryRegistryWriter
193 {
194 public:
195                                                 BinaryRegistryWriter    (const std::string& dstPath);
196                                                 ~BinaryRegistryWriter   (void);
197
198         void                            storeProgram                    (const ProgramIdentifier& id, const ProgramBinary& binary);
199         void                            writeIndex                              (void) const;
200
201 private:
202         struct BinaryIndex
203         {
204                 ProgramIdentifier       id;
205                 deUint32                        index;
206
207                 BinaryIndex (const ProgramIdentifier&   id_,
208                                          deUint32                                       index_)
209                         : id    (id_)
210                         , index (index_)
211                 {}
212         };
213
214         typedef std::vector<ProgramBinary*>     BinaryVector;
215         typedef std::vector<BinaryIndex>        BinaryIndexVector;
216
217         const std::string&      m_dstPath;
218
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
223 };
224
225 } // BinaryRegistryDetail
226
227 using BinaryRegistryDetail::BinaryRegistryReader;
228 using BinaryRegistryDetail::BinaryRegistryWriter;
229 using BinaryRegistryDetail::ProgramIdentifier;
230 using BinaryRegistryDetail::ProgramNotFoundException;
231
232 } // vk
233
234 #endif // _VKBINARYREGISTRY_HPP