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 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
    235