Home | History | Annotate | Download | only in vulkan
      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 class BinaryRegistryReader
    174 {
    175 public:
    176 							BinaryRegistryReader	(const tcu::Archive& archive, const std::string& srcPath);
    177 							~BinaryRegistryReader	(void);
    178 
    179 	ProgramBinary*			loadProgram				(const ProgramIdentifier& id) const;
    180 
    181 private:
    182 	typedef de::MovePtr<BinaryIndexAccess> BinaryIndexPtr;
    183 
    184 	const tcu::Archive&		m_archive;
    185 	const std::string		m_srcPath;
    186 
    187 	mutable BinaryIndexPtr	m_binaryIndex;
    188 };
    189 
    190 struct ProgramIdentifierIndex
    191 {
    192 	ProgramIdentifier	id;
    193 	deUint32			index;
    194 
    195 	ProgramIdentifierIndex (const ProgramIdentifier&	id_,
    196 							deUint32					index_)
    197 		: id	(id_)
    198 		, index	(index_)
    199 	{}
    200 };
    201 
    202 DE_DECLARE_POOL_HASH(BinaryIndexHashImpl, const ProgramBinary*, deUint32);
    203 
    204 class BinaryIndexHash
    205 {
    206 public:
    207 								BinaryIndexHash		(void);
    208 								~BinaryIndexHash	(void);
    209 
    210 	deUint32*					find				(const ProgramBinary* binary) const;
    211 	void						insert				(const ProgramBinary* binary, deUint32 index);
    212 
    213 private:
    214 								BinaryIndexHash		(const BinaryIndexHash&);
    215 	BinaryIndexHash&			operator=			(const BinaryIndexHash&);
    216 
    217 	de::MemPool					m_memPool;
    218 	BinaryIndexHashImpl* const	m_hash;
    219 };
    220 
    221 class BinaryRegistryWriter
    222 {
    223 public:
    224 						BinaryRegistryWriter	(const std::string& dstPath);
    225 						~BinaryRegistryWriter	(void);
    226 
    227 	void				addProgram				(const ProgramIdentifier& id, const ProgramBinary& binary);
    228 	void				write					(void) const;
    229 
    230 private:
    231 	void				initFromPath			(const std::string& srcPath);
    232 	void				writeToPath				(const std::string& dstPath) const;
    233 
    234 	deUint32*			findBinary				(const ProgramBinary& binary) const;
    235 	deUint32			getNextSlot				(void) const;
    236 	void				addBinary				(deUint32 index, const ProgramBinary& binary);
    237 
    238 	struct BinarySlot
    239 	{
    240 		ProgramBinary*	binary;
    241 		size_t			referenceCount;
    242 
    243 		BinarySlot (ProgramBinary* binary_, size_t referenceCount_)
    244 			: binary		(binary_)
    245 			, referenceCount(referenceCount_)
    246 		{}
    247 
    248 		BinarySlot (void)
    249 			: binary		(DE_NULL)
    250 			, referenceCount(0)
    251 		{}
    252 	};
    253 
    254 	typedef std::vector<BinarySlot>				BinaryVector;
    255 	typedef std::vector<ProgramIdentifierIndex>	ProgIdIndexVector;
    256 
    257 	const std::string&	m_dstPath;
    258 
    259 	ProgIdIndexVector	m_binaryIndices;		//!< ProgramIdentifier -> slot in m_binaries
    260 	BinaryIndexHash		m_binaryHash;			//!< ProgramBinary -> slot in m_binaries
    261 	BinaryVector		m_binaries;
    262 };
    263 
    264 } // BinaryRegistryDetail
    265 
    266 using BinaryRegistryDetail::BinaryRegistryReader;
    267 using BinaryRegistryDetail::BinaryRegistryWriter;
    268 using BinaryRegistryDetail::ProgramIdentifier;
    269 using BinaryRegistryDetail::ProgramNotFoundException;
    270 
    271 } // vk
    272 
    273 #endif // _VKBINARYREGISTRY_HPP
    274