tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MemoryProgramCache.cpp (9078B)


      1 //
      2 // Copyright 2017 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 // MemoryProgramCache: Stores compiled and linked programs in memory so they don't
      7 //   always have to be re-compiled. Can be used in conjunction with the platform
      8 //   layer to warm up the cache from disk.
      9 
     10 // Include zlib first, otherwise FAR gets defined elsewhere.
     11 #define USE_SYSTEM_ZLIB
     12 #include "compression_utils_portable.h"
     13 
     14 #include "libANGLE/MemoryProgramCache.h"
     15 
     16 #include <GLSLANG/ShaderVars.h>
     17 #include <anglebase/sha1.h>
     18 
     19 #include "common/angle_version_info.h"
     20 #include "common/utilities.h"
     21 #include "libANGLE/BinaryStream.h"
     22 #include "libANGLE/Context.h"
     23 #include "libANGLE/Debug.h"
     24 #include "libANGLE/Uniform.h"
     25 #include "libANGLE/capture/FrameCapture.h"
     26 #include "libANGLE/histogram_macros.h"
     27 #include "libANGLE/renderer/ProgramImpl.h"
     28 #include "platform/PlatformMethods.h"
     29 
     30 namespace gl
     31 {
     32 
     33 namespace
     34 {
     35 class HashStream final : angle::NonCopyable
     36 {
     37  public:
     38    std::string str() { return mStringStream.str(); }
     39 
     40    template <typename T>
     41    HashStream &operator<<(T value)
     42    {
     43        mStringStream << value << kSeparator;
     44        return *this;
     45    }
     46 
     47  private:
     48    static constexpr char kSeparator = ':';
     49    std::ostringstream mStringStream;
     50 };
     51 
     52 HashStream &operator<<(HashStream &stream, Shader *shader)
     53 {
     54    if (shader)
     55    {
     56        stream << shader->getSourceString().c_str() << shader->getSourceString().length()
     57               << shader->getCompilerResourcesString().c_str();
     58    }
     59    return stream;
     60 }
     61 
     62 HashStream &operator<<(HashStream &stream, const ProgramBindings &bindings)
     63 {
     64    for (const auto &binding : bindings.getStableIterationMap())
     65    {
     66        stream << binding.first << binding.second;
     67    }
     68    return stream;
     69 }
     70 
     71 HashStream &operator<<(HashStream &stream, const ProgramAliasedBindings &bindings)
     72 {
     73    for (const auto &binding : bindings.getStableIterationMap())
     74    {
     75        stream << binding.first << binding.second.location;
     76    }
     77    return stream;
     78 }
     79 
     80 HashStream &operator<<(HashStream &stream, const std::vector<std::string> &strings)
     81 {
     82    for (const auto &str : strings)
     83    {
     84        stream << str;
     85    }
     86    return stream;
     87 }
     88 
     89 HashStream &operator<<(HashStream &stream, const std::vector<gl::VariableLocation> &locations)
     90 {
     91    for (const auto &loc : locations)
     92    {
     93        stream << loc.index << loc.arrayIndex << loc.ignored;
     94    }
     95    return stream;
     96 }
     97 
     98 }  // anonymous namespace
     99 
    100 MemoryProgramCache::MemoryProgramCache(egl::BlobCache &blobCache) : mBlobCache(blobCache) {}
    101 
    102 MemoryProgramCache::~MemoryProgramCache() {}
    103 
    104 void MemoryProgramCache::ComputeHash(const Context *context,
    105                                     const Program *program,
    106                                     egl::BlobCache::Key *hashOut)
    107 {
    108    // Compute the program hash. Start with the shader hashes and resource strings.
    109    HashStream hashStream;
    110    for (ShaderType shaderType : AllShaderTypes())
    111    {
    112        hashStream << program->getAttachedShader(shaderType);
    113    }
    114 
    115    // Add some ANGLE metadata and Context properties, such as version and back-end.
    116    hashStream << angle::GetANGLECommitHash() << context->getClientMajorVersion()
    117               << context->getClientMinorVersion() << context->getString(GL_RENDERER);
    118 
    119    // Hash pre-link program properties.
    120    hashStream << program->getAttributeBindings() << program->getUniformLocationBindings()
    121               << program->getFragmentOutputLocations() << program->getFragmentOutputIndexes()
    122               << program->getState().getTransformFeedbackVaryingNames()
    123               << program->getState().getTransformFeedbackBufferMode()
    124               << program->getState().getOutputLocations()
    125               << program->getState().getSecondaryOutputLocations();
    126 
    127    // Include the status of FrameCapture, which adds source strings to the binary
    128    hashStream << context->getShareGroup()->getFrameCaptureShared()->enabled();
    129 
    130    // Call the secure SHA hashing function.
    131    const std::string &programKey = hashStream.str();
    132    angle::base::SHA1HashBytes(reinterpret_cast<const unsigned char *>(programKey.c_str()),
    133                               programKey.length(), hashOut->data());
    134 }
    135 
    136 angle::Result MemoryProgramCache::getProgram(const Context *context,
    137                                             Program *program,
    138                                             egl::BlobCache::Key *hashOut)
    139 {
    140    // If caching is effectively disabled, don't bother calculating the hash.
    141    if (!mBlobCache.isCachingEnabled())
    142    {
    143        return angle::Result::Incomplete;
    144    }
    145 
    146    ComputeHash(context, program, hashOut);
    147 
    148    angle::MemoryBuffer uncompressedData;
    149    switch (mBlobCache.getAndDecompress(context->getScratchBuffer(), *hashOut, &uncompressedData))
    150    {
    151        case egl::BlobCache::GetAndDecompressResult::NotFound:
    152            return angle::Result::Incomplete;
    153 
    154        case egl::BlobCache::GetAndDecompressResult::DecompressFailure:
    155            ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
    156                               "Error decompressing program binary data fetched from cache.");
    157            return angle::Result::Incomplete;
    158 
    159        case egl::BlobCache::GetAndDecompressResult::GetSuccess:
    160            angle::Result result =
    161                program->loadBinary(context, GL_PROGRAM_BINARY_ANGLE, uncompressedData.data(),
    162                                    static_cast<int>(uncompressedData.size()));
    163            ANGLE_TRY(result);
    164 
    165            if (result == angle::Result::Continue)
    166                return angle::Result::Continue;
    167 
    168            // Cache load failed, evict
    169            ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
    170                               "Failed to load program binary from cache.");
    171            remove(*hashOut);
    172 
    173            return angle::Result::Incomplete;
    174    }
    175 
    176    UNREACHABLE();
    177    return angle::Result::Incomplete;
    178 }
    179 
    180 bool MemoryProgramCache::getAt(size_t index,
    181                               const egl::BlobCache::Key **hashOut,
    182                               egl::BlobCache::Value *programOut)
    183 {
    184    return mBlobCache.getAt(index, hashOut, programOut);
    185 }
    186 
    187 void MemoryProgramCache::remove(const egl::BlobCache::Key &programHash)
    188 {
    189    mBlobCache.remove(programHash);
    190 }
    191 
    192 angle::Result MemoryProgramCache::putProgram(const egl::BlobCache::Key &programHash,
    193                                             const Context *context,
    194                                             const Program *program)
    195 {
    196    // If caching is effectively disabled, don't bother serializing the program.
    197    if (!mBlobCache.isCachingEnabled())
    198    {
    199        return angle::Result::Incomplete;
    200    }
    201 
    202    angle::MemoryBuffer serializedProgram;
    203    ANGLE_TRY(program->serialize(context, &serializedProgram));
    204 
    205    angle::MemoryBuffer compressedData;
    206    if (!egl::CompressBlobCacheData(serializedProgram.size(), serializedProgram.data(),
    207                                    &compressedData))
    208    {
    209        ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
    210                           "Error compressing binary data.");
    211        return angle::Result::Incomplete;
    212    }
    213 
    214    {
    215        std::scoped_lock<std::mutex> lock(mBlobCache.getMutex());
    216        // TODO: http://anglebug.com/7568
    217        // This was a workaround for Chrome until it added support for EGL_ANDROID_blob_cache,
    218        // tracked by http://anglebug.com/2516. This issue has since been closed, but removing this
    219        // still causes a test failure.
    220        auto *platform = ANGLEPlatformCurrent();
    221        platform->cacheProgram(platform, programHash, compressedData.size(), compressedData.data());
    222    }
    223 
    224    mBlobCache.put(programHash, std::move(compressedData));
    225    return angle::Result::Continue;
    226 }
    227 
    228 angle::Result MemoryProgramCache::updateProgram(const Context *context, const Program *program)
    229 {
    230    egl::BlobCache::Key programHash;
    231    ComputeHash(context, program, &programHash);
    232    return putProgram(programHash, context, program);
    233 }
    234 
    235 bool MemoryProgramCache::putBinary(const egl::BlobCache::Key &programHash,
    236                                   const uint8_t *binary,
    237                                   size_t length)
    238 {
    239    // Copy the binary.
    240    angle::MemoryBuffer newEntry;
    241    if (!newEntry.resize(length))
    242    {
    243        return false;
    244    }
    245    memcpy(newEntry.data(), binary, length);
    246 
    247    // Store the binary.
    248    mBlobCache.populate(programHash, std::move(newEntry));
    249 
    250    return true;
    251 }
    252 
    253 void MemoryProgramCache::clear()
    254 {
    255    mBlobCache.clear();
    256 }
    257 
    258 void MemoryProgramCache::resize(size_t maxCacheSizeBytes)
    259 {
    260    mBlobCache.resize(maxCacheSizeBytes);
    261 }
    262 
    263 size_t MemoryProgramCache::entryCount() const
    264 {
    265    return mBlobCache.entryCount();
    266 }
    267 
    268 size_t MemoryProgramCache::trim(size_t limit)
    269 {
    270    return mBlobCache.trim(limit);
    271 }
    272 
    273 size_t MemoryProgramCache::size() const
    274 {
    275    return mBlobCache.size();
    276 }
    277 
    278 size_t MemoryProgramCache::maxSize() const
    279 {
    280    return mBlobCache.maxSize();
    281 }
    282 
    283 }  // namespace gl