| #ifndef _VKBINARYREGISTRY_HPP |
| #define _VKBINARYREGISTRY_HPP |
| /*------------------------------------------------------------------------- |
| * Vulkan CTS Framework |
| * -------------------- |
| * |
| * Copyright (c) 2015 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Program binary registry. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vkDefs.hpp" |
| #include "vkPrograms.hpp" |
| #include "tcuResource.hpp" |
| #include "deMemPool.hpp" |
| #include "dePoolHash.h" |
| #include "deUniquePtr.hpp" |
| |
| #include <map> |
| #include <vector> |
| #include <stdexcept> |
| |
| namespace vk |
| { |
| namespace BinaryRegistryDetail |
| { |
| |
| struct ProgramIdentifier |
| { |
| std::string testCasePath; |
| std::string programName; |
| |
| ProgramIdentifier(const std::string &testCasePath_, const std::string &programName_) |
| : testCasePath(testCasePath_) |
| , programName(programName_) |
| { |
| } |
| }; |
| |
| inline bool operator<(const ProgramIdentifier &a, const ProgramIdentifier &b) |
| { |
| return (a.testCasePath < b.testCasePath) || ((a.testCasePath == b.testCasePath) && (a.programName < b.programName)); |
| } |
| |
| class ProgramNotFoundException : public tcu::ResourceError |
| { |
| public: |
| ProgramNotFoundException(const ProgramIdentifier &id, const std::string &reason) |
| : tcu::ResourceError("Program " + id.testCasePath + " / '" + id.programName + "' not found: " + reason) |
| { |
| } |
| }; |
| |
| // Program Binary Index |
| // -------------------- |
| // |
| // When SPIR-V binaries are stored on disk, duplicate binaries are eliminated |
| // to save a significant amount of space. Many tests use identical binaries and |
| // just storing each compiled binary without de-duplication would be incredibly |
| // wasteful. |
| // |
| // To locate binary that corresponds given ProgramIdentifier, a program binary |
| // index is needed. Since that index is accessed every time a test requests shader |
| // binary, it must be fast to load (to reduce statup cost), and fast to access. |
| // |
| // Simple trie is used to store binary indices. It is laid out as an array of |
| // BinaryIndexNodes. Nodes store 4-byte pieces (words) of search string, rather |
| // than just a single character. This gives more regular memory layout in exchange |
| // of a little wasted storage. |
| // |
| // Search strings are created by splitting original string into 4-byte words and |
| // appending one or more terminating 0 bytes. |
| // |
| // For each node where word doesn't have trailing 0 bytes (not terminated), the |
| // index points into a offset of its child list. Children for each node are stored |
| // consecutively, and the list is terminated by child with word = 0. |
| // |
| // If word contains one or more trailing 0 bytes, index denotes the binary index |
| // instead of index of the child list. |
| |
| struct BinaryIndexNode |
| { |
| uint32_t word; //!< 4 bytes of search string. |
| uint32_t index; //!< Binary index if word ends with 0 bytes, or index of first child node otherwise. |
| }; |
| |
| template <typename Element> |
| class LazyResource |
| { |
| public: |
| LazyResource(de::MovePtr<tcu::Resource> resource); |
| |
| const Element &operator[](size_t ndx); |
| size_t size(void) const |
| { |
| return m_elements.size(); |
| } |
| |
| private: |
| enum |
| { |
| ELEMENTS_PER_PAGE_LOG2 = 10 |
| }; |
| |
| inline size_t getPageForElement(size_t elemNdx) const |
| { |
| return elemNdx >> ELEMENTS_PER_PAGE_LOG2; |
| } |
| inline bool isPageResident(size_t pageNdx) const |
| { |
| return m_isPageResident[pageNdx]; |
| } |
| |
| void makePageResident(size_t pageNdx); |
| |
| de::UniquePtr<tcu::Resource> m_resource; |
| |
| std::vector<Element> m_elements; |
| std::vector<bool> m_isPageResident; |
| }; |
| |
| template <typename Element> |
| LazyResource<Element>::LazyResource(de::MovePtr<tcu::Resource> resource) : m_resource(resource) |
| { |
| const size_t resSize = m_resource->getSize(); |
| const size_t numElements = resSize / sizeof(Element); |
| const size_t numPages = |
| (numElements >> ELEMENTS_PER_PAGE_LOG2) + ((numElements & ((1u << ELEMENTS_PER_PAGE_LOG2) - 1u)) == 0 ? 0 : 1); |
| |
| TCU_CHECK_INTERNAL(numElements * sizeof(Element) == resSize); |
| |
| m_elements.resize(numElements); |
| m_isPageResident.resize(numPages, false); |
| } |
| |
| template <typename Element> |
| const Element &LazyResource<Element>::operator[](size_t ndx) |
| { |
| const size_t pageNdx = getPageForElement(ndx); |
| |
| if (ndx >= m_elements.size()) |
| throw std::out_of_range(""); |
| |
| if (!isPageResident(pageNdx)) |
| makePageResident(pageNdx); |
| |
| return m_elements[ndx]; |
| } |
| |
| template <typename Element> |
| void LazyResource<Element>::makePageResident(size_t pageNdx) |
| { |
| const size_t pageSize = (size_t)(1 << ELEMENTS_PER_PAGE_LOG2) * sizeof(Element); |
| const size_t pageOffset = pageNdx * pageSize; |
| const size_t numBytesToRead = de::min(m_elements.size() * sizeof(Element) - pageOffset, pageSize); |
| |
| DE_ASSERT(!isPageResident(pageNdx)); |
| |
| if ((size_t)m_resource->getPosition() != pageOffset) |
| m_resource->setPosition((int)pageOffset); |
| |
| m_resource->read((uint8_t *)&m_elements[pageNdx << ELEMENTS_PER_PAGE_LOG2], (int)numBytesToRead); |
| m_isPageResident[pageNdx] = true; |
| } |
| |
| typedef LazyResource<BinaryIndexNode> BinaryIndexAccess; |
| |
| class BinaryRegistryReader |
| { |
| public: |
| BinaryRegistryReader(const tcu::Archive &archive, const std::string &srcPath); |
| ~BinaryRegistryReader(void); |
| |
| ProgramBinary *loadProgram(const ProgramIdentifier &id) const; |
| |
| private: |
| typedef de::MovePtr<BinaryIndexAccess> BinaryIndexPtr; |
| |
| const tcu::Archive &m_archive; |
| const std::string m_srcPath; |
| |
| mutable BinaryIndexPtr m_binaryIndex; |
| }; |
| |
| struct ProgramIdentifierIndex |
| { |
| ProgramIdentifier id; |
| uint32_t index; |
| |
| ProgramIdentifierIndex(const ProgramIdentifier &id_, uint32_t index_) : id(id_), index(index_) |
| { |
| } |
| }; |
| |
| DE_DECLARE_POOL_HASH(BinaryIndexHashImpl, const ProgramBinary *, uint32_t); |
| |
| class BinaryIndexHash |
| { |
| public: |
| BinaryIndexHash(void); |
| ~BinaryIndexHash(void); |
| |
| uint32_t *find(const ProgramBinary *binary) const; |
| void insert(const ProgramBinary *binary, uint32_t index); |
| |
| private: |
| BinaryIndexHash(const BinaryIndexHash &); |
| BinaryIndexHash &operator=(const BinaryIndexHash &); |
| |
| de::MemPool m_memPool; |
| BinaryIndexHashImpl *const m_hash; |
| }; |
| |
| class BinaryRegistryWriter |
| { |
| public: |
| BinaryRegistryWriter(const std::string &dstPath); |
| ~BinaryRegistryWriter(void); |
| |
| void addProgram(const ProgramIdentifier &id, const ProgramBinary &binary); |
| void write(void) const; |
| |
| private: |
| void initFromPath(const std::string &srcPath); |
| void writeToPath(const std::string &dstPath) const; |
| |
| uint32_t *findBinary(const ProgramBinary &binary) const; |
| uint32_t getNextSlot(void) const; |
| void addBinary(uint32_t index, const ProgramBinary &binary); |
| |
| struct BinarySlot |
| { |
| ProgramBinary *binary; |
| size_t referenceCount; |
| |
| BinarySlot(ProgramBinary *binary_, size_t referenceCount_) : binary(binary_), referenceCount(referenceCount_) |
| { |
| } |
| |
| BinarySlot(void) : binary(DE_NULL), referenceCount(0) |
| { |
| } |
| }; |
| |
| typedef std::vector<BinarySlot> BinaryVector; |
| typedef std::vector<ProgramIdentifierIndex> ProgIdIndexVector; |
| |
| const std::string &m_dstPath; |
| |
| ProgIdIndexVector m_binaryIndices; //!< ProgramIdentifier -> slot in m_binaries |
| BinaryIndexHash m_binaryHash; //!< ProgramBinary -> slot in m_binaries |
| BinaryVector m_binaries; |
| }; |
| |
| } // namespace BinaryRegistryDetail |
| |
| using BinaryRegistryDetail::BinaryRegistryReader; |
| using BinaryRegistryDetail::BinaryRegistryWriter; |
| using BinaryRegistryDetail::ProgramIdentifier; |
| using BinaryRegistryDetail::ProgramNotFoundException; |
| |
| } // namespace vk |
| |
| #endif // _VKBINARYREGISTRY_HPP |