Edit

kc3-lang/angle/src/libANGLE/MemoryProgramCache.cpp

Branch :

  • Show log

    Commit

  • Author : Geoff Lang
    Date : 2019-02-14 12:53:04
    Hash : e332e621
    Message : D3D: Asynchronously load program binaries. Unpack as much of the binary steam as possible before passing the final loading of the shader programs off to a worker thread. Reporting as many possible link errors before becoming asynchronous means that linking should only fail due to unexpected system issues at that point. This also allows other backends to asynchronously load program binaries. BUG=angleproject:2857 Change-Id: I587917a3e54522114dabd41d1b14fc491c8fd18a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1473451 Commit-Queue: Jamie Madill <jmadill@google.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>

  • src/libANGLE/MemoryProgramCache.cpp
  • //
    // Copyright 2017 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // MemoryProgramCache: Stores compiled and linked programs in memory so they don't
    //   always have to be re-compiled. Can be used in conjunction with the platform
    //   layer to warm up the cache from disk.
    
    #include "libANGLE/MemoryProgramCache.h"
    
    #include <GLSLANG/ShaderVars.h>
    #include <anglebase/sha1.h>
    
    #include "common/utilities.h"
    #include "common/version.h"
    #include "libANGLE/BinaryStream.h"
    #include "libANGLE/Context.h"
    #include "libANGLE/Uniform.h"
    #include "libANGLE/histogram_macros.h"
    #include "libANGLE/renderer/ProgramImpl.h"
    #include "platform/Platform.h"
    
    namespace gl
    {
    
    namespace
    {
    constexpr unsigned int kWarningLimit = 3;
    
    class HashStream final : angle::NonCopyable
    {
      public:
        std::string str() { return mStringStream.str(); }
    
        template <typename T>
        HashStream &operator<<(T value)
        {
            mStringStream << value << kSeparator;
            return *this;
        }
    
      private:
        static constexpr char kSeparator = ':';
        std::ostringstream mStringStream;
    };
    
    HashStream &operator<<(HashStream &stream, const Shader *shader)
    {
        if (shader)
        {
            stream << shader->getSourceString().c_str() << shader->getSourceString().length()
                   << shader->getCompilerResourcesString().c_str();
        }
        return stream;
    }
    
    HashStream &operator<<(HashStream &stream, const ProgramBindings &bindings)
    {
        for (const auto &binding : bindings)
        {
            stream << binding.first << binding.second;
        }
        return stream;
    }
    
    HashStream &operator<<(HashStream &stream, const std::vector<std::string> &strings)
    {
        for (const auto &str : strings)
        {
            stream << str;
        }
        return stream;
    }
    
    HashStream &operator<<(HashStream &stream, const std::vector<gl::VariableLocation> &locations)
    {
        for (const auto &loc : locations)
        {
            stream << loc.index << loc.arrayIndex << loc.ignored;
        }
        return stream;
    }
    
    }  // anonymous namespace
    
    MemoryProgramCache::MemoryProgramCache(egl::BlobCache &blobCache)
        : mBlobCache(blobCache), mIssuedWarnings(0)
    {}
    
    MemoryProgramCache::~MemoryProgramCache() {}
    
    void MemoryProgramCache::ComputeHash(const Context *context,
                                         const Program *program,
                                         egl::BlobCache::Key *hashOut)
    {
        // Compute the program hash. Start with the shader hashes and resource strings.
        HashStream hashStream;
        for (ShaderType shaderType : AllShaderTypes())
        {
            hashStream << program->getAttachedShader(shaderType);
        }
    
        // Add some ANGLE metadata and Context properties, such as version and back-end.
        hashStream << ANGLE_COMMIT_HASH << context->getClientMajorVersion()
                   << context->getClientMinorVersion() << context->getString(GL_RENDERER);
    
        // Hash pre-link program properties.
        hashStream << program->getAttributeBindings() << program->getUniformLocationBindings()
                   << program->getFragmentInputBindings()
                   << program->getState().getTransformFeedbackVaryingNames()
                   << program->getState().getTransformFeedbackBufferMode()
                   << program->getState().getOutputLocations()
                   << program->getState().getSecondaryOutputLocations();
    
        // Call the secure SHA hashing function.
        const std::string &programKey = hashStream.str();
        angle::base::SHA1HashBytes(reinterpret_cast<const unsigned char *>(programKey.c_str()),
                                   programKey.length(), hashOut->data());
    }
    
    angle::Result MemoryProgramCache::getProgram(const Context *context,
                                                 Program *program,
                                                 egl::BlobCache::Key *hashOut)
    {
        // If caching is effectively disabled, don't bother calculating the hash.
        if (!mBlobCache.isCachingEnabled())
        {
            return angle::Result::Incomplete;
        }
    
        ComputeHash(context, program, hashOut);
        egl::BlobCache::Value binaryProgram;
        if (get(context, *hashOut, &binaryProgram))
        {
            angle::Result result = program->loadBinary(context, GL_PROGRAM_BINARY_ANGLE,
                                                       binaryProgram.data(), binaryProgram.size());
            ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess",
                                    result == angle::Result::Continue);
            ANGLE_TRY(result);
    
            if (result == angle::Result::Continue)
                return angle::Result::Continue;
    
            // Cache load failed, evict.
            if (mIssuedWarnings++ < kWarningLimit)
            {
                WARN() << "Failed to load binary from cache.";
    
                if (mIssuedWarnings == kWarningLimit)
                {
                    WARN() << "Reaching warning limit for cache load failures, silencing "
                              "subsequent warnings.";
                }
            }
            remove(*hashOut);
        }
        return angle::Result::Incomplete;
    }
    
    bool MemoryProgramCache::get(const Context *context,
                                 const egl::BlobCache::Key &programHash,
                                 egl::BlobCache::Value *programOut)
    {
        return mBlobCache.get(context->getScratchBuffer(), programHash, programOut);
    }
    
    bool MemoryProgramCache::getAt(size_t index,
                                   const egl::BlobCache::Key **hashOut,
                                   egl::BlobCache::Value *programOut)
    {
        return mBlobCache.getAt(index, hashOut, programOut);
    }
    
    void MemoryProgramCache::remove(const egl::BlobCache::Key &programHash)
    {
        mBlobCache.remove(programHash);
    }
    
    void MemoryProgramCache::putProgram(const egl::BlobCache::Key &programHash,
                                        const Context *context,
                                        const Program *program)
    {
        // If caching is effectively disabled, don't bother serializing the program.
        if (!mBlobCache.isCachingEnabled())
        {
            return;
        }
    
        angle::MemoryBuffer serializedProgram;
        program->serialize(context, &serializedProgram);
    
        ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramBinarySizeBytes",
                               static_cast<int>(serializedProgram.size()));
    
        // TODO(syoussefi): to be removed.  Compatibility for Chrome until it supports
        // EGL_ANDROID_blob_cache. http://anglebug.com/2516
        auto *platform = ANGLEPlatformCurrent();
        platform->cacheProgram(platform, programHash, serializedProgram.size(),
                               serializedProgram.data());
    
        mBlobCache.put(programHash, std::move(serializedProgram));
    }
    
    void MemoryProgramCache::updateProgram(const Context *context, const Program *program)
    {
        egl::BlobCache::Key programHash;
        ComputeHash(context, program, &programHash);
        putProgram(programHash, context, program);
    }
    
    void MemoryProgramCache::putBinary(const egl::BlobCache::Key &programHash,
                                       const uint8_t *binary,
                                       size_t length)
    {
        // Copy the binary.
        angle::MemoryBuffer newEntry;
        newEntry.resize(length);
        memcpy(newEntry.data(), binary, length);
    
        // Store the binary.
        mBlobCache.populate(programHash, std::move(newEntry));
    }
    
    void MemoryProgramCache::clear()
    {
        mBlobCache.clear();
        mIssuedWarnings = 0;
    }
    
    void MemoryProgramCache::resize(size_t maxCacheSizeBytes)
    {
        mBlobCache.resize(maxCacheSizeBytes);
    }
    
    size_t MemoryProgramCache::entryCount() const
    {
        return mBlobCache.entryCount();
    }
    
    size_t MemoryProgramCache::trim(size_t limit)
    {
        return mBlobCache.trim(limit);
    }
    
    size_t MemoryProgramCache::size() const
    {
        return mBlobCache.size();
    }
    
    size_t MemoryProgramCache::maxSize() const
    {
        return mBlobCache.maxSize();
    }
    
    }  // namespace gl