1e5c31af7Sopenharmony_ci#ifndef _VKBINARYREGISTRY_HPP
2e5c31af7Sopenharmony_ci#define _VKBINARYREGISTRY_HPP
3e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
4e5c31af7Sopenharmony_ci * Vulkan CTS Framework
5e5c31af7Sopenharmony_ci * --------------------
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Copyright (c) 2015 Google Inc.
8e5c31af7Sopenharmony_ci *
9e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
10e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
11e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
14e5c31af7Sopenharmony_ci *
15e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
16e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
17e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
19e5c31af7Sopenharmony_ci * limitations under the License.
20e5c31af7Sopenharmony_ci *
21e5c31af7Sopenharmony_ci *//*!
22e5c31af7Sopenharmony_ci * \file
23e5c31af7Sopenharmony_ci * \brief Program binary registry.
24e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
25e5c31af7Sopenharmony_ci
26e5c31af7Sopenharmony_ci#include "vkDefs.hpp"
27e5c31af7Sopenharmony_ci#include "vkPrograms.hpp"
28e5c31af7Sopenharmony_ci#include "tcuResource.hpp"
29e5c31af7Sopenharmony_ci#include "deMemPool.hpp"
30e5c31af7Sopenharmony_ci#include "dePoolHash.h"
31e5c31af7Sopenharmony_ci#include "deUniquePtr.hpp"
32e5c31af7Sopenharmony_ci
33e5c31af7Sopenharmony_ci#include <map>
34e5c31af7Sopenharmony_ci#include <vector>
35e5c31af7Sopenharmony_ci#include <stdexcept>
36e5c31af7Sopenharmony_ci
37e5c31af7Sopenharmony_cinamespace vk
38e5c31af7Sopenharmony_ci{
39e5c31af7Sopenharmony_cinamespace BinaryRegistryDetail
40e5c31af7Sopenharmony_ci{
41e5c31af7Sopenharmony_ci
42e5c31af7Sopenharmony_cistruct ProgramIdentifier
43e5c31af7Sopenharmony_ci{
44e5c31af7Sopenharmony_ci	std::string		testCasePath;
45e5c31af7Sopenharmony_ci	std::string		programName;
46e5c31af7Sopenharmony_ci
47e5c31af7Sopenharmony_ci	ProgramIdentifier (const std::string& testCasePath_, const std::string& programName_)
48e5c31af7Sopenharmony_ci		: testCasePath	(testCasePath_)
49e5c31af7Sopenharmony_ci		, programName	(programName_)
50e5c31af7Sopenharmony_ci	{
51e5c31af7Sopenharmony_ci	}
52e5c31af7Sopenharmony_ci};
53e5c31af7Sopenharmony_ci
54e5c31af7Sopenharmony_ciinline bool operator< (const ProgramIdentifier& a, const ProgramIdentifier& b)
55e5c31af7Sopenharmony_ci{
56e5c31af7Sopenharmony_ci	return (a.testCasePath < b.testCasePath) || ((a.testCasePath == b.testCasePath) && (a.programName < b.programName));
57e5c31af7Sopenharmony_ci}
58e5c31af7Sopenharmony_ci
59e5c31af7Sopenharmony_ciclass ProgramNotFoundException : public tcu::ResourceError
60e5c31af7Sopenharmony_ci{
61e5c31af7Sopenharmony_cipublic:
62e5c31af7Sopenharmony_ci	ProgramNotFoundException (const ProgramIdentifier& id, const std::string& reason)
63e5c31af7Sopenharmony_ci		: tcu::ResourceError("Program " + id.testCasePath + " / '" + id.programName + "' not found: " + reason)
64e5c31af7Sopenharmony_ci	{
65e5c31af7Sopenharmony_ci	}
66e5c31af7Sopenharmony_ci};
67e5c31af7Sopenharmony_ci
68e5c31af7Sopenharmony_ci// Program Binary Index
69e5c31af7Sopenharmony_ci// --------------------
70e5c31af7Sopenharmony_ci//
71e5c31af7Sopenharmony_ci// When SPIR-V binaries are stored on disk, duplicate binaries are eliminated
72e5c31af7Sopenharmony_ci// to save a significant amount of space. Many tests use identical binaries and
73e5c31af7Sopenharmony_ci// just storing each compiled binary without de-duplication would be incredibly
74e5c31af7Sopenharmony_ci// wasteful.
75e5c31af7Sopenharmony_ci//
76e5c31af7Sopenharmony_ci// To locate binary that corresponds given ProgramIdentifier, a program binary
77e5c31af7Sopenharmony_ci// index is needed. Since that index is accessed every time a test requests shader
78e5c31af7Sopenharmony_ci// binary, it must be fast to load (to reduce statup cost), and fast to access.
79e5c31af7Sopenharmony_ci//
80e5c31af7Sopenharmony_ci// Simple trie is used to store binary indices. It is laid out as an array of
81e5c31af7Sopenharmony_ci// BinaryIndexNodes. Nodes store 4-byte pieces (words) of search string, rather
82e5c31af7Sopenharmony_ci// than just a single character. This gives more regular memory layout in exchange
83e5c31af7Sopenharmony_ci// of a little wasted storage.
84e5c31af7Sopenharmony_ci//
85e5c31af7Sopenharmony_ci// Search strings are created by splitting original string into 4-byte words and
86e5c31af7Sopenharmony_ci// appending one or more terminating 0 bytes.
87e5c31af7Sopenharmony_ci//
88e5c31af7Sopenharmony_ci// For each node where word doesn't have trailing 0 bytes (not terminated), the
89e5c31af7Sopenharmony_ci// index points into a offset of its child list. Children for each node are stored
90e5c31af7Sopenharmony_ci// consecutively, and the list is terminated by child with word = 0.
91e5c31af7Sopenharmony_ci//
92e5c31af7Sopenharmony_ci// If word contains one or more trailing 0 bytes, index denotes the binary index
93e5c31af7Sopenharmony_ci// instead of index of the child list.
94e5c31af7Sopenharmony_ci
95e5c31af7Sopenharmony_cistruct BinaryIndexNode
96e5c31af7Sopenharmony_ci{
97e5c31af7Sopenharmony_ci	deUint32	word;		//!< 4 bytes of search string.
98e5c31af7Sopenharmony_ci	deUint32	index;		//!< Binary index if word ends with 0 bytes, or index of first child node otherwise.
99e5c31af7Sopenharmony_ci};
100e5c31af7Sopenharmony_ci
101e5c31af7Sopenharmony_citemplate<typename Element>
102e5c31af7Sopenharmony_ciclass LazyResource
103e5c31af7Sopenharmony_ci{
104e5c31af7Sopenharmony_cipublic:
105e5c31af7Sopenharmony_ci									LazyResource		(de::MovePtr<tcu::Resource> resource);
106e5c31af7Sopenharmony_ci
107e5c31af7Sopenharmony_ci	const Element&					operator[]			(size_t ndx);
108e5c31af7Sopenharmony_ci	size_t							size				(void) const { return m_elements.size();	}
109e5c31af7Sopenharmony_ci
110e5c31af7Sopenharmony_ciprivate:
111e5c31af7Sopenharmony_ci	enum
112e5c31af7Sopenharmony_ci	{
113e5c31af7Sopenharmony_ci		ELEMENTS_PER_PAGE_LOG2	= 10
114e5c31af7Sopenharmony_ci	};
115e5c31af7Sopenharmony_ci
116e5c31af7Sopenharmony_ci	inline size_t					getPageForElement	(size_t elemNdx) const { return elemNdx >> ELEMENTS_PER_PAGE_LOG2;	}
117e5c31af7Sopenharmony_ci	inline bool						isPageResident		(size_t pageNdx) const { return m_isPageResident[pageNdx];			}
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_ci	void							makePageResident	(size_t pageNdx);
120e5c31af7Sopenharmony_ci
121e5c31af7Sopenharmony_ci	de::UniquePtr<tcu::Resource>	m_resource;
122e5c31af7Sopenharmony_ci
123e5c31af7Sopenharmony_ci	std::vector<Element>			m_elements;
124e5c31af7Sopenharmony_ci	std::vector<bool>				m_isPageResident;
125e5c31af7Sopenharmony_ci};
126e5c31af7Sopenharmony_ci
127e5c31af7Sopenharmony_citemplate<typename Element>
128e5c31af7Sopenharmony_ciLazyResource<Element>::LazyResource (de::MovePtr<tcu::Resource> resource)
129e5c31af7Sopenharmony_ci	: m_resource(resource)
130e5c31af7Sopenharmony_ci{
131e5c31af7Sopenharmony_ci	const size_t	resSize		= m_resource->getSize();
132e5c31af7Sopenharmony_ci	const size_t	numElements	= resSize/sizeof(Element);
133e5c31af7Sopenharmony_ci	const size_t	numPages	= (numElements >> ELEMENTS_PER_PAGE_LOG2) + ((numElements & ((1u<<ELEMENTS_PER_PAGE_LOG2)-1u)) == 0 ? 0 : 1);
134e5c31af7Sopenharmony_ci
135e5c31af7Sopenharmony_ci	TCU_CHECK_INTERNAL(numElements*sizeof(Element) == resSize);
136e5c31af7Sopenharmony_ci
137e5c31af7Sopenharmony_ci	m_elements.resize(numElements);
138e5c31af7Sopenharmony_ci	m_isPageResident.resize(numPages, false);
139e5c31af7Sopenharmony_ci}
140e5c31af7Sopenharmony_ci
141e5c31af7Sopenharmony_citemplate<typename Element>
142e5c31af7Sopenharmony_ciconst Element& LazyResource<Element>::operator[] (size_t ndx)
143e5c31af7Sopenharmony_ci{
144e5c31af7Sopenharmony_ci	const size_t pageNdx = getPageForElement(ndx);
145e5c31af7Sopenharmony_ci
146e5c31af7Sopenharmony_ci	if (ndx >= m_elements.size())
147e5c31af7Sopenharmony_ci		throw std::out_of_range("");
148e5c31af7Sopenharmony_ci
149e5c31af7Sopenharmony_ci	if (!isPageResident(pageNdx))
150e5c31af7Sopenharmony_ci		makePageResident(pageNdx);
151e5c31af7Sopenharmony_ci
152e5c31af7Sopenharmony_ci	return m_elements[ndx];
153e5c31af7Sopenharmony_ci}
154e5c31af7Sopenharmony_ci
155e5c31af7Sopenharmony_citemplate<typename Element>
156e5c31af7Sopenharmony_civoid LazyResource<Element>::makePageResident (size_t pageNdx)
157e5c31af7Sopenharmony_ci{
158e5c31af7Sopenharmony_ci	const size_t	pageSize		= (size_t)(1<<ELEMENTS_PER_PAGE_LOG2)*sizeof(Element);
159e5c31af7Sopenharmony_ci	const size_t	pageOffset		= pageNdx*pageSize;
160e5c31af7Sopenharmony_ci	const size_t	numBytesToRead	= de::min(m_elements.size()*sizeof(Element) - pageOffset, pageSize);
161e5c31af7Sopenharmony_ci
162e5c31af7Sopenharmony_ci	DE_ASSERT(!isPageResident(pageNdx));
163e5c31af7Sopenharmony_ci
164e5c31af7Sopenharmony_ci	if ((size_t)m_resource->getPosition() != pageOffset)
165e5c31af7Sopenharmony_ci		m_resource->setPosition((int)pageOffset);
166e5c31af7Sopenharmony_ci
167e5c31af7Sopenharmony_ci	m_resource->read((deUint8*)&m_elements[pageNdx << ELEMENTS_PER_PAGE_LOG2], (int)numBytesToRead);
168e5c31af7Sopenharmony_ci	m_isPageResident[pageNdx] = true;
169e5c31af7Sopenharmony_ci}
170e5c31af7Sopenharmony_ci
171e5c31af7Sopenharmony_citypedef LazyResource<BinaryIndexNode> BinaryIndexAccess;
172e5c31af7Sopenharmony_ci
173e5c31af7Sopenharmony_ciclass BinaryRegistryReader
174e5c31af7Sopenharmony_ci{
175e5c31af7Sopenharmony_cipublic:
176e5c31af7Sopenharmony_ci							BinaryRegistryReader	(const tcu::Archive& archive, const std::string& srcPath);
177e5c31af7Sopenharmony_ci							~BinaryRegistryReader	(void);
178e5c31af7Sopenharmony_ci
179e5c31af7Sopenharmony_ci	ProgramBinary*			loadProgram				(const ProgramIdentifier& id) const;
180e5c31af7Sopenharmony_ci
181e5c31af7Sopenharmony_ciprivate:
182e5c31af7Sopenharmony_ci	typedef de::MovePtr<BinaryIndexAccess> BinaryIndexPtr;
183e5c31af7Sopenharmony_ci
184e5c31af7Sopenharmony_ci	const tcu::Archive&		m_archive;
185e5c31af7Sopenharmony_ci	const std::string		m_srcPath;
186e5c31af7Sopenharmony_ci
187e5c31af7Sopenharmony_ci	mutable BinaryIndexPtr	m_binaryIndex;
188e5c31af7Sopenharmony_ci};
189e5c31af7Sopenharmony_ci
190e5c31af7Sopenharmony_cistruct ProgramIdentifierIndex
191e5c31af7Sopenharmony_ci{
192e5c31af7Sopenharmony_ci	ProgramIdentifier	id;
193e5c31af7Sopenharmony_ci	deUint32			index;
194e5c31af7Sopenharmony_ci
195e5c31af7Sopenharmony_ci	ProgramIdentifierIndex (const ProgramIdentifier&	id_,
196e5c31af7Sopenharmony_ci							deUint32					index_)
197e5c31af7Sopenharmony_ci		: id	(id_)
198e5c31af7Sopenharmony_ci		, index	(index_)
199e5c31af7Sopenharmony_ci	{}
200e5c31af7Sopenharmony_ci};
201e5c31af7Sopenharmony_ci
202e5c31af7Sopenharmony_ciDE_DECLARE_POOL_HASH(BinaryIndexHashImpl, const ProgramBinary*, deUint32);
203e5c31af7Sopenharmony_ci
204e5c31af7Sopenharmony_ciclass BinaryIndexHash
205e5c31af7Sopenharmony_ci{
206e5c31af7Sopenharmony_cipublic:
207e5c31af7Sopenharmony_ci								BinaryIndexHash		(void);
208e5c31af7Sopenharmony_ci								~BinaryIndexHash	(void);
209e5c31af7Sopenharmony_ci
210e5c31af7Sopenharmony_ci	deUint32*					find				(const ProgramBinary* binary) const;
211e5c31af7Sopenharmony_ci	void						insert				(const ProgramBinary* binary, deUint32 index);
212e5c31af7Sopenharmony_ci
213e5c31af7Sopenharmony_ciprivate:
214e5c31af7Sopenharmony_ci								BinaryIndexHash		(const BinaryIndexHash&);
215e5c31af7Sopenharmony_ci	BinaryIndexHash&			operator=			(const BinaryIndexHash&);
216e5c31af7Sopenharmony_ci
217e5c31af7Sopenharmony_ci	de::MemPool					m_memPool;
218e5c31af7Sopenharmony_ci	BinaryIndexHashImpl* const	m_hash;
219e5c31af7Sopenharmony_ci};
220e5c31af7Sopenharmony_ci
221e5c31af7Sopenharmony_ciclass BinaryRegistryWriter
222e5c31af7Sopenharmony_ci{
223e5c31af7Sopenharmony_cipublic:
224e5c31af7Sopenharmony_ci						BinaryRegistryWriter	(const std::string& dstPath);
225e5c31af7Sopenharmony_ci						~BinaryRegistryWriter	(void);
226e5c31af7Sopenharmony_ci
227e5c31af7Sopenharmony_ci	void				addProgram				(const ProgramIdentifier& id, const ProgramBinary& binary);
228e5c31af7Sopenharmony_ci	void				write					(void) const;
229e5c31af7Sopenharmony_ci
230e5c31af7Sopenharmony_ciprivate:
231e5c31af7Sopenharmony_ci	void				initFromPath			(const std::string& srcPath);
232e5c31af7Sopenharmony_ci	void				writeToPath				(const std::string& dstPath) const;
233e5c31af7Sopenharmony_ci
234e5c31af7Sopenharmony_ci	deUint32*			findBinary				(const ProgramBinary& binary) const;
235e5c31af7Sopenharmony_ci	deUint32			getNextSlot				(void) const;
236e5c31af7Sopenharmony_ci	void				addBinary				(deUint32 index, const ProgramBinary& binary);
237e5c31af7Sopenharmony_ci
238e5c31af7Sopenharmony_ci	struct BinarySlot
239e5c31af7Sopenharmony_ci	{
240e5c31af7Sopenharmony_ci		ProgramBinary*	binary;
241e5c31af7Sopenharmony_ci		size_t			referenceCount;
242e5c31af7Sopenharmony_ci
243e5c31af7Sopenharmony_ci		BinarySlot (ProgramBinary* binary_, size_t referenceCount_)
244e5c31af7Sopenharmony_ci			: binary		(binary_)
245e5c31af7Sopenharmony_ci			, referenceCount(referenceCount_)
246e5c31af7Sopenharmony_ci		{}
247e5c31af7Sopenharmony_ci
248e5c31af7Sopenharmony_ci		BinarySlot (void)
249e5c31af7Sopenharmony_ci			: binary		(DE_NULL)
250e5c31af7Sopenharmony_ci			, referenceCount(0)
251e5c31af7Sopenharmony_ci		{}
252e5c31af7Sopenharmony_ci	};
253e5c31af7Sopenharmony_ci
254e5c31af7Sopenharmony_ci	typedef std::vector<BinarySlot>				BinaryVector;
255e5c31af7Sopenharmony_ci	typedef std::vector<ProgramIdentifierIndex>	ProgIdIndexVector;
256e5c31af7Sopenharmony_ci
257e5c31af7Sopenharmony_ci	const std::string&	m_dstPath;
258e5c31af7Sopenharmony_ci
259e5c31af7Sopenharmony_ci	ProgIdIndexVector	m_binaryIndices;		//!< ProgramIdentifier -> slot in m_binaries
260e5c31af7Sopenharmony_ci	BinaryIndexHash		m_binaryHash;			//!< ProgramBinary -> slot in m_binaries
261e5c31af7Sopenharmony_ci	BinaryVector		m_binaries;
262e5c31af7Sopenharmony_ci};
263e5c31af7Sopenharmony_ci
264e5c31af7Sopenharmony_ci} // BinaryRegistryDetail
265e5c31af7Sopenharmony_ci
266e5c31af7Sopenharmony_ciusing BinaryRegistryDetail::BinaryRegistryReader;
267e5c31af7Sopenharmony_ciusing BinaryRegistryDetail::BinaryRegistryWriter;
268e5c31af7Sopenharmony_ciusing BinaryRegistryDetail::ProgramIdentifier;
269e5c31af7Sopenharmony_ciusing BinaryRegistryDetail::ProgramNotFoundException;
270e5c31af7Sopenharmony_ci
271e5c31af7Sopenharmony_ci} // vk
272e5c31af7Sopenharmony_ci
273e5c31af7Sopenharmony_ci#endif // _VKBINARYREGISTRY_HPP
274